{ "name": "toolbar", "type": "registry:component", "dependencies": [ "lucide-react", "motion" ], "files": [ { "type": "registry:component", "content": "\"use client\";\n\n/**\n * @author: @dorianbaffier\n * @description: Toolbar\n * @version: 1.0.0\n * @date: 2025-06-26\n * @license: MIT\n * @website: https://kokonutui.com\n * @github: https://github.com/kokonut-labs/kokonutui\n */\n\nimport {\n Bell,\n CircleUserRound,\n Edit2,\n FileDown,\n Frame,\n Layers,\n Lock,\n type LucideIcon,\n MousePointer2,\n Move,\n Palette,\n Shapes,\n Share2,\n SlidersHorizontal,\n} from \"lucide-react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\ninterface ToolbarItem {\n id: string;\n title: string;\n icon: LucideIcon;\n type?: never;\n}\n\ninterface ToolbarProps {\n items?: ToolbarItem[];\n defaultSelected?: string;\n className?: string;\n activeColor?: string;\n onSelect?: (itemId: string) => void;\n}\n\nconst DEFAULT_TOOLBAR_ITEMS: ToolbarItem[] = [\n { id: \"select\", title: \"Select\", icon: MousePointer2 },\n { id: \"move\", title: \"Move\", icon: Move },\n { id: \"shapes\", title: \"Shapes\", icon: Shapes },\n { id: \"layers\", title: \"Layers\", icon: Layers },\n { id: \"frame\", title: \"Frame\", icon: Frame },\n { id: \"properties\", title: \"Properties\", icon: SlidersHorizontal },\n { id: \"export\", title: \"Export\", icon: FileDown },\n { id: \"share\", title: \"Share\", icon: Share2 },\n { id: \"notifications\", title: \"Notifications\", icon: Bell },\n { id: \"profile\", title: \"Profile\", icon: CircleUserRound },\n { id: \"appearance\", title: \"Appearance\", icon: Palette },\n];\n\nconst buttonVariants = {\n initial: {\n gap: 0,\n paddingLeft: \".5rem\",\n paddingRight: \".5rem\",\n },\n animate: (isSelected: boolean) => ({\n gap: isSelected ? \".5rem\" : 0,\n paddingLeft: isSelected ? \"1rem\" : \".5rem\",\n paddingRight: isSelected ? \"1rem\" : \".5rem\",\n }),\n};\n\nconst spanVariants = {\n initial: { width: 0, opacity: 0 },\n animate: { width: \"auto\", opacity: 1 },\n exit: { width: 0, opacity: 0 },\n};\n\nconst notificationVariants = {\n initial: { opacity: 0, y: 10 },\n animate: { opacity: 1, y: -10 },\n exit: { opacity: 0, y: -20 },\n};\n\nconst lineVariants = {\n initial: { scaleX: 0, x: \"-50%\" },\n animate: {\n scaleX: 1,\n x: \"0%\",\n transition: { duration: 0.2, ease: \"easeOut\" },\n },\n exit: {\n scaleX: 0,\n x: \"50%\",\n transition: { duration: 0.2, ease: \"easeIn\" },\n },\n};\n\nconst transition = { type: \"spring\", bounce: 0, duration: 0.4 };\n\nexport function Toolbar({\n items = DEFAULT_TOOLBAR_ITEMS,\n defaultSelected = \"select\",\n className,\n activeColor = \"text-primary\",\n onSelect,\n}: ToolbarProps) {\n const [selected, setSelected] = React.useState(\n defaultSelected\n );\n const [isToggled, setIsToggled] = React.useState(false);\n const [activeNotification, setActiveNotification] = React.useState<\n string | null\n >(null);\n const outsideClickRef = React.useRef(null);\n\n const handleItemClick = (itemId: string) => {\n setSelected(selected === itemId ? null : itemId);\n onSelect?.(itemId);\n setActiveNotification(itemId);\n setTimeout(() => setActiveNotification(null), 1500);\n };\n\n return (\n
\n \n \n {activeNotification && (\n \n
\n {items.find((item) => item.id === activeNotification)?.title}{\" \"}\n clicked!\n
\n \n \n )}\n
\n\n
\n {items.map((item) => (\n handleItemClick(item.id)}\n transition={transition as any}\n variants={buttonVariants as any}\n >\n \n \n {selected === item.id && (\n \n {item.title}\n \n )}\n \n \n ))}\n\n setIsToggled(!isToggled)}\n whileHover={{ scale: 1.02 }}\n whileTap={{ scale: 0.98 }}\n >\n {isToggled ? (\n \n ) : (\n \n )}\n \n {isToggled ? \"On\" : \"Off\"}\n \n \n
\n
\n \n );\n}\n\nexport default Toolbar;\n", "path": "/components/kokonutui/toolbar.tsx", "target": "components/kokonutui/toolbar.tsx" } ] }