{
  "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<string | null>(\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    <div className=\"space-y-2\">\n      <div\n        className={cn(\n          \"relative flex items-center gap-3 p-2\",\n          \"bg-background\",\n          \"rounded-xl border\",\n          \"transition-all duration-200\",\n          className\n        )}\n        ref={outsideClickRef}\n      >\n        <AnimatePresence>\n          {activeNotification && (\n            <motion.div\n              animate=\"animate\"\n              className=\"absolute -top-8 left-1/2 z-50 -translate-x-1/2 transform\"\n              exit=\"exit\"\n              initial=\"initial\"\n              transition={{ duration: 0.3 }}\n              variants={notificationVariants as any}\n            >\n              <div className=\"rounded-full bg-primary px-3 py-1 text-primary-foreground text-xs\">\n                {items.find((item) => item.id === activeNotification)?.title}{\" \"}\n                clicked!\n              </div>\n              <motion.div\n                animate=\"animate\"\n                className=\"absolute -bottom-1 left-1/2 h-[2px] w-full origin-left bg-primary\"\n                exit=\"exit\"\n                initial=\"initial\"\n                variants={lineVariants as any}\n              />\n            </motion.div>\n          )}\n        </AnimatePresence>\n\n        <div className=\"flex items-center gap-2\">\n          {items.map((item) => (\n            <motion.button\n              animate=\"animate\"\n              className={cn(\n                \"relative flex items-center rounded-none px-3 py-2\",\n                \"font-medium text-sm transition-colors duration-300\",\n                selected === item.id\n                  ? \"rounded-lg bg-[#1F9CFE] text-white\"\n                  : \"text-muted-foreground hover:bg-muted hover:text-foreground\"\n              )}\n              custom={selected === item.id}\n              initial={false}\n              key={item.id}\n              onClick={() => handleItemClick(item.id)}\n              transition={transition as any}\n              variants={buttonVariants as any}\n            >\n              <item.icon\n                className={cn(selected === item.id && \"text-white\")}\n                size={16}\n              />\n              <AnimatePresence initial={false}>\n                {selected === item.id && (\n                  <motion.span\n                    animate=\"animate\"\n                    className=\"overflow-hidden\"\n                    exit=\"exit\"\n                    initial=\"initial\"\n                    transition={transition as any}\n                    variants={spanVariants as any}\n                  >\n                    {item.title}\n                  </motion.span>\n                )}\n              </AnimatePresence>\n            </motion.button>\n          ))}\n\n          <motion.button\n            className={cn(\n              \"flex items-center gap-2 px-4 py-2\",\n              \"rounded-xl border shadow-sm transition-all duration-200\",\n              \"hover:shadow-md active:border-primary/50\",\n              isToggled\n                ? [\n                    \"bg-[#1F9CFE] text-white\",\n                    \"border-[#1F9CFE]/30\",\n                    \"hover:bg-[#1F9CFE]/90\",\n                    \"hover:border-[#1F9CFE]/40\",\n                  ]\n                : [\n                    \"bg-background text-muted-foreground\",\n                    \"border-border/30\",\n                    \"hover:bg-muted\",\n                    \"hover:text-foreground\",\n                    \"hover:border-border/40\",\n                  ]\n            )}\n            onClick={() => setIsToggled(!isToggled)}\n            whileHover={{ scale: 1.02 }}\n            whileTap={{ scale: 0.98 }}\n          >\n            {isToggled ? (\n              <Edit2 className=\"h-3.5 w-3.5\" />\n            ) : (\n              <Lock className=\"h-3.5 w-3.5\" />\n            )}\n            <span className=\"font-medium text-sm\">\n              {isToggled ? \"On\" : \"Off\"}\n            </span>\n          </motion.button>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default Toolbar;\n",
      "path": "/components/kokonutui/toolbar.tsx",
      "target": "components/kokonutui/toolbar.tsx"
    }
  ]
}