{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "menubar-styled",
  "title": "Menubar essentials",
  "description": "Styled menubar: the essentials set. 5 decorative menubar variations (BarMenubar, PillMenubar, GlassMenubar, MinimalMenubar, IconMenubar) on the ai2 token system, powered by framer-motion, reduced-motion aware and sized sm to xl. Part of the free styled layer.",
  "dependencies": [
    "motion@^12.42.2",
    "lucide-react@^1.23.0"
  ],
  "registryDependencies": [
    "@ai2/tokens"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/menubar-styled.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { FileText, Pencil, Eye } from \"lucide-react\"\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Menubar family: 5 decorative, SELF-SUFFICIENT menubars. NO radix or portal.\n   A horizontal bar of triggers (like File/Edit/View) + a dropdown absolutely\n   positioned BELOW the trigger when clicked. Classic menubar behavior: while one\n   menu is open, hovering a sibling trigger switches to that menu. Only one menu is\n   open at a time (the open index is held in state). It closes on an outside click,\n   on Escape or on an item selection. The open dropdown uses AnimatePresence;\n   instant under reduced-motion. Color comes ONLY from tokens, via alpha\n   color-mix. */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\ntype MenuItem = { label: React.ReactNode; onSelect?: () => void }\ntype Menu = { label: React.ReactNode; items: MenuItem[] }\n\ninterface MenubarProps {\n  className?: string\n  size?: StyledSize\n  menus?: Menu[]\n}\n\nconst defaultMenus: Menu[] = [\n  {\n    label: \"File\",\n    items: [\n      { label: \"New File\" },\n      { label: \"Open...\" },\n      { label: \"Save\" },\n      { label: \"Save As...\" },\n    ],\n  },\n  {\n    label: \"Edit\",\n    items: [\n      { label: \"Undo\" },\n      { label: \"Redo\" },\n      { label: \"Cut\" },\n      { label: \"Copy\" },\n      { label: \"Paste\" },\n    ],\n  },\n  {\n    label: \"View\",\n    items: [\n      { label: \"Zoom In\" },\n      { label: \"Zoom Out\" },\n      { label: \"Full Screen\" },\n    ],\n  },\n]\n\nconst defaultIcons = [FileText, Pencil, Eye]\n\nconst barSize: Record<StyledSize, string> = {\n  sm: \"h-8 gap-0.5 px-1 text-xs\",\n  md: \"h-9 gap-1 px-1 text-sm\",\n  lg: \"h-10 gap-1 px-1.5 text-sm\",\n  xl: \"h-11 gap-1.5 px-2 text-base\",\n}\n\nconst triggerSize: Record<StyledSize, string> = {\n  sm: \"h-6 px-2\",\n  md: \"h-7 px-2.5\",\n  lg: \"h-8 px-3\",\n  xl: \"h-9 px-3.5\",\n}\n\nconst dropdownSize: Record<StyledSize, string> = {\n  sm: \"min-w-40 text-xs\",\n  md: \"min-w-44 text-sm\",\n  lg: \"min-w-48 text-sm\",\n  xl: \"min-w-52 text-base\",\n}\n\nconst itemSize: Record<StyledSize, string> = {\n  sm: \"px-2 py-1.5\",\n  md: \"px-2.5 py-1.5\",\n  lg: \"px-3 py-2\",\n  xl: \"px-3.5 py-2\",\n}\n\nconst softHover =\n  \"hover:bg-[color-mix(in_oklab,var(--color-foreground)_6%,transparent)]\"\n\nconst itemBase =\n  \"flex w-full cursor-default select-none items-center gap-2 rounded-md text-left text-popover-foreground outline-none transition-colors focus-visible:ring-[3px] focus-visible:ring-ring/50 [&_svg]:size-4 [&_svg]:shrink-0 [&_i]:text-base [&_i]:leading-none\"\n\n/* The shared menubar core. triggerClass(active) and dropdownClass decide the look;\n   when showIcons is true a token icon is placed before every top-level trigger. */\nfunction MenubarCore({\n  props,\n  barClassName,\n  triggerClassName,\n  dropdownClassName,\n  showIcons = false,\n}: {\n  props: MenubarProps\n  barClassName?: string\n  triggerClassName?: (active: boolean) => string\n  dropdownClassName?: string\n  showIcons?: boolean\n}) {\n  const { className, size = \"md\", menus = defaultMenus } = props\n  const reduce = useReducedMotion()\n  const [openIndex, setOpenIndex] = React.useState<number | null>(null)\n  const rootRef = React.useRef<HTMLDivElement>(null)\n\n  React.useEffect(() => {\n    if (openIndex === null) return\n    const onKey = (e: KeyboardEvent) => {\n      if (e.key === \"Escape\") setOpenIndex(null)\n    }\n    const onPointer = (e: PointerEvent) => {\n      const node = rootRef.current\n      if (node && e.target instanceof Node && !node.contains(e.target)) {\n        setOpenIndex(null)\n      }\n    }\n    window.addEventListener(\"keydown\", onKey)\n    window.addEventListener(\"pointerdown\", onPointer)\n    return () => {\n      window.removeEventListener(\"keydown\", onKey)\n      window.removeEventListener(\"pointerdown\", onPointer)\n    }\n  }, [openIndex])\n\n  const enter = reduce\n    ? { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 } }\n    : {\n        initial: { opacity: 0, scale: 0.97, y: -4 },\n        animate: { opacity: 1, scale: 1, y: 0 },\n        exit: { opacity: 0, scale: 0.97, y: -4 },\n      }\n\n  return (\n    <div\n      ref={rootRef}\n      data-slot=\"styled-menubar\"\n      role=\"menubar\"\n      className={cn(\n        \"inline-flex items-center\",\n        barSize[size],\n        barClassName,\n        className\n      )}\n    >\n      {menus.map((menu, i) => {\n        const active = openIndex === i\n        const Icon = showIcons ? defaultIcons[i % defaultIcons.length] : null\n        return (\n          <div key={i} className=\"relative\">\n            <button\n              type=\"button\"\n              role=\"menuitem\"\n              aria-haspopup=\"menu\"\n              aria-expanded={active}\n              onClick={() => setOpenIndex(active ? null : i)}\n              onPointerEnter={() => {\n                if (openIndex !== null) setOpenIndex(i)\n              }}\n              className={cn(\n                \"inline-flex select-none items-center gap-1.5 whitespace-nowrap rounded-md font-medium outline-none transition-colors focus-visible:ring-[3px] focus-visible:ring-ring/50 [&_svg]:size-4 [&_svg]:shrink-0 [&_i]:text-base [&_i]:leading-none\",\n                triggerSize[size],\n                triggerClassName?.(active) ??\n                  (active\n                    ? \"bg-accent text-accent-foreground\"\n                    : cn(\"text-foreground\", softHover))\n              )}\n            >\n              {Icon ? <Icon aria-hidden /> : null}\n              {menu.label}\n            </button>\n\n            <AnimatePresence>\n              {active ? (\n                <motion.div\n                  role=\"menu\"\n                  className={cn(\n                    \"absolute left-0 top-full z-50 mt-1.5 origin-top rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-lg outline-none\",\n                    dropdownSize[size],\n                    dropdownClassName\n                  )}\n                  initial={enter.initial}\n                  animate={enter.animate}\n                  exit={enter.exit}\n                  transition={\n                    reduce\n                      ? { duration: 0.12 }\n                      : { type: \"spring\", stiffness: 360, damping: 26 }\n                  }\n                >\n                  {menu.items.map((item, j) => (\n                    <button\n                      key={j}\n                      type=\"button\"\n                      role=\"menuitem\"\n                      onClick={() => {\n                        item.onSelect?.()\n                        setOpenIndex(null)\n                      }}\n                      className={cn(itemBase, itemSize[size], softHover)}\n                    >\n                      {item.label}\n                    </button>\n                  ))}\n                </motion.div>\n              ) : null}\n            </AnimatePresence>\n          </div>\n        )\n      })}\n    </div>\n  )\n}\n\n/* Bar: klasik uygulama menubar, kenarlikli cubuk. */\nexport function BarMenubar({ className, size = \"md\", menus }: MenubarProps) {\n  return (\n    <MenubarCore\n      props={{ className, size, menus }}\n      barClassName=\"rounded-lg border border-border bg-card shadow-xs\"\n    />\n  )\n}\n\n/* Pill: aktif menu triggeri token pill highlight alir. */\nexport function PillMenubar({ className, size = \"md\", menus }: MenubarProps) {\n  return (\n    <MenubarCore\n      props={{ className, size, menus }}\n      barClassName=\"rounded-full border border-border bg-card\"\n      triggerClassName={(active) =>\n        active\n          ? \"rounded-full bg-primary text-primary-foreground shadow-sm\"\n          : cn(\n              \"rounded-full text-muted-foreground\",\n              \"hover:bg-[color-mix(in_oklab,var(--color-foreground)_6%,transparent)] hover:text-foreground\"\n            )\n      }\n      dropdownClassName=\"rounded-xl\"\n    />\n  )\n}\n\n/* Glass: buzlu cam cubuk + dropdown. */\nexport function GlassMenubar({ className, size = \"md\", menus }: MenubarProps) {\n  return (\n    <MenubarCore\n      props={{ className, size, menus }}\n      barClassName=\"rounded-xl border border-border bg-[color-mix(in_oklab,var(--color-card)_70%,transparent)] shadow-[inset_0_1px_0_color-mix(in_oklab,var(--color-foreground)_12%,transparent)] supports-[backdrop-filter]:bg-[color-mix(in_oklab,var(--color-card)_50%,transparent)] supports-[backdrop-filter]:backdrop-blur-xl\"\n      dropdownClassName=\"border-border bg-[color-mix(in_oklab,var(--color-popover)_75%,transparent)] shadow-[inset_0_1px_0_color-mix(in_oklab,var(--color-foreground)_12%,transparent)] supports-[backdrop-filter]:bg-[color-mix(in_oklab,var(--color-popover)_55%,transparent)] supports-[backdrop-filter]:backdrop-blur-xl\"\n    />\n  )\n}\n\n/* Minimal: borderless, text-only triggers; a line under the active one. */\nexport function MinimalMenubar({ className, size = \"md\", menus }: MenubarProps) {\n  return (\n    <MenubarCore\n      props={{ className, size, menus }}\n      barClassName=\"bg-transparent\"\n      triggerClassName={(active) =>\n        cn(\n          \"rounded-none border-b-2 transition-colors\",\n          active\n            ? \"border-primary text-foreground\"\n            : cn(\n                \"border-transparent text-muted-foreground\",\n                \"hover:border-[color-mix(in_oklab,var(--color-foreground)_20%,transparent)] hover:text-foreground\"\n              )\n        )\n      }\n    />\n  )\n}\n\n/* Icon: a token icon before every top-level trigger. */\nexport function IconMenubar({ className, size = \"md\", menus }: MenubarProps) {\n  return (\n    <MenubarCore\n      props={{ className, size, menus }}\n      barClassName=\"rounded-lg border border-border bg-card shadow-xs\"\n      showIcons\n    />\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/menubar-styled.tsx"
    }
  ],
  "categories": [
    "styled",
    "menubar"
  ],
  "type": "registry:component"
}