{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "menubar",
  "title": "Menubar",
  "description": "shadcn/ui(new-york-v4) menubar의 유니버설(웹+네이티브 한 벌 소스) 포팅. 포팅 판단(원본 대비 차이·이유): context(useDropdownMenuContext) 의존이라 단독 재사용이 불가능하다. 대신",
  "dependencies": [
    "@unikit-bridge/ui"
  ],
  "registryDependencies": [
    "dropdown-menu",
    "utils",
    "animations"
  ],
  "files": [
    {
      "path": "registry/ui/menubar.tsx",
      "content": "// Menubar — shadcn/ui（new-york-v4） menubar.tsx 유니버설 포팅 （사이클 40, T-1e）.\n// 원본: shadcn-ref/ui/menubar.tsx — radix Menubar 엔진 제거.\n//\n// 포팅 판단（원본 대비 차이이유）:\n// - 재구성 방식（독립 구현 vs 조합）: dropdown-menu의 하위 컴포넌트는 전부 내부\n//   context（useDropdownMenuContext） 의존이라 단독 재사용이 불가능하다. 대신\n//   MenubarMenu가 DropdownMenu를 루트로 소비하면 Trigger/Content/Item/Checkbox/\n//   Radio/Separator/Label/Sub 계열이 전부 그대로 동작한다 — 파일 수정 없이\n//   전량 조합（소비）으로 간다. 원본 export 16종은 그대로 유지된다.\n// - \"한 번에 하나의 메뉴만 열림\"（radix menubar 루트 계약）은 Menubar 루트가\n//   value（열린 메뉴 식별자）를 조율해 제공한다 — MenubarMenu가 DropdownMenu를\n//   제어 모드（open/onOpenChange）로 렌더하고 다른 메뉴가 열리면 자동으로 닫는다.\n//   원본 Root의 value/onValueChange 계약（활성 메뉴 제어）도 이 값으로 유지되고,\n//   MenubarMenu에 value를 명시하면 사용처가 이 식별자로 제어할 수 있다.\n// - 미지원（radix 대비 근사）: 열린 상태에서 인접 트리거 hover 전환（브리지에\n//   onHoverIn 계약 부재 — dropdown SubTrigger와 동일 판단, 눌림 전환만）,\n//   화살표키 트리거 순회타입어헤드, 등장/퇴장 애니메이션origin 변형,\n//   alignOffset=-4（AnchoredOverlay 계약 밖 — Content에서 미수용으로 제거）.\n//   ESC바깥 눌림 닫기포커스 이동은 소비하는 dropdown 계열이 제공한다.\n// - MenubarTrigger: 원본 토큰（focus/open 하이라이트 bg-accent·text-accent-foreground\n//   ·font-medium）을 조건부 클래스로 전개해 dropdown 트리거에 얹는다. 문자열/숫자\n//   children은 자체 Text로 감싸 조건부 전경을 직접 준다 — 요소 자식은 그대로 전달돼\n//   dropdown 트리거의 wrapTextChildren이 통과시킨다（select 트리거 위임 패턴）.\n//   배경 하이라이트는 web:focus-visible·web:hover·active·isOpen 조건부 근사\n//   （UniKit UI 관행 — 네이티브 hover 부재）, 라벨 전경은 web:hover·active·isOpen로만\n//   근사한다. 라벨의 focus-visible 전환은 Pressable 포커스 계약 부재로 미구현 —\n//   한계·로드맵（input-group과 동일 계열, 사이클 72 G3 F-1）.\n// - MenubarContent: 원본 기본값（align startsideOffset 8） 유지, min-w-［12rem］\n//   → min-w-48（표준 계단 근사）. CheckboxItem rounded-xs→dropdown rounded-sm\n//   근사 등 사소한 토큰 차이는 승계（동일 역할시각 차이 미미）.\n// - MenubarPortal은 API 호환 투명 래퍼 — 포털은 AnchoredOverlay 골격이 대체.\n// - 아이콘: CheckIcon·ChevronRightIcon은 브리지 SVG 아이콘, CircleIcon은 점 View —\n//   소비하는 dropdown-menu가 브리지 SVG 아이콘 관행으로 처리한다.\n// - 접근성: 루트 role=\"menubar\"（브리지 BridgeRole 카탈로그에 있음 — RN은 이\n//   role을 무시하고 웹 스크린리더만 이득, bridge/types.ts 문서화 방침）.\n//   트리거 aria-expandedaria-controls콘텐츠 role=\"menu\"항목 menuitem\n//   aria-checked는 dropdown 소비로 자동 제공된다.\nimport {\n  Children,\n  createContext,\n  forwardRef,\n  useCallback,\n  useContext,\n  useId,\n  useMemo,\n  useRef,\n  useState,\n  type ReactNode,\n} from \"react\";\nimport {\n  Text,\n  View,\n  type BridgePressableRef,\n  type BridgeTextRef,\n  type BridgeViewRef,\n  type PressableProps,\n  type ViewProps,\n} from \"@unikit-bridge/ui/primitives\";\n\nimport {\n  DropdownMenu,\n  DropdownMenuCheckboxItem,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuRadioGroup,\n  DropdownMenuRadioItem,\n  DropdownMenuSeparator,\n  DropdownMenuShortcut,\n  DropdownMenuSub,\n  DropdownMenuSubContent,\n  DropdownMenuSubTrigger,\n  DropdownMenuTrigger,\n  type DropdownMenuCheckboxItemProps,\n  type DropdownMenuContentProps,\n  type DropdownMenuGroupProps,\n  type DropdownMenuItemProps,\n  type DropdownMenuLabelProps,\n  type DropdownMenuRadioGroupProps,\n  type DropdownMenuRadioItemProps,\n  type DropdownMenuSeparatorProps,\n  type DropdownMenuShortcutProps,\n  type DropdownMenuSubContentProps,\n  type DropdownMenuSubProps,\n  type DropdownMenuSubTriggerProps,\n} from \"./dropdown-menu\";\nimport { cn } from \"@/lib/utils\";\n\n// ---------------------------------------------------------------------------\n// 상태 context — 루트（단일 열림 조율）메뉴（자기 열림）\n// ---------------------------------------------------------------------------\n\ntype MenubarContextValue = {\n  /** 열려 있는 메뉴 value — null이면 전부 닫힘 */\n  value: string | null;\n  setValue: (value: string | null) => void;\n};\n\nconst MenubarContext = createContext<MenubarContextValue | null>(null);\n\nfunction useMenubarContext(component: string): MenubarContextValue {\n  const ctx = useContext(MenubarContext);\n  if (!ctx) {\n    throw new Error(`<${component}>는 <Menubar> 안에서 사용해야 합니다.`);\n  }\n  return ctx;\n}\n\n/** 메뉴 단위 열림 — MenubarTrigger가 하이라이트 조건으로 소비 */\nconst MenubarMenuContext = createContext<{ isOpen: boolean }>({\n  isOpen: false,\n});\n\n// ---------------------------------------------------------------------------\n// 루트메뉴\n// ---------------------------------------------------------------------------\n\nexport type MenubarProps = ViewProps & {\n  /** 열린 메뉴 value（제어） — MenubarMenu의 value와 대응 */\n  value?: string | null;\n  defaultValue?: string | null;\n  onValueChange?: (value: string | null) => void;\n};\n\nconst Menubar = forwardRef<BridgeViewRef, MenubarProps>(\n  (\n    { value, defaultValue = null, onValueChange, className, children, ...props },\n    ref,\n  ) => {\n    // 비제어 상태 — 제어（value 지정）면 무시된다.\n    const [internalValue, setInternalValue] = useState(defaultValue);\n    const current = value !== undefined ? value : internalValue;\n    const stateRef = useRef({ value, current, onValueChange });\n    stateRef.current = { value, current, onValueChange };\n    const setValue = useCallback((next: string | null) => {\n      const state = stateRef.current;\n      if (state.value === undefined) setInternalValue(next);\n      if (next !== state.current) state.onValueChange?.(next);\n    }, []);\n    const contextValue = useMemo<MenubarContextValue>(\n      () => ({ value: current, setValue }),\n      [current, setValue],\n    );\n    return (\n      <MenubarContext.Provider value={contextValue}>\n        <View\n          ref={ref}\n          accessibilityRole=\"menubar\"\n          className={cn(\n            \"h-9 flex-row items-center gap-1 rounded-md border border-border bg-background p-1\",\n            className,\n          )}\n          {...props}\n        >\n          {children}\n        </View>\n      </MenubarContext.Provider>\n    );\n  },\n);\nMenubar.displayName = \"Menubar\";\n\nexport type MenubarMenuProps = {\n  /** 메뉴 식별자 — Menubar 루트 value 제어와 연결（미지정 시 자동 생성） */\n  value?: string;\n  children?: ReactNode;\n};\n\nfunction MenubarMenu({ value, children }: MenubarMenuProps) {\n  const menubar = useMenubarContext(\"MenubarMenu\");\n  const fallbackId = useId();\n  const menuValue = value ?? fallbackId;\n  const isOpen = menubar.value === menuValue;\n  const menuContextValue = useMemo(() => ({ isOpen }), [isOpen]);\n  const handleOpenChange = useCallback(\n    (open: boolean) => menubar.setValue(open ? menuValue : null),\n    [menubar, menuValue],\n  );\n  return (\n    <MenubarMenuContext.Provider value={menuContextValue}>\n      {/* 제어 모드 조합 — 다른 메뉴가 열리면 이 값이 바뀌어 자동으로 닫힌다 */}\n      <DropdownMenu open={isOpen} onOpenChange={handleOpenChange}>\n        {children}\n      </DropdownMenu>\n    </MenubarMenuContext.Provider>\n  );\n}\n\n/** API 호환용 투명 래퍼 — 포털은 AnchoredOverlay가 대체（forceMountcontainer 미지원） */\nexport type MenubarPortalProps = { children?: ReactNode };\n\nfunction MenubarPortal({ children }: MenubarPortalProps) {\n  return <>{children}</>;\n}\n\n// ---------------------------------------------------------------------------\n// 트리거콘텐츠\n// ---------------------------------------------------------------------------\n\nexport type MenubarTriggerProps = PressableProps;\n\nconst MenubarTrigger = forwardRef<BridgePressableRef, MenubarTriggerProps>(\n  ({ className, children, ...props }, ref) => {\n    const menu = useContext(MenubarMenuContext);\n    return (\n      <DropdownMenuTrigger\n        ref={ref}\n        className={cn(\n          \"items-center rounded-sm px-2 py-1 active:bg-accent web:hover:bg-accent web:focus-visible:bg-accent\",\n          // 원본 data-［state=open］:bg-accent → 조건부 클래스\n          menu.isOpen && \"bg-accent\",\n          className,\n        )}\n        {...props}\n      >\n        {/* 문자열/숫자 children은 자체 Text로 감싸 조건부 전경·원본 font-medium을\n            준다 — 요소 자식은 그대로 전달돼 dropdown 트리거의 wrapTextChildren이\n            통과시킨다（select 트리거 위임 패턴）. */}\n        {Children.map(children, (child) =>\n          typeof child === \"string\" || typeof child === \"number\" ? (\n            <Text\n              className={cn(\n                \"font-sans text-sm font-medium text-foreground active:text-accent-foreground web:hover:text-accent-foreground\",\n                // 원본 data-［state=open］:text-accent-foreground → 조건부 클래스\n                menu.isOpen && \"text-accent-foreground\",\n              )}\n            >\n              {child}\n            </Text>\n          ) : (\n            child\n          ),\n        )}\n      </DropdownMenuTrigger>\n    );\n  },\n);\nMenubarTrigger.displayName = \"MenubarTrigger\";\n\nexport type MenubarContentProps = DropdownMenuContentProps;\n\nconst MenubarContent = forwardRef<BridgeViewRef, MenubarContentProps>(\n  ({ className, side = \"bottom\", align = \"start\", sideOffset = 8, ...props }, ref) => (\n    // 원본 기본값 sideOffset 8（alignOffset -4는 미지원 — 머리 주석 참조）\n    <DropdownMenuContent\n      ref={ref}\n      side={side}\n      align={align}\n      sideOffset={sideOffset}\n      className={cn(\"min-w-48\", className)}\n      {...props}\n    />\n  ),\n);\nMenubarContent.displayName = \"MenubarContent\";\n\nexport type MenubarGroupProps = DropdownMenuGroupProps;\n\nconst MenubarGroup = forwardRef<BridgeViewRef, MenubarGroupProps>(\n  (props, ref) => <DropdownMenuGroup ref={ref} {...props} />,\n);\nMenubarGroup.displayName = \"MenubarGroup\";\n\nexport type MenubarItemProps = DropdownMenuItemProps;\n\nconst MenubarItem = forwardRef<BridgePressableRef, MenubarItemProps>(\n  (props, ref) => <DropdownMenuItem ref={ref} {...props} />,\n);\nMenubarItem.displayName = \"MenubarItem\";\n\n// ---------------------------------------------------------------------------\n// 체크라디오기타 항목\n// ---------------------------------------------------------------------------\n\nexport type MenubarCheckboxItemProps = DropdownMenuCheckboxItemProps;\n\nconst MenubarCheckboxItem = forwardRef<\n  BridgePressableRef,\n  MenubarCheckboxItemProps\n>((props, ref) => <DropdownMenuCheckboxItem ref={ref} {...props} />);\nMenubarCheckboxItem.displayName = \"MenubarCheckboxItem\";\n\nexport type MenubarRadioGroupProps = DropdownMenuRadioGroupProps;\n\nconst MenubarRadioGroup = forwardRef<BridgeViewRef, MenubarRadioGroupProps>(\n  (props, ref) => <DropdownMenuRadioGroup ref={ref} {...props} />,\n);\nMenubarRadioGroup.displayName = \"MenubarRadioGroup\";\n\nexport type MenubarRadioItemProps = DropdownMenuRadioItemProps;\n\nconst MenubarRadioItem = forwardRef<BridgePressableRef, MenubarRadioItemProps>(\n  (props, ref) => <DropdownMenuRadioItem ref={ref} {...props} />,\n);\nMenubarRadioItem.displayName = \"MenubarRadioItem\";\n\nexport type MenubarLabelProps = DropdownMenuLabelProps;\n\nconst MenubarLabel = forwardRef<BridgeViewRef, MenubarLabelProps>(\n  (props, ref) => (\n    // dropdown Label과 동일 계약（inset） — 조합으로 승계\n    <DropdownMenuLabel ref={ref} {...props} />\n  ),\n);\nMenubarLabel.displayName = \"MenubarLabel\";\n\nexport type MenubarSeparatorProps = DropdownMenuSeparatorProps;\n\nconst MenubarSeparator = forwardRef<BridgeViewRef, MenubarSeparatorProps>(\n  (props, ref) => <DropdownMenuSeparator ref={ref} {...props} />,\n);\nMenubarSeparator.displayName = \"MenubarSeparator\";\n\nexport type MenubarShortcutProps = DropdownMenuShortcutProps;\n\nconst MenubarShortcut = forwardRef<BridgeTextRef, MenubarShortcutProps>(\n  (props, ref) => <DropdownMenuShortcut ref={ref} {...props} />,\n);\nMenubarShortcut.displayName = \"MenubarShortcut\";\n\n// ---------------------------------------------------------------------------\n// 서브메뉴\n// ---------------------------------------------------------------------------\n\nexport type MenubarSubProps = DropdownMenuSubProps;\n\nfunction MenubarSub(props: MenubarSubProps) {\n  return <DropdownMenuSub {...props} />;\n}\n\nexport type MenubarSubTriggerProps = DropdownMenuSubTriggerProps;\n\nconst MenubarSubTrigger = forwardRef<\n  BridgePressableRef,\n  MenubarSubTriggerProps\n>((props, ref) => <DropdownMenuSubTrigger ref={ref} {...props} />);\nMenubarSubTrigger.displayName = \"MenubarSubTrigger\";\n\nexport type MenubarSubContentProps = DropdownMenuSubContentProps;\n\nconst MenubarSubContent = forwardRef<BridgeViewRef, MenubarSubContentProps>(\n  (props, ref) => <DropdownMenuSubContent ref={ref} {...props} />,\n);\nMenubarSubContent.displayName = \"MenubarSubContent\";\n\nexport {\n  Menubar,\n  MenubarPortal,\n  MenubarMenu,\n  MenubarTrigger,\n  MenubarContent,\n  MenubarGroup,\n  MenubarSeparator,\n  MenubarLabel,\n  MenubarItem,\n  MenubarShortcut,\n  MenubarCheckboxItem,\n  MenubarRadioGroup,\n  MenubarRadioItem,\n  MenubarSub,\n  MenubarSubTrigger,\n  MenubarSubContent,\n};\n",
      "type": "registry:ui",
      "target": "components/ui/menubar.tsx"
    }
  ],
  "type": "registry:ui"
}
