@evinvest/uikit 0.26.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +142 -8
  2. package/dist/components/account-menu.js +70 -0
  3. package/dist/components/account-menu.js.map +1 -0
  4. package/dist/components/alert-dialog.js +4 -3
  5. package/dist/components/alert-dialog.js.map +1 -1
  6. package/dist/components/app-shell.js +11 -0
  7. package/dist/components/app-shell.js.map +1 -1
  8. package/dist/components/command.js +129 -20
  9. package/dist/components/command.js.map +1 -1
  10. package/dist/components/context-menu.js +8 -8
  11. package/dist/components/context-menu.js.map +1 -1
  12. package/dist/components/dialog.js +4 -3
  13. package/dist/components/dialog.js.map +1 -1
  14. package/dist/components/drawer.js +9 -5
  15. package/dist/components/drawer.js.map +1 -1
  16. package/dist/components/dropdown-menu.js +13 -10
  17. package/dist/components/dropdown-menu.js.map +1 -1
  18. package/dist/components/info-tip.js +2 -2
  19. package/dist/components/info-tip.js.map +1 -1
  20. package/dist/components/menubar.js +18 -5
  21. package/dist/components/menubar.js.map +1 -1
  22. package/dist/components/navigation-menu.js +2 -2
  23. package/dist/components/navigation-menu.js.map +1 -1
  24. package/dist/components/popover.js +2 -2
  25. package/dist/components/popover.js.map +1 -1
  26. package/dist/components/select.js +2 -2
  27. package/dist/components/select.js.map +1 -1
  28. package/dist/components/sheet.js +4 -3
  29. package/dist/components/sheet.js.map +1 -1
  30. package/dist/components/sonner.js +1 -0
  31. package/dist/components/sonner.js.map +1 -1
  32. package/dist/components/table.js +24 -7
  33. package/dist/components/table.js.map +1 -1
  34. package/dist/components/toggle-group.js +1 -1
  35. package/dist/components/toggle-group.js.map +1 -1
  36. package/dist/components/top-bar.js +21 -0
  37. package/dist/components/top-bar.js.map +1 -0
  38. package/dist/generated/context-menu.js +1 -1
  39. package/dist/generated/context-menu.js.map +1 -1
  40. package/dist/generated/dropdown-menu.js +1 -1
  41. package/dist/generated/dropdown-menu.js.map +1 -1
  42. package/dist/generated/menubar.js +1 -1
  43. package/dist/generated/menubar.js.map +1 -1
  44. package/dist/generated/table.js +20 -3
  45. package/dist/generated/table.js.map +1 -1
  46. package/dist/generated/toggle.js +2 -2
  47. package/dist/generated/toggle.js.map +1 -1
  48. package/dist/index.d.ts +168 -22
  49. package/dist/index.js +5 -2
  50. package/dist/primitives/dismissable-layer.js +80 -15
  51. package/dist/primitives/dismissable-layer.js.map +1 -1
  52. package/dist/primitives/use-roving-focus.js +13 -7
  53. package/dist/primitives/use-roving-focus.js.map +1 -1
  54. package/package.json +1 -1
  55. package/styles/ev.css +4 -2
  56. package/styles/theme.css +7 -0
  57. package/styles/tokens.css +15 -3
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/drawer.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useControllableState } from \"../primitives/use-controllable-state\";\nimport { useFocusScope } from \"../primitives/focus-scope\";\nimport { mergeRefs } from \"../primitives/merge-refs\";\nimport { Portal } from \"../primitives/portal\";\nimport { Slot } from \"../primitives/slot\";\nimport {\n DRAWER_BODY,\n DRAWER_CONTENT_BASE,\n DRAWER_DESCRIPTION,\n DRAWER_FOOTER,\n DRAWER_HANDLE,\n DRAWER_HEADER,\n DRAWER_OVERLAY,\n DRAWER_TITLE,\n drawerDirectionClasses,\n type DrawerDirection,\n} from \"../generated/drawer\";\n\nexport type { DrawerDirection };\n\n// Drag-to-dismiss tuning (pointer physics, TS-only — Rust stays render-only).\n// Values from Vaul: a release past 25% of the panel's size along the drag\n// axis, or a flick faster than 0.4px/ms, closes; anything short snaps back.\n// Drags are refused for the first 500ms after opening so the enter finishes.\nconst CLOSE_THRESHOLD = 0.25;\nconst VELOCITY_THRESHOLD = 0.4;\nconst DRAG_AFTER_OPEN_MS = 500;\n// The closing node is dropped on its exit `transitionend`; this is the safety\n// net for when that never fires (display:none ancestor, tab hidden, a full\n// drag that left the panel exactly at its off-screen transform). Just past\n// the 500ms transition in motion.css.\nconst EXIT_FALLBACK_MS = 600;\n\ninterface DrawerContextValue {\n open: boolean;\n setOpen: (next: boolean) => void;\n direction: DrawerDirection;\n triggerRef: React.RefObject<HTMLElement | null>;\n}\n\nconst DrawerContext = React.createContext<DrawerContextValue | null>(null);\n\nfunction useDrawer(): DrawerContextValue {\n const ctx = React.useContext(DrawerContext);\n if (!ctx) throw new Error(\"Drawer parts must be used within <Drawer>\");\n return ctx;\n}\n\nexport interface DrawerProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n direction?: DrawerDirection;\n children?: React.ReactNode;\n}\n\nexport function Drawer({\n open,\n defaultOpen = false,\n onOpenChange,\n direction = \"bottom\",\n children,\n}: DrawerProps) {\n const [isOpen, setOpen] = useControllableState<boolean>({\n ...(open !== undefined ? { value: open } : {}),\n defaultValue: defaultOpen,\n ...(onOpenChange ? { onChange: onOpenChange } : {}),\n });\n const triggerRef = React.useRef<HTMLElement | null>(null);\n return (\n <DrawerContext.Provider value={{ open: isOpen, setOpen, direction, triggerRef }}>\n <div data-slot=\"drawer\">{children}</div>\n </DrawerContext.Provider>\n );\n}\n\nexport interface DrawerTriggerProps extends React.ComponentProps<\"button\"> {\n asChild?: boolean;\n}\n\nexport function DrawerTrigger({ asChild = false, onClick, ...props }: DrawerTriggerProps) {\n const { setOpen, triggerRef } = useDrawer();\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n data-slot=\"drawer-trigger\"\n ref={triggerRef as React.Ref<HTMLButtonElement>}\n onClick={(e: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(e);\n setOpen(true);\n }}\n {...(props as Record<string, unknown>)}\n />\n );\n}\n\nexport interface DrawerCloseProps extends React.ComponentProps<\"button\"> {\n asChild?: boolean;\n}\n\nexport function DrawerClose({ asChild = false, onClick, ...props }: DrawerCloseProps) {\n const { setOpen } = useDrawer();\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n data-slot=\"drawer-close\"\n onClick={(e: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(e);\n setOpen(false);\n }}\n {...(props as Record<string, unknown>)}\n />\n );\n}\n\n/**\n * Standalone scrim, redundant with the one {@link DrawerContent} renders (as in\n * shadcn). Mounted only while open; the animated exit lives on the content's\n * own scrim.\n */\nexport function DrawerOverlay({ className, ...props }: React.ComponentProps<\"div\">) {\n const { open, setOpen } = useDrawer();\n if (!open) return null;\n return (\n <div\n data-slot=\"drawer-overlay\"\n data-state=\"open\"\n onClick={() => setOpen(false)}\n className={cn(DRAWER_OVERLAY, className)}\n {...props}\n />\n );\n}\n\n// Positive delta = the finger moved towards the docked edge (bottom: down,\n// top: up, right: right, left: left), i.e. the closing direction.\nconst EDGE_SIGN: Record<DrawerDirection, 1 | -1> = {\n bottom: 1,\n top: -1,\n right: 1,\n left: -1,\n};\n\nfunction isVertical(direction: DrawerDirection): boolean {\n return direction === \"bottom\" || direction === \"top\";\n}\n\nfunction translateAlong(direction: DrawerDirection, px: number): string {\n return isVertical(direction) ? `translate3d(0, ${px}px, 0)` : `translate3d(${px}px, 0, 0)`;\n}\n\n// Vaul's over-drag curve: the panel barely moves past its docked edge. Only\n// starts displacing once the finger has gone ~6px (log(v + 1) > 2); before\n// that the curve is negative, which reads as \"stay home\".\nfunction dampen(px: number): number {\n return Math.max(8 * (Math.log(px + 1) - 2), 0);\n}\n\n// Vaul's `shouldDrag`, minus snap points. `towardsEdge` false = the user is\n// pulling the panel further open, which on a vertical sheet is the scroll\n// gesture — hand it to the scroller. The scroll walk is vertical-only: a\n// horizontal sheet never competes with its body's vertical scroll.\nfunction shouldDrag(\n target: EventTarget | null,\n panel: HTMLElement,\n direction: DrawerDirection,\n towardsEdge: boolean,\n): boolean {\n if (!(target instanceof Element)) return false;\n if (target.tagName === \"SELECT\") return false; // https://github.com/emilkowalski/vaul/issues/483\n if (target.closest(\"[data-vaul-no-drag]\")) return false;\n if (!isVertical(direction)) return true;\n if (!towardsEdge) return false;\n const selection = window.getSelection?.()?.toString();\n if (selection && selection.length > 0) return false;\n // any scroller between the finger and the panel that isn't at its top owns\n // the gesture; the user can scroll up and the next move re-asks\n let el: Element | null = target;\n while (el && el !== panel) {\n if (el.scrollHeight > el.clientHeight && el.scrollTop > 0) return false;\n el = el.parentElement;\n }\n return true;\n}\n\ninterface DragGesture {\n pointerId: number;\n // the element under the finger at pointerdown — once the panel captures the\n // pointer, every later event's `target` is the panel itself, and the scroll\n // walk in `shouldDrag` would never see the scroller it started in\n target: EventTarget | null;\n start: number; // clientX/Y along the axis\n time: number;\n size: number; // panel extent along the axis, for the close threshold + scrim fade\n allowed: boolean | null; // null = undecided; true sticks for the gesture (Vaul's isAllowedToDrag)\n delta: number;\n}\n\n// ── drag-to-dismiss (Vaul pointer physics) ────────────────────────────────\n// No React state on the hot path: the gesture lives in a ref and every move is\n// one inline `transform` write on the panel plus one `opacity` write on the\n// scrim. Not a CSS var: a custom-property change re-resolves inherited values\n// across the whole subtree, per move.\nfunction useDrawerDrag(opts: {\n panelRef: React.RefObject<HTMLDivElement | null>;\n scrimRef: React.RefObject<HTMLDivElement | null>;\n direction: DrawerDirection;\n open: boolean;\n present: boolean;\n openedAtRef: React.RefObject<number>;\n onClose: () => void;\n}) {\n const { panelRef, scrimRef, direction, open, present, openedAtRef, onClose } = opts;\n const dragRef = React.useRef<DragGesture | null>(null);\n\n // Native scroll suppression. Once a gesture is allowed, the browser must not\n // turn the same touch into a scroll/overscroll of a body sitting at its top —\n // that would pointercancel us mid-drag. Pointer events precede the compat\n // touch events, so `allowed` is already decided when this runs. React's\n // onTouchMove is passive, hence the manual listener.\n React.useEffect(() => {\n if (!present) return;\n const panel = panelRef.current;\n if (!panel) return;\n const onTouchMove = (e: TouchEvent) => {\n if (dragRef.current?.allowed) e.preventDefault();\n };\n panel.addEventListener(\"touchmove\", onTouchMove, { passive: false });\n return () => panel.removeEventListener(\"touchmove\", onTouchMove);\n }, [present, panelRef]);\n\n const axisPos = (e: React.PointerEvent) => (isVertical(direction) ? e.clientY : e.clientX);\n\n const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n const panel = panelRef.current;\n // one gesture at a time: a second finger must not reset the first one's\n // state and leave the panel stranded mid-drag\n if (!panel || e.button > 0 || !open || dragRef.current) return;\n const target = e.target as HTMLElement;\n if (target.closest('[data-slot=\"drawer-close\"]')) return;\n // React bubbles portal events (a Select's listbox, a Popover) through the\n // tree; a drag can only start from the panel's own DOM\n if (!panel.contains(target)) return;\n const rect = panel.getBoundingClientRect();\n dragRef.current = {\n pointerId: e.pointerId,\n target,\n start: axisPos(e),\n time: Date.now(),\n size: isVertical(direction) ? rect.height : rect.width,\n allowed: null,\n delta: 0,\n };\n // Capture on the element under the finger, not the panel (Vaul does the\n // same): a click's target is the common ancestor of pointerdown and\n // pointerup, so capturing on the panel would steal every click from the\n // buttons and links inside. No preventDefault either — inputs inside the\n // sheet must still focus on tap.\n try {\n target.setPointerCapture?.(e.pointerId);\n } catch {\n // jsdom / unsupported — capture is a nice-to-have, the drag works without it\n }\n };\n\n const onPointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n const drag = dragRef.current;\n const panel = panelRef.current;\n if (!drag || !panel) return;\n const delta = (axisPos(e) - drag.start) * EDGE_SIGN[direction];\n drag.delta = delta;\n if (!drag.allowed) {\n if (Date.now() - openedAtRef.current < DRAG_AFTER_OPEN_MS) return;\n // refused on this move only — the user may scroll the body to its top\n // and carry on, so the gesture stays alive\n if (!shouldDrag(drag.target, panel, direction, delta > 0)) return;\n drag.allowed = true;\n panel.setAttribute(\"data-dragging\", \"true\"); // CSS drops the transitions for 1:1 tracking\n scrimRef.current?.setAttribute(\"data-dragging\", \"true\");\n }\n const scrim = scrimRef.current;\n if (delta < 0) {\n panel.style.transform = translateAlong(direction, -dampen(-delta) * EDGE_SIGN[direction]);\n if (scrim) scrim.style.opacity = \"1\";\n return;\n }\n panel.style.transform = translateAlong(direction, delta * EDGE_SIGN[direction]);\n if (scrim) {\n scrim.style.opacity = `${Math.min(1, Math.max(0, 1 - delta / drag.size))}`;\n }\n };\n\n // Release hands styling back to the CSS: with the inline transform gone and\n // data-dragging cleared in the same frame, the restored transition carries\n // the panel from wherever the finger left it — home on a snap-back, or (with\n // data-state=closed committed by `onClose` in the same frame) straight off.\n const endGesture = (e: React.PointerEvent<HTMLDivElement>, cancelled: boolean) => {\n const drag = dragRef.current;\n const panel = panelRef.current;\n if (!drag || !panel || e.pointerId !== drag.pointerId) return;\n dragRef.current = null;\n try {\n (drag.target as HTMLElement).releasePointerCapture?.(drag.pointerId);\n } catch {\n // jsdom / unsupported\n }\n if (!drag.allowed) return;\n panel.removeAttribute(\"data-dragging\");\n panel.style.transform = \"\";\n const scrim = scrimRef.current;\n if (scrim) {\n scrim.removeAttribute(\"data-dragging\");\n scrim.style.opacity = \"\";\n }\n if (cancelled || drag.delta <= 0) return;\n const dt = Date.now() - drag.time;\n const velocity = dt > 0 ? drag.delta / dt : 0;\n if (velocity > VELOCITY_THRESHOLD || drag.delta >= drag.size * CLOSE_THRESHOLD) {\n onClose();\n }\n };\n\n return {\n onPointerDown,\n onPointerMove,\n onPointerUp: (e: React.PointerEvent<HTMLDivElement>) => endGesture(e, false),\n onPointerCancel: (e: React.PointerEvent<HTMLDivElement>) => endGesture(e, true),\n };\n}\n\n/**\n * The panel plus its scrim. Presence outlives `open`: once it turns false the\n * panel flips to `data-state=\"closed\"` and is unmounted when its exit\n * `transform` transition ends (or the fallback timer fires). Re-opening\n * mid-exit just flips the state back and the same transition carries the\n * panel home. Drag-to-dismiss is TS-only pointer physics; opt a region out\n * with `data-vaul-no-drag`.\n */\nexport function DrawerContent({ className, children, ...props }: React.ComponentProps<\"div\">) {\n const { open, setOpen, direction, triggerRef } = useDrawer();\n // Derived during render so the panel is in the same commit that opened it —\n // the enter keyframe plays on insertion, no mount flip needed.\n const [present, setPresent] = React.useState(open);\n if (open && !present) setPresent(true);\n const closing = present && !open;\n\n const scopeRef = useFocusScope(open, { returnFocusTo: triggerRef });\n const panelRef = React.useRef<HTMLDivElement | null>(null);\n const scrimRef = React.useRef<HTMLDivElement | null>(null);\n const openedAtRef = React.useRef(0);\n\n React.useEffect(() => {\n if (open) openedAtRef.current = Date.now();\n }, [open]);\n\n React.useEffect(() => {\n if (!open) return;\n const prev = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = prev;\n };\n }, [open]);\n\n // Safety net for a missed exit transitionend; the cleanup is what cancels it\n // on re-open.\n React.useEffect(() => {\n if (!closing) return;\n const id = setTimeout(() => setPresent(false), EXIT_FALLBACK_MS);\n return () => clearTimeout(id);\n }, [closing]);\n\n const drag = useDrawerDrag({\n panelRef,\n scrimRef,\n direction,\n open,\n present,\n openedAtRef,\n onClose: () => setOpen(false),\n });\n\n if (!present) return null;\n const state = closing ? \"closed\" : \"open\";\n return (\n <Portal>\n <div\n ref={scrimRef}\n data-slot=\"drawer-overlay\"\n data-state={state}\n className={DRAWER_OVERLAY}\n onClick={() => setOpen(false)}\n />\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n data-slot=\"drawer-content\"\n data-state={state}\n data-vaul-drawer-direction={direction}\n ref={mergeRefs(scopeRef, panelRef)}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") setOpen(false);\n }}\n // transitionend bubbles from children (a hover on a button inside),\n // so pin it to the panel's own exit transform\n onTransitionEnd={(e) => {\n if (closing && e.propertyName === \"transform\" && e.target === e.currentTarget) {\n setPresent(false);\n }\n }}\n onPointerDown={drag.onPointerDown}\n onPointerMove={drag.onPointerMove}\n onPointerUp={drag.onPointerUp}\n onPointerCancel={drag.onPointerCancel}\n className={cn(DRAWER_CONTENT_BASE, drawerDirectionClasses[direction], className)}\n {...(props as Record<string, unknown>)}\n >\n {direction === \"bottom\" ? (\n <div\n data-slot=\"drawer-handle\"\n className={DRAWER_HANDLE}\n />\n ) : null}\n <div\n data-slot=\"drawer-body\"\n className={DRAWER_BODY}\n >\n {children}\n </div>\n </div>\n </Portal>\n );\n}\n\nexport function DrawerHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-header\"\n className={cn(DRAWER_HEADER, className)}\n {...props}\n />\n );\n}\n\nexport function DrawerFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-footer\"\n className={cn(DRAWER_FOOTER, className)}\n {...props}\n />\n );\n}\n\nexport function DrawerTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-title\"\n className={cn(DRAWER_TITLE, className)}\n {...props}\n />\n );\n}\n\nexport function DrawerDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-description\"\n className={cn(DRAWER_DESCRIPTION, className)}\n {...props}\n />\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/drawer.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useControllableState } from \"../primitives/use-controllable-state\";\nimport { DismissableLayerScope, useDismissableLayer } from \"../primitives/dismissable-layer\";\nimport { useFocusScope } from \"../primitives/focus-scope\";\nimport { mergeRefs } from \"../primitives/merge-refs\";\nimport { Portal } from \"../primitives/portal\";\nimport { Slot } from \"../primitives/slot\";\nimport {\n DRAWER_BODY,\n DRAWER_CONTENT_BASE,\n DRAWER_DESCRIPTION,\n DRAWER_FOOTER,\n DRAWER_HANDLE,\n DRAWER_HEADER,\n DRAWER_OVERLAY,\n DRAWER_TITLE,\n drawerDirectionClasses,\n type DrawerDirection,\n} from \"../generated/drawer\";\n\nexport type { DrawerDirection };\n\n// Drag-to-dismiss tuning (pointer physics, TS-only — Rust stays render-only).\n// Values from Vaul: a release past 25% of the panel's size along the drag\n// axis, or a flick faster than 0.4px/ms, closes; anything short snaps back.\n// Drags are refused for the first 500ms after opening so the enter finishes.\nconst CLOSE_THRESHOLD = 0.25;\nconst VELOCITY_THRESHOLD = 0.4;\nconst DRAG_AFTER_OPEN_MS = 500;\n// The closing node is dropped on its exit `transitionend`; this is the safety\n// net for when that never fires (display:none ancestor, tab hidden, a full\n// drag that left the panel exactly at its off-screen transform). Just past\n// the 500ms transition in motion.css.\nconst EXIT_FALLBACK_MS = 600;\n\ninterface DrawerContextValue {\n open: boolean;\n setOpen: (next: boolean) => void;\n direction: DrawerDirection;\n triggerRef: React.RefObject<HTMLElement | null>;\n}\n\nconst DrawerContext = React.createContext<DrawerContextValue | null>(null);\n\nfunction useDrawer(): DrawerContextValue {\n const ctx = React.useContext(DrawerContext);\n if (!ctx) throw new Error(\"Drawer parts must be used within <Drawer>\");\n return ctx;\n}\n\nexport interface DrawerProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n direction?: DrawerDirection;\n children?: React.ReactNode;\n}\n\nexport function Drawer({\n open,\n defaultOpen = false,\n onOpenChange,\n direction = \"bottom\",\n children,\n}: DrawerProps) {\n const [isOpen, setOpen] = useControllableState<boolean>({\n ...(open !== undefined ? { value: open } : {}),\n defaultValue: defaultOpen,\n ...(onOpenChange ? { onChange: onOpenChange } : {}),\n });\n const triggerRef = React.useRef<HTMLElement | null>(null);\n return (\n <DrawerContext.Provider value={{ open: isOpen, setOpen, direction, triggerRef }}>\n <div data-slot=\"drawer\">{children}</div>\n </DrawerContext.Provider>\n );\n}\n\nexport interface DrawerTriggerProps extends React.ComponentProps<\"button\"> {\n asChild?: boolean;\n}\n\nexport function DrawerTrigger({ asChild = false, onClick, ...props }: DrawerTriggerProps) {\n const { setOpen, triggerRef } = useDrawer();\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n data-slot=\"drawer-trigger\"\n ref={triggerRef as React.Ref<HTMLButtonElement>}\n onClick={(e: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(e);\n setOpen(true);\n }}\n {...(props as Record<string, unknown>)}\n />\n );\n}\n\nexport interface DrawerCloseProps extends React.ComponentProps<\"button\"> {\n asChild?: boolean;\n}\n\nexport function DrawerClose({ asChild = false, onClick, ...props }: DrawerCloseProps) {\n const { setOpen } = useDrawer();\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n data-slot=\"drawer-close\"\n onClick={(e: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(e);\n setOpen(false);\n }}\n {...(props as Record<string, unknown>)}\n />\n );\n}\n\n/**\n * Standalone scrim, redundant with the one {@link DrawerContent} renders (as in\n * shadcn). Mounted only while open; the animated exit lives on the content's\n * own scrim.\n */\nexport function DrawerOverlay({ className, ...props }: React.ComponentProps<\"div\">) {\n const { open, setOpen } = useDrawer();\n if (!open) return null;\n return (\n <div\n data-slot=\"drawer-overlay\"\n data-state=\"open\"\n onClick={() => setOpen(false)}\n className={cn(DRAWER_OVERLAY, className)}\n {...props}\n />\n );\n}\n\n// Positive delta = the finger moved towards the docked edge (bottom: down,\n// top: up, right: right, left: left), i.e. the closing direction.\nconst EDGE_SIGN: Record<DrawerDirection, 1 | -1> = {\n bottom: 1,\n top: -1,\n right: 1,\n left: -1,\n};\n\nfunction isVertical(direction: DrawerDirection): boolean {\n return direction === \"bottom\" || direction === \"top\";\n}\n\nfunction translateAlong(direction: DrawerDirection, px: number): string {\n return isVertical(direction) ? `translate3d(0, ${px}px, 0)` : `translate3d(${px}px, 0, 0)`;\n}\n\n// Vaul's over-drag curve: the panel barely moves past its docked edge. Only\n// starts displacing once the finger has gone ~6px (log(v + 1) > 2); before\n// that the curve is negative, which reads as \"stay home\".\nfunction dampen(px: number): number {\n return Math.max(8 * (Math.log(px + 1) - 2), 0);\n}\n\n// Vaul's `shouldDrag`, minus snap points. `towardsEdge` false = the user is\n// pulling the panel further open, which on a vertical sheet is the scroll\n// gesture — hand it to the scroller. The scroll walk is vertical-only: a\n// horizontal sheet never competes with its body's vertical scroll.\nfunction shouldDrag(\n target: EventTarget | null,\n panel: HTMLElement,\n direction: DrawerDirection,\n towardsEdge: boolean,\n): boolean {\n if (!(target instanceof Element)) return false;\n if (target.tagName === \"SELECT\") return false; // https://github.com/emilkowalski/vaul/issues/483\n if (target.closest(\"[data-vaul-no-drag]\")) return false;\n if (!isVertical(direction)) return true;\n if (!towardsEdge) return false;\n const selection = window.getSelection?.()?.toString();\n if (selection && selection.length > 0) return false;\n // any scroller between the finger and the panel that isn't at its top owns\n // the gesture; the user can scroll up and the next move re-asks\n let el: Element | null = target;\n while (el && el !== panel) {\n if (el.scrollHeight > el.clientHeight && el.scrollTop > 0) return false;\n el = el.parentElement;\n }\n return true;\n}\n\ninterface DragGesture {\n pointerId: number;\n // the element under the finger at pointerdown — once the panel captures the\n // pointer, every later event's `target` is the panel itself, and the scroll\n // walk in `shouldDrag` would never see the scroller it started in\n target: EventTarget | null;\n start: number; // clientX/Y along the axis\n time: number;\n size: number; // panel extent along the axis, for the close threshold + scrim fade\n allowed: boolean | null; // null = undecided; true sticks for the gesture (Vaul's isAllowedToDrag)\n delta: number;\n}\n\n// ── drag-to-dismiss (Vaul pointer physics) ────────────────────────────────\n// No React state on the hot path: the gesture lives in a ref and every move is\n// one inline `transform` write on the panel plus one `opacity` write on the\n// scrim. Not a CSS var: a custom-property change re-resolves inherited values\n// across the whole subtree, per move.\nfunction useDrawerDrag(opts: {\n panelRef: React.RefObject<HTMLDivElement | null>;\n scrimRef: React.RefObject<HTMLDivElement | null>;\n direction: DrawerDirection;\n open: boolean;\n present: boolean;\n openedAtRef: React.RefObject<number>;\n onClose: () => void;\n}) {\n const { panelRef, scrimRef, direction, open, present, openedAtRef, onClose } = opts;\n const dragRef = React.useRef<DragGesture | null>(null);\n\n // Native scroll suppression. Once a gesture is allowed, the browser must not\n // turn the same touch into a scroll/overscroll of a body sitting at its top —\n // that would pointercancel us mid-drag. Pointer events precede the compat\n // touch events, so `allowed` is already decided when this runs. React's\n // onTouchMove is passive, hence the manual listener.\n React.useEffect(() => {\n if (!present) return;\n const panel = panelRef.current;\n if (!panel) return;\n const onTouchMove = (e: TouchEvent) => {\n if (dragRef.current?.allowed) e.preventDefault();\n };\n panel.addEventListener(\"touchmove\", onTouchMove, { passive: false });\n return () => panel.removeEventListener(\"touchmove\", onTouchMove);\n }, [present, panelRef]);\n\n const axisPos = (e: React.PointerEvent) => (isVertical(direction) ? e.clientY : e.clientX);\n\n const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n const panel = panelRef.current;\n // one gesture at a time: a second finger must not reset the first one's\n // state and leave the panel stranded mid-drag\n if (!panel || e.button > 0 || !open || dragRef.current) return;\n const target = e.target as HTMLElement;\n if (target.closest('[data-slot=\"drawer-close\"]')) return;\n // React bubbles portal events (a Select's listbox, a Popover) through the\n // tree; a drag can only start from the panel's own DOM\n if (!panel.contains(target)) return;\n const rect = panel.getBoundingClientRect();\n dragRef.current = {\n pointerId: e.pointerId,\n target,\n start: axisPos(e),\n time: Date.now(),\n size: isVertical(direction) ? rect.height : rect.width,\n allowed: null,\n delta: 0,\n };\n // Capture on the element under the finger, not the panel (Vaul does the\n // same): a click's target is the common ancestor of pointerdown and\n // pointerup, so capturing on the panel would steal every click from the\n // buttons and links inside. No preventDefault either — inputs inside the\n // sheet must still focus on tap.\n try {\n target.setPointerCapture?.(e.pointerId);\n } catch {\n // jsdom / unsupported — capture is a nice-to-have, the drag works without it\n }\n };\n\n const onPointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n const drag = dragRef.current;\n const panel = panelRef.current;\n if (!drag || !panel) return;\n const delta = (axisPos(e) - drag.start) * EDGE_SIGN[direction];\n drag.delta = delta;\n if (!drag.allowed) {\n if (Date.now() - openedAtRef.current < DRAG_AFTER_OPEN_MS) return;\n // refused on this move only — the user may scroll the body to its top\n // and carry on, so the gesture stays alive\n if (!shouldDrag(drag.target, panel, direction, delta > 0)) return;\n drag.allowed = true;\n panel.setAttribute(\"data-dragging\", \"true\"); // CSS drops the transitions for 1:1 tracking\n scrimRef.current?.setAttribute(\"data-dragging\", \"true\");\n }\n const scrim = scrimRef.current;\n if (delta < 0) {\n panel.style.transform = translateAlong(direction, -dampen(-delta) * EDGE_SIGN[direction]);\n if (scrim) scrim.style.opacity = \"1\";\n return;\n }\n panel.style.transform = translateAlong(direction, delta * EDGE_SIGN[direction]);\n if (scrim) {\n scrim.style.opacity = `${Math.min(1, Math.max(0, 1 - delta / drag.size))}`;\n }\n };\n\n // Release hands styling back to the CSS: with the inline transform gone and\n // data-dragging cleared in the same frame, the restored transition carries\n // the panel from wherever the finger left it — home on a snap-back, or (with\n // data-state=closed committed by `onClose` in the same frame) straight off.\n const endGesture = (e: React.PointerEvent<HTMLDivElement>, cancelled: boolean) => {\n const drag = dragRef.current;\n const panel = panelRef.current;\n if (!drag || !panel || e.pointerId !== drag.pointerId) return;\n dragRef.current = null;\n try {\n (drag.target as HTMLElement).releasePointerCapture?.(drag.pointerId);\n } catch {\n // jsdom / unsupported\n }\n if (!drag.allowed) return;\n panel.removeAttribute(\"data-dragging\");\n panel.style.transform = \"\";\n const scrim = scrimRef.current;\n if (scrim) {\n scrim.removeAttribute(\"data-dragging\");\n scrim.style.opacity = \"\";\n }\n if (cancelled || drag.delta <= 0) return;\n const dt = Date.now() - drag.time;\n const velocity = dt > 0 ? drag.delta / dt : 0;\n if (velocity > VELOCITY_THRESHOLD || drag.delta >= drag.size * CLOSE_THRESHOLD) {\n onClose();\n }\n };\n\n return {\n onPointerDown,\n onPointerMove,\n onPointerUp: (e: React.PointerEvent<HTMLDivElement>) => endGesture(e, false),\n onPointerCancel: (e: React.PointerEvent<HTMLDivElement>) => endGesture(e, true),\n };\n}\n\n/**\n * The panel plus its scrim. Presence outlives `open`: once it turns false the\n * panel flips to `data-state=\"closed\"` and is unmounted when its exit\n * `transform` transition ends (or the fallback timer fires). Re-opening\n * mid-exit just flips the state back and the same transition carries the\n * panel home. Drag-to-dismiss is TS-only pointer physics; opt a region out\n * with `data-vaul-no-drag`.\n */\nexport function DrawerContent({ className, children, ...props }: React.ComponentProps<\"div\">) {\n const { open, setOpen, direction, triggerRef } = useDrawer();\n // Derived during render so the panel is in the same commit that opened it —\n // the enter keyframe plays on insertion, no mount flip needed.\n const [present, setPresent] = React.useState(open);\n if (open && !present) setPresent(true);\n const closing = present && !open;\n\n const scopeRef = useFocusScope(open, { returnFocusTo: triggerRef });\n const panelRef = React.useRef<HTMLDivElement | null>(null);\n const scrimRef = React.useRef<HTMLDivElement | null>(null);\n const openedAtRef = React.useRef(0);\n\n React.useEffect(() => {\n if (open) openedAtRef.current = Date.now();\n }, [open]);\n\n React.useEffect(() => {\n if (!open) return;\n const prev = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = prev;\n };\n }, [open]);\n\n // Safety net for a missed exit transitionend; the cleanup is what cancels it\n // on re-open.\n React.useEffect(() => {\n if (!closing) return;\n const id = setTimeout(() => setPresent(false), EXIT_FALLBACK_MS);\n return () => clearTimeout(id);\n }, [closing]);\n\n const drag = useDrawerDrag({\n panelRef,\n scrimRef,\n direction,\n open,\n present,\n openedAtRef,\n onClose: () => setOpen(false),\n });\n\n // On the stack for Escape, and modal so the layers below ignore every press\n // while it is open — its scrim included. Outside clicks stay with the scrim:\n // it covers everything but the layers above, so a press on a toast or a\n // nested Dialog's backdrop is not a click away from the Drawer.\n const dismissRef = useDismissableLayer({\n enabled: open,\n onDismiss: () => setOpen(false),\n pointerOutside: false,\n modal: true,\n });\n\n if (!present) return null;\n const state = closing ? \"closed\" : \"open\";\n return (\n <Portal>\n <div\n ref={scrimRef}\n data-slot=\"drawer-overlay\"\n data-state={state}\n className={DRAWER_OVERLAY}\n onClick={() => setOpen(false)}\n />\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n data-slot=\"drawer-content\"\n data-state={state}\n data-vaul-drawer-direction={direction}\n ref={mergeRefs(scopeRef, panelRef, dismissRef)}\n // transitionend bubbles from children (a hover on a button inside),\n // so pin it to the panel's own exit transform\n onTransitionEnd={(e) => {\n if (closing && e.propertyName === \"transform\" && e.target === e.currentTarget) {\n setPresent(false);\n }\n }}\n onPointerDown={drag.onPointerDown}\n onPointerMove={drag.onPointerMove}\n onPointerUp={drag.onPointerUp}\n onPointerCancel={drag.onPointerCancel}\n className={cn(DRAWER_CONTENT_BASE, drawerDirectionClasses[direction], className)}\n {...(props as Record<string, unknown>)}\n >\n {direction === \"bottom\" ? (\n <div\n data-slot=\"drawer-handle\"\n className={DRAWER_HANDLE}\n />\n ) : null}\n <div\n data-slot=\"drawer-body\"\n className={DRAWER_BODY}\n >\n <DismissableLayerScope layer={dismissRef}>{children}</DismissableLayerScope>\n </div>\n </div>\n </Portal>\n );\n}\n\nexport function DrawerHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-header\"\n className={cn(DRAWER_HEADER, className)}\n {...props}\n />\n );\n}\n\nexport function DrawerFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-footer\"\n className={cn(DRAWER_FOOTER, className)}\n {...props}\n />\n );\n}\n\nexport function DrawerTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-title\"\n className={cn(DRAWER_TITLE, className)}\n {...props}\n />\n );\n}\n\nexport function DrawerDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-description\"\n className={cn(DRAWER_DESCRIPTION, className)}\n {...props}\n />\n );\n}\n"],"mappings":"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","names":[]}
@@ -4,7 +4,7 @@ import * as React from "react";
4
4
  import { cn } from "../lib/cn.js";
5
5
  import { useControllableState } from "../primitives/use-controllable-state.js";
6
6
  import { useFloating } from "../primitives/use-floating.js";
7
- import { useDismissableLayer } from "../primitives/dismissable-layer.js";
7
+ import { DismissableLayerScope, useDismissableLayer } from "../primitives/dismissable-layer.js";
8
8
  import { usePresence } from "../primitives/presence.js";
9
9
  import { useRovingFocus } from "../primitives/use-roving-focus.js";
10
10
  import { mergeRefs } from "../primitives/merge-refs.js";
@@ -63,6 +63,7 @@ function DropdownMenuTrigger({ asChild = false, onClick, ...props }) {
63
63
  function DropdownMenuContent({
64
64
  className,
65
65
  sideOffset = 4,
66
+ align = "start",
66
67
  children,
67
68
  ...props
68
69
  }) {
@@ -72,7 +73,7 @@ function DropdownMenuContent({
72
73
  anchorRef,
73
74
  open,
74
75
  side: "bottom",
75
- align: "start",
76
+ align,
76
77
  offset: sideOffset
77
78
  });
78
79
  const dismissRef = useDismissableLayer({
@@ -84,11 +85,14 @@ function DropdownMenuContent({
84
85
  const items = () => Array.from(
85
86
  contentRef.current?.querySelectorAll("[role^='menuitem']") ?? []
86
87
  ).filter((el) => el.getAttribute("data-disabled") === null);
87
- const { activeIndex, onKeyDown: rovingKeyDown } = useRovingFocus({
88
- count: 64,
88
+ const { activeIndex, setActiveIndex, onKeyDown: rovingKeyDown } = useRovingFocus({
89
+ count: () => items().length,
89
90
  orientation: "vertical",
90
91
  loop: true
91
92
  });
93
+ React.useEffect(() => {
94
+ if (!open) setActiveIndex(0);
95
+ }, [open, setActiveIndex]);
92
96
  React.useEffect(() => {
93
97
  if (!open) return;
94
98
  items()[activeIndex]?.focus();
@@ -103,10 +107,7 @@ function DropdownMenuContent({
103
107
  "data-side": side,
104
108
  role: "menu",
105
109
  tabIndex: -1,
106
- onKeyDown: (e) => {
107
- rovingKeyDown(e);
108
- if (e.key === "Escape") setOpen(false);
109
- },
110
+ onKeyDown: rovingKeyDown,
110
111
  ref: mergeRefs(floatingRef, dismissRef, presRef, contentRef),
111
112
  style,
112
113
  className: cn(
@@ -114,7 +115,7 @@ function DropdownMenuContent({
114
115
  className
115
116
  ),
116
117
  ...props,
117
- children
118
+ children: /* @__PURE__ */ jsx(DismissableLayerScope, { layer: dismissRef, children })
118
119
  }
119
120
  ) }) });
120
121
  }
@@ -124,6 +125,7 @@ function DropdownMenuGroup({ className, ...props }) {
124
125
  return /* @__PURE__ */ jsx("div", { "data-slot": "dropdown-menu-group", role: "group", className, ...props });
125
126
  }
126
127
  function DropdownMenuItem({
128
+ asChild = false,
127
129
  className,
128
130
  inset,
129
131
  variant = "neutral",
@@ -133,8 +135,9 @@ function DropdownMenuItem({
133
135
  ...props
134
136
  }) {
135
137
  const close = React.useContext(DropdownMenuCloseContext);
138
+ const Comp = asChild ? Slot : "div";
136
139
  return /* @__PURE__ */ jsx(
137
- "div",
140
+ Comp,
138
141
  {
139
142
  "data-slot": "dropdown-menu-item",
140
143
  "data-inset": inset ? "" : void 0,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/dropdown-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useControllableState } from \"../primitives/use-controllable-state\";\nimport { useFloating } from \"../primitives/use-floating\";\nimport { useDismissableLayer } from \"../primitives/dismissable-layer\";\nimport { usePresence } from \"../primitives/presence\";\nimport { useRovingFocus } from \"../primitives/use-roving-focus\";\nimport { mergeRefs } from \"../primitives/merge-refs\";\nimport { Portal } from \"../primitives/portal\";\nimport { Slot } from \"../primitives/slot\";\nimport {\n DROPDOWN_MENU_CHECK_ITEM,\n DROPDOWN_MENU_CONTENT,\n DROPDOWN_MENU_ITEM,\n DROPDOWN_MENU_ITEM_INDICATOR,\n DROPDOWN_MENU_LABEL,\n DROPDOWN_MENU_SEPARATOR,\n DROPDOWN_MENU_SHORTCUT,\n DROPDOWN_MENU_SUB_CONTENT,\n DROPDOWN_MENU_SUB_TRIGGER,\n} from \"../generated/dropdown-menu\";\n\ninterface DropdownMenuContextValue {\n open: boolean;\n setOpen: (next: boolean) => void;\n anchorRef: React.RefObject<HTMLElement | null>;\n}\n\nconst DropdownMenuContext = React.createContext<DropdownMenuContextValue | null>(\n null,\n);\n\nfunction useDropdownMenu(): DropdownMenuContextValue {\n const ctx = React.useContext(DropdownMenuContext);\n if (!ctx) throw new Error(\"DropdownMenu parts must be used within <DropdownMenu>\");\n return ctx;\n}\n\nexport interface DropdownMenuProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n children?: React.ReactNode;\n}\n\nexport function DropdownMenu({ open, defaultOpen = false, onOpenChange, children }: DropdownMenuProps) {\n const [isOpen, setOpen] = useControllableState<boolean>({\n ...(open !== undefined ? { value: open } : {}),\n defaultValue: defaultOpen,\n ...(onOpenChange ? { onChange: onOpenChange } : {}),\n });\n const anchorRef = React.useRef<HTMLElement | null>(null);\n return (\n <DropdownMenuContext.Provider value={{ open: isOpen, setOpen, anchorRef }}>\n <div data-slot=\"dropdown-menu\">{children}</div>\n </DropdownMenuContext.Provider>\n );\n}\n\nexport function DropdownMenuPortal({ children }: { children?: React.ReactNode }) {\n return <Portal>{children}</Portal>;\n}\n\nexport interface DropdownMenuTriggerProps extends React.ComponentProps<\"button\"> {\n asChild?: boolean;\n}\n\nexport function DropdownMenuTrigger({ asChild = false, onClick, ...props }: DropdownMenuTriggerProps) {\n const { open, setOpen, anchorRef } = useDropdownMenu();\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n data-slot=\"dropdown-menu-trigger\"\n aria-haspopup=\"menu\"\n aria-expanded={open}\n data-state={open ? \"open\" : \"closed\"}\n ref={anchorRef as React.Ref<HTMLButtonElement>}\n onClick={(e: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(e);\n setOpen(!open);\n }}\n {...(props as Record<string, unknown>)}\n />\n );\n}\n\nexport interface DropdownMenuContentProps extends React.ComponentProps<\"div\"> {\n sideOffset?: number;\n}\n\nexport function DropdownMenuContent({\n className,\n sideOffset = 4,\n children,\n ...props\n}: DropdownMenuContentProps) {\n const { open, setOpen, anchorRef } = useDropdownMenu();\n const { isPresent, ref: presRef } = usePresence(open);\n const { floatingRef, style, side } = useFloating({\n anchorRef,\n open,\n side: \"bottom\",\n align: \"start\",\n offset: sideOffset,\n });\n const dismissRef = useDismissableLayer({\n enabled: open,\n onDismiss: () => setOpen(false),\n exclude: [anchorRef],\n });\n const contentRef = React.useRef<HTMLDivElement | null>(null);\n // Roving focus across rendered menu items: ArrowUp/Down move the active item.\n const items = () =>\n Array.from(\n contentRef.current?.querySelectorAll<HTMLElement>(\"[role^='menuitem']\") ?? [],\n ).filter((el) => el.getAttribute(\"data-disabled\") === null);\n const { activeIndex, onKeyDown: rovingKeyDown } = useRovingFocus({\n count: 64,\n orientation: \"vertical\",\n loop: true,\n });\n React.useEffect(() => {\n if (!open) return;\n items()[activeIndex]?.focus();\n }, [open, activeIndex]);\n // Selecting an item closes the menu: items call this through context.\n const close = React.useCallback(() => setOpen(false), [setOpen]);\n if (!isPresent) return null;\n return (\n <Portal>\n <DropdownMenuCloseContext.Provider value={close}>\n <div\n data-slot=\"dropdown-menu-content\"\n data-state={open ? \"open\" : \"closed\"}\n data-side={side}\n role=\"menu\"\n tabIndex={-1}\n onKeyDown={(e) => {\n rovingKeyDown(e);\n if (e.key === \"Escape\") setOpen(false);\n }}\n ref={mergeRefs(floatingRef, dismissRef, presRef, contentRef)}\n style={style}\n className={cn(\n DROPDOWN_MENU_CONTENT,\n className,\n )}\n {...(props as Record<string, unknown>)}\n >\n {children}\n </div>\n </DropdownMenuCloseContext.Provider>\n </Portal>\n );\n}\n\nconst DropdownMenuCloseContext = React.createContext<() => void>(() => {});\n\nexport function DropdownMenuGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div data-slot=\"dropdown-menu-group\" role=\"group\" className={className} {...props} />;\n}\n\nexport interface DropdownMenuItemProps extends React.ComponentProps<\"div\"> {\n inset?: boolean;\n variant?: \"neutral\" | \"destructive\";\n disabled?: boolean;\n}\n\nexport function DropdownMenuItem({\n className,\n inset,\n variant = \"neutral\",\n disabled,\n onClick,\n onKeyDown,\n ...props\n}: DropdownMenuItemProps) {\n const close = React.useContext(DropdownMenuCloseContext);\n return (\n <div\n data-slot=\"dropdown-menu-item\"\n data-inset={inset ? \"\" : undefined}\n data-variant={variant}\n data-disabled={disabled ? \"\" : undefined}\n role=\"menuitem\"\n tabIndex={disabled ? undefined : -1}\n className={cn(\n DROPDOWN_MENU_ITEM,\n className,\n )}\n onClick={(e) => {\n if (disabled) return;\n onClick?.(e);\n close();\n }}\n onKeyDown={(e) => {\n onKeyDown?.(e);\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n (e.currentTarget as HTMLElement).click();\n }\n }}\n {...props}\n />\n );\n}\n\nexport interface DropdownMenuCheckboxItemProps extends React.ComponentProps<\"div\"> {\n checked?: boolean;\n disabled?: boolean;\n}\n\nexport function DropdownMenuCheckboxItem({\n className,\n children,\n checked,\n disabled,\n onClick,\n ...props\n}: DropdownMenuCheckboxItemProps) {\n const close = React.useContext(DropdownMenuCloseContext);\n return (\n <div\n data-slot=\"dropdown-menu-checkbox-item\"\n role=\"menuitemcheckbox\"\n aria-checked={checked}\n data-state={checked ? \"checked\" : \"unchecked\"}\n data-disabled={disabled ? \"\" : undefined}\n tabIndex={disabled ? undefined : -1}\n className={cn(\n DROPDOWN_MENU_CHECK_ITEM,\n className,\n )}\n onClick={(e) => {\n if (disabled) return;\n onClick?.(e);\n close();\n }}\n {...props}\n >\n <span className={DROPDOWN_MENU_ITEM_INDICATOR}>\n {checked ? (\n <svg className=\"size-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n ) : null}\n </span>\n {children}\n </div>\n );\n}\n\ninterface DropdownMenuRadioGroupContextValue {\n value: string | undefined;\n setValue: (next: string) => void;\n}\n\nconst DropdownMenuRadioGroupContext =\n React.createContext<DropdownMenuRadioGroupContextValue | null>(null);\n\nexport interface DropdownMenuRadioGroupProps extends Omit<React.ComponentProps<\"div\">, \"onChange\"> {\n value?: string;\n onValueChange?: (value: string) => void;\n}\n\nexport function DropdownMenuRadioGroup({\n className,\n value,\n onValueChange,\n children,\n ...props\n}: DropdownMenuRadioGroupProps) {\n const ctx = React.useMemo<DropdownMenuRadioGroupContextValue>(\n () => ({ value, setValue: (next) => onValueChange?.(next) }),\n [value, onValueChange],\n );\n return (\n <DropdownMenuRadioGroupContext.Provider value={ctx}>\n <div data-slot=\"dropdown-menu-radio-group\" role=\"group\" className={className} {...props}>\n {children}\n </div>\n </DropdownMenuRadioGroupContext.Provider>\n );\n}\n\nexport interface DropdownMenuRadioItemProps extends React.ComponentProps<\"div\"> {\n value: string;\n disabled?: boolean;\n}\n\nexport function DropdownMenuRadioItem({\n className,\n children,\n value,\n disabled,\n onClick,\n ...props\n}: DropdownMenuRadioItemProps) {\n const close = React.useContext(DropdownMenuCloseContext);\n const group = React.useContext(DropdownMenuRadioGroupContext);\n const checked = group?.value === value;\n return (\n <div\n data-slot=\"dropdown-menu-radio-item\"\n role=\"menuitemradio\"\n aria-checked={checked}\n data-state={checked ? \"checked\" : \"unchecked\"}\n data-disabled={disabled ? \"\" : undefined}\n tabIndex={disabled ? undefined : -1}\n className={cn(\n DROPDOWN_MENU_CHECK_ITEM,\n className,\n )}\n onClick={(e) => {\n if (disabled) return;\n onClick?.(e);\n group?.setValue(value);\n close();\n }}\n {...props}\n >\n <span className={DROPDOWN_MENU_ITEM_INDICATOR}>\n {checked ? (\n <svg className=\"size-2 fill-current\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n </svg>\n ) : null}\n </span>\n {children}\n </div>\n );\n}\n\nexport interface DropdownMenuLabelProps extends React.ComponentProps<\"div\"> {\n inset?: boolean;\n}\n\nexport function DropdownMenuLabel({ className, inset, ...props }: DropdownMenuLabelProps) {\n return (\n <div\n data-slot=\"dropdown-menu-label\"\n data-inset={inset ? \"\" : undefined}\n className={cn(DROPDOWN_MENU_LABEL, className)}\n {...props}\n />\n );\n}\n\nexport function DropdownMenuSeparator({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dropdown-menu-separator\"\n role=\"separator\"\n className={cn(DROPDOWN_MENU_SEPARATOR, className)}\n {...props}\n />\n );\n}\n\nexport function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn(DROPDOWN_MENU_SHORTCUT, className)}\n {...props}\n />\n );\n}\n\n// Sub-menus render inline (nested) rather than in a separate floating layer: the\n// sub-content is revealed in place when its trigger toggles, simplifying the\n// nesting Radix portals each level. data-state still reflects open/closed.\ninterface DropdownMenuSubContextValue {\n open: boolean;\n setOpen: (next: boolean) => void;\n}\n\nconst DropdownMenuSubContext = React.createContext<DropdownMenuSubContextValue | null>(null);\n\nexport interface DropdownMenuSubProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n children?: React.ReactNode;\n}\n\nexport function DropdownMenuSub({ open, defaultOpen = false, onOpenChange, children }: DropdownMenuSubProps) {\n const [isOpen, setOpen] = useControllableState<boolean>({\n ...(open !== undefined ? { value: open } : {}),\n defaultValue: defaultOpen,\n ...(onOpenChange ? { onChange: onOpenChange } : {}),\n });\n return (\n <DropdownMenuSubContext.Provider value={{ open: isOpen, setOpen }}>\n <div data-slot=\"dropdown-menu-sub\">{children}</div>\n </DropdownMenuSubContext.Provider>\n );\n}\n\nexport interface DropdownMenuSubTriggerProps extends React.ComponentProps<\"div\"> {\n inset?: boolean;\n}\n\nexport function DropdownMenuSubTrigger({ className, inset, children, onClick, ...props }: DropdownMenuSubTriggerProps) {\n const ctx = React.useContext(DropdownMenuSubContext);\n return (\n <div\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset ? \"\" : undefined}\n data-state={ctx?.open ? \"open\" : \"closed\"}\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded={ctx?.open}\n tabIndex={-1}\n className={cn(\n DROPDOWN_MENU_SUB_TRIGGER,\n className,\n )}\n onClick={(e) => {\n onClick?.(e);\n ctx?.setOpen(!ctx.open);\n }}\n {...props}\n >\n {children}\n <svg className=\"ml-auto size-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </div>\n );\n}\n\nexport function DropdownMenuSubContent({ className, children, ...props }: React.ComponentProps<\"div\">) {\n const ctx = React.useContext(DropdownMenuSubContext);\n if (!ctx?.open) return null;\n return (\n <div\n data-slot=\"dropdown-menu-sub-content\"\n data-state=\"open\"\n role=\"menu\"\n className={cn(\n DROPDOWN_MENU_SUB_CONTENT,\n className,\n )}\n {...props}\n >\n {children}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/dropdown-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useControllableState } from \"../primitives/use-controllable-state\";\nimport { useFloating } from \"../primitives/use-floating\";\nimport { DismissableLayerScope, useDismissableLayer } from \"../primitives/dismissable-layer\";\nimport { usePresence } from \"../primitives/presence\";\nimport { useRovingFocus } from \"../primitives/use-roving-focus\";\nimport { mergeRefs } from \"../primitives/merge-refs\";\nimport { Portal } from \"../primitives/portal\";\nimport { Slot } from \"../primitives/slot\";\nimport {\n DROPDOWN_MENU_CHECK_ITEM,\n DROPDOWN_MENU_CONTENT,\n DROPDOWN_MENU_ITEM,\n DROPDOWN_MENU_ITEM_INDICATOR,\n DROPDOWN_MENU_LABEL,\n DROPDOWN_MENU_SEPARATOR,\n DROPDOWN_MENU_SHORTCUT,\n DROPDOWN_MENU_SUB_CONTENT,\n DROPDOWN_MENU_SUB_TRIGGER,\n} from \"../generated/dropdown-menu\";\n\ninterface DropdownMenuContextValue {\n open: boolean;\n setOpen: (next: boolean) => void;\n anchorRef: React.RefObject<HTMLElement | null>;\n}\n\nconst DropdownMenuContext = React.createContext<DropdownMenuContextValue | null>(\n null,\n);\n\nfunction useDropdownMenu(): DropdownMenuContextValue {\n const ctx = React.useContext(DropdownMenuContext);\n if (!ctx) throw new Error(\"DropdownMenu parts must be used within <DropdownMenu>\");\n return ctx;\n}\n\nexport interface DropdownMenuProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n children?: React.ReactNode;\n}\n\nexport function DropdownMenu({ open, defaultOpen = false, onOpenChange, children }: DropdownMenuProps) {\n const [isOpen, setOpen] = useControllableState<boolean>({\n ...(open !== undefined ? { value: open } : {}),\n defaultValue: defaultOpen,\n ...(onOpenChange ? { onChange: onOpenChange } : {}),\n });\n const anchorRef = React.useRef<HTMLElement | null>(null);\n return (\n <DropdownMenuContext.Provider value={{ open: isOpen, setOpen, anchorRef }}>\n <div data-slot=\"dropdown-menu\">{children}</div>\n </DropdownMenuContext.Provider>\n );\n}\n\nexport function DropdownMenuPortal({ children }: { children?: React.ReactNode }) {\n return <Portal>{children}</Portal>;\n}\n\nexport interface DropdownMenuTriggerProps extends React.ComponentProps<\"button\"> {\n asChild?: boolean;\n}\n\nexport function DropdownMenuTrigger({ asChild = false, onClick, ...props }: DropdownMenuTriggerProps) {\n const { open, setOpen, anchorRef } = useDropdownMenu();\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n data-slot=\"dropdown-menu-trigger\"\n aria-haspopup=\"menu\"\n aria-expanded={open}\n data-state={open ? \"open\" : \"closed\"}\n ref={anchorRef as React.Ref<HTMLButtonElement>}\n onClick={(e: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(e);\n setOpen(!open);\n }}\n {...(props as Record<string, unknown>)}\n />\n );\n}\n\nexport interface DropdownMenuContentProps extends React.ComponentProps<\"div\"> {\n sideOffset?: number;\n align?: \"start\" | \"center\" | \"end\";\n}\n\nexport function DropdownMenuContent({\n className,\n sideOffset = 4,\n align = \"start\",\n children,\n ...props\n}: DropdownMenuContentProps) {\n const { open, setOpen, anchorRef } = useDropdownMenu();\n const { isPresent, ref: presRef } = usePresence(open);\n const { floatingRef, style, side } = useFloating({\n anchorRef,\n open,\n side: \"bottom\",\n align,\n offset: sideOffset,\n });\n const dismissRef = useDismissableLayer({\n enabled: open,\n onDismiss: () => setOpen(false),\n exclude: [anchorRef],\n });\n const contentRef = React.useRef<HTMLDivElement | null>(null);\n // Roving focus across rendered menu items: ArrowUp/Down move the active item.\n const items = () =>\n Array.from(\n contentRef.current?.querySelectorAll<HTMLElement>(\"[role^='menuitem']\") ?? [],\n ).filter((el) => el.getAttribute(\"data-disabled\") === null);\n const { activeIndex, setActiveIndex, onKeyDown: rovingKeyDown } = useRovingFocus({\n count: () => items().length,\n orientation: \"vertical\",\n loop: true,\n });\n // Reset on close: a menu reopens on its first item, and an index left past\n // the end (items gone while closed) would focus nothing.\n React.useEffect(() => {\n if (!open) setActiveIndex(0);\n }, [open, setActiveIndex]);\n React.useEffect(() => {\n if (!open) return;\n items()[activeIndex]?.focus();\n }, [open, activeIndex]);\n // Selecting an item closes the menu: items call this through context.\n const close = React.useCallback(() => setOpen(false), [setOpen]);\n if (!isPresent) return null;\n return (\n <Portal>\n <DropdownMenuCloseContext.Provider value={close}>\n <div\n data-slot=\"dropdown-menu-content\"\n data-state={open ? \"open\" : \"closed\"}\n data-side={side}\n role=\"menu\"\n tabIndex={-1}\n // Escape is the stack's (useDismissableLayer): it closes this menu\n // only while it is the top layer.\n onKeyDown={rovingKeyDown}\n ref={mergeRefs(floatingRef, dismissRef, presRef, contentRef)}\n style={style}\n className={cn(\n DROPDOWN_MENU_CONTENT,\n className,\n )}\n {...(props as Record<string, unknown>)}\n >\n <DismissableLayerScope layer={dismissRef}>{children}</DismissableLayerScope>\n </div>\n </DropdownMenuCloseContext.Provider>\n </Portal>\n );\n}\n\nconst DropdownMenuCloseContext = React.createContext<() => void>(() => {});\n\nexport function DropdownMenuGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div data-slot=\"dropdown-menu-group\" role=\"group\" className={className} {...props} />;\n}\n\nexport interface DropdownMenuItemProps extends React.ComponentProps<\"div\"> {\n /** Render the child (a link) as the item. */\n asChild?: boolean;\n inset?: boolean;\n variant?: \"neutral\" | \"destructive\";\n disabled?: boolean;\n}\n\nexport function DropdownMenuItem({\n asChild = false,\n className,\n inset,\n variant = \"neutral\",\n disabled,\n onClick,\n onKeyDown,\n ...props\n}: DropdownMenuItemProps) {\n const close = React.useContext(DropdownMenuCloseContext);\n const Comp = asChild ? Slot : \"div\";\n return (\n <Comp\n data-slot=\"dropdown-menu-item\"\n data-inset={inset ? \"\" : undefined}\n data-variant={variant}\n data-disabled={disabled ? \"\" : undefined}\n role=\"menuitem\"\n tabIndex={disabled ? undefined : -1}\n className={cn(\n DROPDOWN_MENU_ITEM,\n className,\n )}\n onClick={(e) => {\n if (disabled) return;\n onClick?.(e);\n close();\n }}\n onKeyDown={(e) => {\n onKeyDown?.(e);\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n (e.currentTarget as HTMLElement).click();\n }\n }}\n {...props}\n />\n );\n}\n\nexport interface DropdownMenuCheckboxItemProps extends React.ComponentProps<\"div\"> {\n checked?: boolean;\n disabled?: boolean;\n}\n\nexport function DropdownMenuCheckboxItem({\n className,\n children,\n checked,\n disabled,\n onClick,\n ...props\n}: DropdownMenuCheckboxItemProps) {\n const close = React.useContext(DropdownMenuCloseContext);\n return (\n <div\n data-slot=\"dropdown-menu-checkbox-item\"\n role=\"menuitemcheckbox\"\n aria-checked={checked}\n data-state={checked ? \"checked\" : \"unchecked\"}\n data-disabled={disabled ? \"\" : undefined}\n tabIndex={disabled ? undefined : -1}\n className={cn(\n DROPDOWN_MENU_CHECK_ITEM,\n className,\n )}\n onClick={(e) => {\n if (disabled) return;\n onClick?.(e);\n close();\n }}\n {...props}\n >\n <span className={DROPDOWN_MENU_ITEM_INDICATOR}>\n {checked ? (\n <svg className=\"size-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n ) : null}\n </span>\n {children}\n </div>\n );\n}\n\ninterface DropdownMenuRadioGroupContextValue {\n value: string | undefined;\n setValue: (next: string) => void;\n}\n\nconst DropdownMenuRadioGroupContext =\n React.createContext<DropdownMenuRadioGroupContextValue | null>(null);\n\nexport interface DropdownMenuRadioGroupProps extends Omit<React.ComponentProps<\"div\">, \"onChange\"> {\n value?: string;\n onValueChange?: (value: string) => void;\n}\n\nexport function DropdownMenuRadioGroup({\n className,\n value,\n onValueChange,\n children,\n ...props\n}: DropdownMenuRadioGroupProps) {\n const ctx = React.useMemo<DropdownMenuRadioGroupContextValue>(\n () => ({ value, setValue: (next) => onValueChange?.(next) }),\n [value, onValueChange],\n );\n return (\n <DropdownMenuRadioGroupContext.Provider value={ctx}>\n <div data-slot=\"dropdown-menu-radio-group\" role=\"group\" className={className} {...props}>\n {children}\n </div>\n </DropdownMenuRadioGroupContext.Provider>\n );\n}\n\nexport interface DropdownMenuRadioItemProps extends React.ComponentProps<\"div\"> {\n value: string;\n disabled?: boolean;\n}\n\nexport function DropdownMenuRadioItem({\n className,\n children,\n value,\n disabled,\n onClick,\n ...props\n}: DropdownMenuRadioItemProps) {\n const close = React.useContext(DropdownMenuCloseContext);\n const group = React.useContext(DropdownMenuRadioGroupContext);\n const checked = group?.value === value;\n return (\n <div\n data-slot=\"dropdown-menu-radio-item\"\n role=\"menuitemradio\"\n aria-checked={checked}\n data-state={checked ? \"checked\" : \"unchecked\"}\n data-disabled={disabled ? \"\" : undefined}\n tabIndex={disabled ? undefined : -1}\n className={cn(\n DROPDOWN_MENU_CHECK_ITEM,\n className,\n )}\n onClick={(e) => {\n if (disabled) return;\n onClick?.(e);\n group?.setValue(value);\n close();\n }}\n {...props}\n >\n <span className={DROPDOWN_MENU_ITEM_INDICATOR}>\n {checked ? (\n <svg className=\"size-2 fill-current\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n </svg>\n ) : null}\n </span>\n {children}\n </div>\n );\n}\n\nexport interface DropdownMenuLabelProps extends React.ComponentProps<\"div\"> {\n inset?: boolean;\n}\n\nexport function DropdownMenuLabel({ className, inset, ...props }: DropdownMenuLabelProps) {\n return (\n <div\n data-slot=\"dropdown-menu-label\"\n data-inset={inset ? \"\" : undefined}\n className={cn(DROPDOWN_MENU_LABEL, className)}\n {...props}\n />\n );\n}\n\nexport function DropdownMenuSeparator({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dropdown-menu-separator\"\n role=\"separator\"\n className={cn(DROPDOWN_MENU_SEPARATOR, className)}\n {...props}\n />\n );\n}\n\nexport function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn(DROPDOWN_MENU_SHORTCUT, className)}\n {...props}\n />\n );\n}\n\n// Sub-menus render inline (nested) rather than in a separate floating layer: the\n// sub-content is revealed in place when its trigger toggles, simplifying the\n// nesting Radix portals each level. data-state still reflects open/closed.\ninterface DropdownMenuSubContextValue {\n open: boolean;\n setOpen: (next: boolean) => void;\n}\n\nconst DropdownMenuSubContext = React.createContext<DropdownMenuSubContextValue | null>(null);\n\nexport interface DropdownMenuSubProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n children?: React.ReactNode;\n}\n\nexport function DropdownMenuSub({ open, defaultOpen = false, onOpenChange, children }: DropdownMenuSubProps) {\n const [isOpen, setOpen] = useControllableState<boolean>({\n ...(open !== undefined ? { value: open } : {}),\n defaultValue: defaultOpen,\n ...(onOpenChange ? { onChange: onOpenChange } : {}),\n });\n return (\n <DropdownMenuSubContext.Provider value={{ open: isOpen, setOpen }}>\n <div data-slot=\"dropdown-menu-sub\">{children}</div>\n </DropdownMenuSubContext.Provider>\n );\n}\n\nexport interface DropdownMenuSubTriggerProps extends React.ComponentProps<\"div\"> {\n inset?: boolean;\n}\n\nexport function DropdownMenuSubTrigger({ className, inset, children, onClick, ...props }: DropdownMenuSubTriggerProps) {\n const ctx = React.useContext(DropdownMenuSubContext);\n return (\n <div\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset ? \"\" : undefined}\n data-state={ctx?.open ? \"open\" : \"closed\"}\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded={ctx?.open}\n tabIndex={-1}\n className={cn(\n DROPDOWN_MENU_SUB_TRIGGER,\n className,\n )}\n onClick={(e) => {\n onClick?.(e);\n ctx?.setOpen(!ctx.open);\n }}\n {...props}\n >\n {children}\n <svg className=\"ml-auto size-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </div>\n );\n}\n\nexport function DropdownMenuSubContent({ className, children, ...props }: React.ComponentProps<\"div\">) {\n const ctx = React.useContext(DropdownMenuSubContext);\n if (!ctx?.open) return null;\n return (\n <div\n data-slot=\"dropdown-menu-sub-content\"\n data-state=\"open\"\n role=\"menu\"\n className={cn(\n DROPDOWN_MENU_SUB_CONTENT,\n className,\n )}\n {...props}\n >\n {children}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -4,7 +4,7 @@ import * as React from "react";
4
4
  import { cn } from "../lib/cn.js";
5
5
  import { useControllableState } from "../primitives/use-controllable-state.js";
6
6
  import { useFloating } from "../primitives/use-floating.js";
7
- import { useDismissableLayer } from "../primitives/dismissable-layer.js";
7
+ import { DismissableLayerScope, useDismissableLayer } from "../primitives/dismissable-layer.js";
8
8
  import { usePresence } from "../primitives/presence.js";
9
9
  import { useHoverIntent } from "../primitives/use-hover-intent.js";
10
10
  import { mergeRefs } from "../primitives/merge-refs.js";
@@ -149,7 +149,7 @@ function InfoTipContent({
149
149
  style,
150
150
  className: cn(POPOVER_CONTENT, "w-64 p-3 text-sm", className),
151
151
  ...props,
152
- children
152
+ children: /* @__PURE__ */ jsx(DismissableLayerScope, { layer: dismissRef, children })
153
153
  }
154
154
  ) });
155
155
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/info-tip.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useControllableState } from \"../primitives/use-controllable-state\";\nimport { useFloating } from \"../primitives/use-floating\";\nimport { useDismissableLayer } from \"../primitives/dismissable-layer\";\nimport { usePresence } from \"../primitives/presence\";\nimport { useHoverIntent } from \"../primitives/use-hover-intent\";\nimport { mergeRefs } from \"../primitives/merge-refs\";\nimport { Portal } from \"../primitives/portal\";\nimport { Slot } from \"../primitives/slot\";\nimport { POPOVER_CONTENT } from \"../generated/popover\";\n\n/**\n * `InfoTip` — the ⓘ-beside-a-label *toggletip*. It reuses the popover machinery\n * (controllable state + floating + dismissable layer + portal) but deliberately\n * NOT the tooltip ARIA: the trigger is a real `<button aria-expanded aria-controls>`\n * and the bubble is a `role=\"status\"` live region, never `role=\"tooltip\"`. That is\n * the pattern that stays correct across mouse, keyboard and touch (a `role=tooltip`\n * is hover/focus-only and never opens on tap). Hover-with-intent (~0.5s) is layered\n * on as a mouse-only enhancement; click/tap/Enter/Space toggle instantly.\n *\n * The bubble holds plain, non-interactive help text — it does not trap focus and\n * nothing inside it is focusable, so there is no focus to manage or return.\n */\ninterface InfoTipContextValue {\n open: boolean;\n setOpen: (next: boolean) => void;\n anchorRef: React.RefObject<HTMLElement | null>;\n contentId: string;\n}\n\nconst InfoTipContext = React.createContext<InfoTipContextValue | null>(null);\n\nfunction useInfoTip(): InfoTipContextValue {\n const ctx = React.useContext(InfoTipContext);\n if (!ctx) throw new Error(\"InfoTip parts must be used within <InfoTip>\");\n return ctx;\n}\n\nexport interface InfoTipProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n children?: React.ReactNode;\n}\n\nexport function InfoTip({\n open,\n defaultOpen = false,\n onOpenChange,\n children,\n}: InfoTipProps) {\n const [isOpen, setOpen] = useControllableState<boolean>({\n ...(open !== undefined ? { value: open } : {}),\n defaultValue: defaultOpen,\n ...(onOpenChange ? { onChange: onOpenChange } : {}),\n });\n const anchorRef = React.useRef<HTMLElement | null>(null);\n const contentId = React.useId();\n return (\n <InfoTipContext.Provider\n value={{ open: isOpen, setOpen, anchorRef, contentId }}\n >\n {children}\n </InfoTipContext.Provider>\n );\n}\n\n// lucide `info`, inlined per the kit's no-lucide-dep icon convention.\nfunction InfoGlyph({ className }: { className?: string }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n className={cn(\"size-4\", className)}\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4\" />\n <path d=\"M12 8h.01\" />\n </svg>\n );\n}\n\nexport interface InfoTipTriggerProps extends React.ComponentProps<\"button\"> {\n asChild?: boolean;\n /** Accessible name for the icon-only button. */\n label?: string;\n /** Milliseconds the mouse must dwell before the tip opens on hover. */\n hoverDelay?: number;\n}\n\nexport function InfoTipTrigger({\n asChild = false,\n label = \"More information\",\n hoverDelay = 500,\n className,\n onClick,\n onBlur,\n onPointerEnter,\n onPointerLeave,\n children,\n ...props\n}: InfoTipTriggerProps) {\n const { open, setOpen, anchorRef, contentId } = useInfoTip();\n const hover = useHoverIntent({\n onOpen: () => setOpen(true),\n onClose: () => setOpen(false),\n openDelay: hoverDelay,\n });\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n data-slot=\"info-tip-trigger\"\n data-state={open ? \"open\" : \"closed\"}\n type={asChild ? undefined : \"button\"}\n aria-label={label}\n aria-expanded={open}\n aria-controls={contentId}\n ref={anchorRef as React.Ref<never>}\n className={cn(\n \"inline-flex size-4 shrink-0 cursor-help items-center justify-center rounded-full align-middle text-ink-soft outline-none transition-colors hover:text-ink focus-visible:ring-2 focus-visible:ring-ring data-[state=open]:text-accent-debug\",\n className,\n )}\n onClick={(e: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(e);\n setOpen(!open);\n }}\n onBlur={(e: React.FocusEvent<HTMLButtonElement>) => {\n onBlur?.(e);\n setOpen(false);\n }}\n onPointerEnter={(e: React.PointerEvent<HTMLButtonElement>) => {\n onPointerEnter?.(e);\n hover.onPointerEnter(e);\n }}\n onPointerLeave={(e: React.PointerEvent<HTMLButtonElement>) => {\n onPointerLeave?.(e);\n hover.onPointerLeave(e);\n }}\n {...(props as Record<string, unknown>)}\n >\n {children ?? <InfoGlyph />}\n </Comp>\n );\n}\n\nexport interface InfoTipContentProps extends React.ComponentProps<\"div\"> {\n side?: \"top\" | \"right\" | \"bottom\" | \"left\";\n align?: \"start\" | \"center\" | \"end\";\n sideOffset?: number;\n}\n\nexport function InfoTipContent({\n className,\n side: sideProp = \"bottom\",\n align = \"center\",\n sideOffset = 6,\n children,\n ...props\n}: InfoTipContentProps) {\n const { open, setOpen, anchorRef, contentId } = useInfoTip();\n const { isPresent, ref: presRef } = usePresence(open);\n const { floatingRef, style, side } = useFloating({\n anchorRef,\n open,\n side: sideProp,\n align,\n offset: sideOffset,\n });\n const dismissRef = useDismissableLayer({\n enabled: open,\n onDismiss: () => setOpen(false),\n exclude: [anchorRef],\n });\n if (!isPresent) return null;\n return (\n <Portal>\n <div\n id={contentId}\n role=\"status\"\n aria-live=\"polite\"\n data-slot=\"info-tip-content\"\n data-state={open ? \"open\" : \"closed\"}\n data-side={side}\n data-align={align}\n ref={mergeRefs(floatingRef, dismissRef, presRef)}\n style={style}\n className={cn(POPOVER_CONTENT, \"w-64 p-3 text-sm\", className)}\n {...(props as Record<string, unknown>)}\n >\n {children}\n </div>\n </Portal>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/info-tip.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useControllableState } from \"../primitives/use-controllable-state\";\nimport { useFloating } from \"../primitives/use-floating\";\nimport { DismissableLayerScope, useDismissableLayer } from \"../primitives/dismissable-layer\";\nimport { usePresence } from \"../primitives/presence\";\nimport { useHoverIntent } from \"../primitives/use-hover-intent\";\nimport { mergeRefs } from \"../primitives/merge-refs\";\nimport { Portal } from \"../primitives/portal\";\nimport { Slot } from \"../primitives/slot\";\nimport { POPOVER_CONTENT } from \"../generated/popover\";\n\n/**\n * `InfoTip` — the ⓘ-beside-a-label *toggletip*. It reuses the popover machinery\n * (controllable state + floating + dismissable layer + portal) but deliberately\n * NOT the tooltip ARIA: the trigger is a real `<button aria-expanded aria-controls>`\n * and the bubble is a `role=\"status\"` live region, never `role=\"tooltip\"`. That is\n * the pattern that stays correct across mouse, keyboard and touch (a `role=tooltip`\n * is hover/focus-only and never opens on tap). Hover-with-intent (~0.5s) is layered\n * on as a mouse-only enhancement; click/tap/Enter/Space toggle instantly.\n *\n * The bubble holds plain, non-interactive help text — it does not trap focus and\n * nothing inside it is focusable, so there is no focus to manage or return.\n */\ninterface InfoTipContextValue {\n open: boolean;\n setOpen: (next: boolean) => void;\n anchorRef: React.RefObject<HTMLElement | null>;\n contentId: string;\n}\n\nconst InfoTipContext = React.createContext<InfoTipContextValue | null>(null);\n\nfunction useInfoTip(): InfoTipContextValue {\n const ctx = React.useContext(InfoTipContext);\n if (!ctx) throw new Error(\"InfoTip parts must be used within <InfoTip>\");\n return ctx;\n}\n\nexport interface InfoTipProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n children?: React.ReactNode;\n}\n\nexport function InfoTip({\n open,\n defaultOpen = false,\n onOpenChange,\n children,\n}: InfoTipProps) {\n const [isOpen, setOpen] = useControllableState<boolean>({\n ...(open !== undefined ? { value: open } : {}),\n defaultValue: defaultOpen,\n ...(onOpenChange ? { onChange: onOpenChange } : {}),\n });\n const anchorRef = React.useRef<HTMLElement | null>(null);\n const contentId = React.useId();\n return (\n <InfoTipContext.Provider\n value={{ open: isOpen, setOpen, anchorRef, contentId }}\n >\n {children}\n </InfoTipContext.Provider>\n );\n}\n\n// lucide `info`, inlined per the kit's no-lucide-dep icon convention.\nfunction InfoGlyph({ className }: { className?: string }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n className={cn(\"size-4\", className)}\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4\" />\n <path d=\"M12 8h.01\" />\n </svg>\n );\n}\n\nexport interface InfoTipTriggerProps extends React.ComponentProps<\"button\"> {\n asChild?: boolean;\n /** Accessible name for the icon-only button. */\n label?: string;\n /** Milliseconds the mouse must dwell before the tip opens on hover. */\n hoverDelay?: number;\n}\n\nexport function InfoTipTrigger({\n asChild = false,\n label = \"More information\",\n hoverDelay = 500,\n className,\n onClick,\n onBlur,\n onPointerEnter,\n onPointerLeave,\n children,\n ...props\n}: InfoTipTriggerProps) {\n const { open, setOpen, anchorRef, contentId } = useInfoTip();\n const hover = useHoverIntent({\n onOpen: () => setOpen(true),\n onClose: () => setOpen(false),\n openDelay: hoverDelay,\n });\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n data-slot=\"info-tip-trigger\"\n data-state={open ? \"open\" : \"closed\"}\n type={asChild ? undefined : \"button\"}\n aria-label={label}\n aria-expanded={open}\n aria-controls={contentId}\n ref={anchorRef as React.Ref<never>}\n className={cn(\n \"inline-flex size-4 shrink-0 cursor-help items-center justify-center rounded-full align-middle text-ink-soft outline-none transition-colors hover:text-ink focus-visible:ring-2 focus-visible:ring-ring data-[state=open]:text-accent-debug\",\n className,\n )}\n onClick={(e: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(e);\n setOpen(!open);\n }}\n onBlur={(e: React.FocusEvent<HTMLButtonElement>) => {\n onBlur?.(e);\n setOpen(false);\n }}\n onPointerEnter={(e: React.PointerEvent<HTMLButtonElement>) => {\n onPointerEnter?.(e);\n hover.onPointerEnter(e);\n }}\n onPointerLeave={(e: React.PointerEvent<HTMLButtonElement>) => {\n onPointerLeave?.(e);\n hover.onPointerLeave(e);\n }}\n {...(props as Record<string, unknown>)}\n >\n {children ?? <InfoGlyph />}\n </Comp>\n );\n}\n\nexport interface InfoTipContentProps extends React.ComponentProps<\"div\"> {\n side?: \"top\" | \"right\" | \"bottom\" | \"left\";\n align?: \"start\" | \"center\" | \"end\";\n sideOffset?: number;\n}\n\nexport function InfoTipContent({\n className,\n side: sideProp = \"bottom\",\n align = \"center\",\n sideOffset = 6,\n children,\n ...props\n}: InfoTipContentProps) {\n const { open, setOpen, anchorRef, contentId } = useInfoTip();\n const { isPresent, ref: presRef } = usePresence(open);\n const { floatingRef, style, side } = useFloating({\n anchorRef,\n open,\n side: sideProp,\n align,\n offset: sideOffset,\n });\n const dismissRef = useDismissableLayer({\n enabled: open,\n onDismiss: () => setOpen(false),\n exclude: [anchorRef],\n });\n if (!isPresent) return null;\n return (\n <Portal>\n <div\n id={contentId}\n role=\"status\"\n aria-live=\"polite\"\n data-slot=\"info-tip-content\"\n data-state={open ? \"open\" : \"closed\"}\n data-side={side}\n data-align={align}\n ref={mergeRefs(floatingRef, dismissRef, presRef)}\n style={style}\n className={cn(POPOVER_CONTENT, \"w-64 p-3 text-sm\", className)}\n {...(props as Record<string, unknown>)}\n >\n <DismissableLayerScope layer={dismissRef}>{children}</DismissableLayerScope>\n </div>\n </Portal>\n );\n}\n"],"mappings":"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","names":[]}
@@ -5,7 +5,7 @@ import { cn } from "../lib/cn.js";
5
5
  import { useControllableState } from "../primitives/use-controllable-state.js";
6
6
  import { Portal } from "../primitives/portal.js";
7
7
  import { useFloating } from "../primitives/use-floating.js";
8
- import { useDismissableLayer } from "../primitives/dismissable-layer.js";
8
+ import { DismissableLayerScope, useDismissableLayer } from "../primitives/dismissable-layer.js";
9
9
  import { usePresence } from "../primitives/presence.js";
10
10
  import { useRovingFocus } from "../primitives/use-roving-focus.js";
11
11
  import { mergeRefs } from "../primitives/merge-refs.js";
@@ -88,13 +88,26 @@ function MenubarContent({
88
88
  onDismiss: () => setOpen(false),
89
89
  exclude: [triggerRef]
90
90
  });
91
- const items = React.Children.toArray(children);
92
- const { onKeyDown } = useRovingFocus({ count: items.length, orientation: "vertical" });
91
+ const contentRef = React.useRef(null);
92
+ const items = () => Array.from(
93
+ contentRef.current?.querySelectorAll("[role^='menuitem']") ?? []
94
+ ).filter((el) => el.getAttribute("data-disabled") === null);
95
+ const { activeIndex, setActiveIndex, onKeyDown } = useRovingFocus({
96
+ count: () => items().length,
97
+ orientation: "vertical"
98
+ });
99
+ React.useEffect(() => {
100
+ if (!open) setActiveIndex(0);
101
+ }, [open, setActiveIndex]);
102
+ React.useEffect(() => {
103
+ if (!open) return;
104
+ items()[activeIndex]?.focus();
105
+ }, [open, activeIndex]);
93
106
  if (!isPresent) return null;
94
107
  return /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(
95
108
  "div",
96
109
  {
97
- ref: mergeRefs(presenceRef, floatingRef, dismissRef),
110
+ ref: mergeRefs(presenceRef, floatingRef, dismissRef, contentRef),
98
111
  "data-slot": "menubar-content",
99
112
  "data-state": open ? "open" : "closed",
100
113
  "data-side": side,
@@ -103,7 +116,7 @@ function MenubarContent({
103
116
  className: cn(MENUBAR_CONTENT, className),
104
117
  onKeyDown,
105
118
  ...props,
106
- children
119
+ children: /* @__PURE__ */ jsx(DismissableLayerScope, { layer: dismissRef, children })
107
120
  }
108
121
  ) });
109
122
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/menubar.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useControllableState } from \"../primitives/use-controllable-state\";\nimport { Portal } from \"../primitives/portal\";\nimport { useFloating } from \"../primitives/use-floating\";\nimport { useDismissableLayer } from \"../primitives/dismissable-layer\";\nimport { usePresence } from \"../primitives/presence\";\nimport { useRovingFocus } from \"../primitives/use-roving-focus\";\nimport { mergeRefs } from \"../primitives/merge-refs\";\nimport {\n MENUBAR_CHECKBOX_ITEM,\n MENUBAR_CONTENT,\n MENUBAR_ITEM,\n MENUBAR_ITEM_INDICATOR,\n MENUBAR_LABEL,\n MENUBAR_RADIO_ITEM,\n MENUBAR_ROOT,\n MENUBAR_SEPARATOR,\n MENUBAR_SHORTCUT,\n MENUBAR_SUB_CONTENT,\n MENUBAR_SUB_TRIGGER,\n MENUBAR_TRIGGER,\n} from \"../generated/menubar\";\n\ninterface MenuCtx {\n open: boolean;\n setOpen: (open: boolean) => void;\n triggerRef: React.RefObject<HTMLButtonElement | null>;\n}\nconst MenubarMenuContext = React.createContext<MenuCtx | null>(null);\nfunction useMenu(): MenuCtx {\n const ctx = React.useContext(MenubarMenuContext);\n if (!ctx) throw new Error(\"Menubar parts must be used within <MenubarMenu>\");\n return ctx;\n}\n\nconst MenubarRadioGroupContext = React.createContext<{\n value: string;\n onValueChange: (value: string) => void;\n} | null>(null);\n\nexport function Menubar({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"menubar\"\n role=\"menubar\"\n className={cn(MENUBAR_ROOT, className)}\n {...props}\n />\n );\n}\n\nexport interface MenubarMenuProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n children?: React.ReactNode;\n}\n\nexport function MenubarMenu({ open, defaultOpen = false, onOpenChange, children }: MenubarMenuProps) {\n const [isOpen, setOpen] = useControllableState({\n value: open,\n defaultValue: defaultOpen,\n onChange: onOpenChange,\n });\n const triggerRef = React.useRef<HTMLButtonElement | null>(null);\n return (\n <MenubarMenuContext.Provider value={{ open: isOpen, setOpen, triggerRef }}>\n <div data-slot=\"menubar-menu\" className=\"relative\">\n {children}\n </div>\n </MenubarMenuContext.Provider>\n );\n}\n\nexport function MenubarTrigger({ className, onClick, ...props }: React.ComponentProps<\"button\">) {\n const { open, setOpen, triggerRef } = useMenu();\n return (\n <button\n ref={triggerRef}\n type=\"button\"\n data-slot=\"menubar-trigger\"\n data-state={open ? \"open\" : \"closed\"}\n className={cn(MENUBAR_TRIGGER, className)}\n onClick={(e) => {\n onClick?.(e);\n setOpen(!open);\n }}\n {...props}\n />\n );\n}\n\nexport function MenubarContent({\n className,\n children,\n align = \"start\",\n ...props\n}: React.ComponentProps<\"div\"> & { align?: \"start\" | \"center\" | \"end\" }) {\n const { open, setOpen, triggerRef } = useMenu();\n const { isPresent, ref: presenceRef } = usePresence(open);\n const { floatingRef, style, side } = useFloating({\n anchorRef: triggerRef,\n open,\n side: \"bottom\",\n align,\n offset: 8,\n });\n const dismissRef = useDismissableLayer({\n enabled: open,\n onDismiss: () => setOpen(false),\n exclude: [triggerRef],\n });\n\n const items = React.Children.toArray(children);\n const { onKeyDown } = useRovingFocus({ count: items.length, orientation: \"vertical\" });\n\n if (!isPresent) return null;\n return (\n <Portal>\n <div\n ref={mergeRefs(presenceRef, floatingRef, dismissRef)}\n data-slot=\"menubar-content\"\n data-state={open ? \"open\" : \"closed\"}\n data-side={side}\n role=\"menu\"\n style={style}\n className={cn(MENUBAR_CONTENT, className)}\n onKeyDown={onKeyDown}\n {...props}\n >\n {children}\n </div>\n </Portal>\n );\n}\n\nexport function MenubarGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div data-slot=\"menubar-group\" role=\"group\" className={className} {...props} />;\n}\n\nexport function MenubarItem({\n className,\n inset,\n variant = \"neutral\",\n ...props\n}: React.ComponentProps<\"div\"> & {\n inset?: boolean;\n variant?: \"neutral\" | \"destructive\";\n}) {\n return (\n <div\n data-slot=\"menubar-item\"\n data-inset={inset}\n data-variant={variant}\n role=\"menuitem\"\n tabIndex={-1}\n className={cn(MENUBAR_ITEM, className)}\n {...props}\n />\n );\n}\n\nexport function MenubarCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: React.ComponentProps<\"div\"> & { checked?: boolean }) {\n return (\n <div\n data-slot=\"menubar-checkbox-item\"\n role=\"menuitemcheckbox\"\n aria-checked={checked}\n tabIndex={-1}\n className={cn(MENUBAR_CHECKBOX_ITEM, className)}\n {...props}\n >\n <span className={MENUBAR_ITEM_INDICATOR}>\n {checked && (\n <svg\n className=\"size-4\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n )}\n </span>\n {children}\n </div>\n );\n}\n\nexport interface MenubarRadioGroupProps {\n value?: string;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n className?: string;\n children?: React.ReactNode;\n}\n\nexport function MenubarRadioGroup({\n value,\n defaultValue = \"\",\n onValueChange,\n className,\n children,\n}: MenubarRadioGroupProps) {\n const [current, setValue] = useControllableState({\n value,\n defaultValue,\n onChange: onValueChange,\n });\n return (\n <MenubarRadioGroupContext.Provider value={{ value: current, onValueChange: setValue }}>\n <div data-slot=\"menubar-radio-group\" role=\"group\" className={className}>\n {children}\n </div>\n </MenubarRadioGroupContext.Provider>\n );\n}\n\nexport function MenubarRadioItem({\n className,\n children,\n value,\n ...props\n}: React.ComponentProps<\"div\"> & { value: string }) {\n const ctx = React.useContext(MenubarRadioGroupContext);\n const checked = ctx?.value === value;\n return (\n <div\n data-slot=\"menubar-radio-item\"\n role=\"menuitemradio\"\n aria-checked={checked}\n tabIndex={-1}\n className={cn(MENUBAR_RADIO_ITEM, className)}\n onClick={() => ctx?.onValueChange(value)}\n {...props}\n >\n <span className={MENUBAR_ITEM_INDICATOR}>\n {checked && (\n <svg className=\"size-2 fill-current\" viewBox=\"0 0 24 24\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n </svg>\n )}\n </span>\n {children}\n </div>\n );\n}\n\nexport function MenubarLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<\"div\"> & { inset?: boolean }) {\n return (\n <div\n data-slot=\"menubar-label\"\n data-inset={inset}\n className={cn(MENUBAR_LABEL, className)}\n {...props}\n />\n );\n}\n\nexport function MenubarSeparator({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"menubar-separator\"\n role=\"separator\"\n className={cn(MENUBAR_SEPARATOR, className)}\n {...props}\n />\n );\n}\n\nexport function MenubarShortcut({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"menubar-shortcut\"\n className={cn(MENUBAR_SHORTCUT, className)}\n {...props}\n />\n );\n}\n\ninterface SubCtx {\n open: boolean;\n setOpen: (open: boolean) => void;\n}\nconst MenubarSubContext = React.createContext<SubCtx | null>(null);\nfunction useSub(): SubCtx {\n const ctx = React.useContext(MenubarSubContext);\n if (!ctx) throw new Error(\"MenubarSub parts must be used within <MenubarSub>\");\n return ctx;\n}\n\nexport interface MenubarSubProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n children?: React.ReactNode;\n}\n\nexport function MenubarSub({ open, defaultOpen = false, onOpenChange, children }: MenubarSubProps) {\n const [isOpen, setOpen] = useControllableState({\n value: open,\n defaultValue: defaultOpen,\n onChange: onOpenChange,\n });\n return (\n <MenubarSubContext.Provider value={{ open: isOpen, setOpen }}>\n <div data-slot=\"menubar-sub\" className=\"relative\">\n {children}\n </div>\n </MenubarSubContext.Provider>\n );\n}\n\nexport function MenubarSubTrigger({\n className,\n inset,\n children,\n onClick,\n ...props\n}: React.ComponentProps<\"div\"> & { inset?: boolean }) {\n const { open, setOpen } = useSub();\n return (\n <div\n data-slot=\"menubar-sub-trigger\"\n data-inset={inset}\n data-state={open ? \"open\" : \"closed\"}\n role=\"menuitem\"\n tabIndex={-1}\n className={cn(MENUBAR_SUB_TRIGGER, className)}\n onClick={(e) => {\n onClick?.(e);\n setOpen(!open);\n }}\n {...props}\n >\n {children}\n <svg\n className=\"ml-auto h-4 w-4\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </div>\n );\n}\n\nexport function MenubarSubContent({ className, children, ...props }: React.ComponentProps<\"div\">) {\n const { open } = useSub();\n const { isPresent, ref } = usePresence(open);\n if (!isPresent) return null;\n return (\n <div\n ref={ref as React.RefObject<HTMLDivElement>}\n data-slot=\"menubar-sub-content\"\n data-state={open ? \"open\" : \"closed\"}\n role=\"menu\"\n className={cn(MENUBAR_SUB_CONTENT, className)}\n {...props}\n >\n {children}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/menubar.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useControllableState } from \"../primitives/use-controllable-state\";\nimport { Portal } from \"../primitives/portal\";\nimport { useFloating } from \"../primitives/use-floating\";\nimport { DismissableLayerScope, useDismissableLayer } from \"../primitives/dismissable-layer\";\nimport { usePresence } from \"../primitives/presence\";\nimport { useRovingFocus } from \"../primitives/use-roving-focus\";\nimport { mergeRefs } from \"../primitives/merge-refs\";\nimport {\n MENUBAR_CHECKBOX_ITEM,\n MENUBAR_CONTENT,\n MENUBAR_ITEM,\n MENUBAR_ITEM_INDICATOR,\n MENUBAR_LABEL,\n MENUBAR_RADIO_ITEM,\n MENUBAR_ROOT,\n MENUBAR_SEPARATOR,\n MENUBAR_SHORTCUT,\n MENUBAR_SUB_CONTENT,\n MENUBAR_SUB_TRIGGER,\n MENUBAR_TRIGGER,\n} from \"../generated/menubar\";\n\ninterface MenuCtx {\n open: boolean;\n setOpen: (open: boolean) => void;\n triggerRef: React.RefObject<HTMLButtonElement | null>;\n}\nconst MenubarMenuContext = React.createContext<MenuCtx | null>(null);\nfunction useMenu(): MenuCtx {\n const ctx = React.useContext(MenubarMenuContext);\n if (!ctx) throw new Error(\"Menubar parts must be used within <MenubarMenu>\");\n return ctx;\n}\n\nconst MenubarRadioGroupContext = React.createContext<{\n value: string;\n onValueChange: (value: string) => void;\n} | null>(null);\n\nexport function Menubar({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"menubar\"\n role=\"menubar\"\n className={cn(MENUBAR_ROOT, className)}\n {...props}\n />\n );\n}\n\nexport interface MenubarMenuProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n children?: React.ReactNode;\n}\n\nexport function MenubarMenu({ open, defaultOpen = false, onOpenChange, children }: MenubarMenuProps) {\n const [isOpen, setOpen] = useControllableState({\n value: open,\n defaultValue: defaultOpen,\n onChange: onOpenChange,\n });\n const triggerRef = React.useRef<HTMLButtonElement | null>(null);\n return (\n <MenubarMenuContext.Provider value={{ open: isOpen, setOpen, triggerRef }}>\n <div data-slot=\"menubar-menu\" className=\"relative\">\n {children}\n </div>\n </MenubarMenuContext.Provider>\n );\n}\n\nexport function MenubarTrigger({ className, onClick, ...props }: React.ComponentProps<\"button\">) {\n const { open, setOpen, triggerRef } = useMenu();\n return (\n <button\n ref={triggerRef}\n type=\"button\"\n data-slot=\"menubar-trigger\"\n data-state={open ? \"open\" : \"closed\"}\n className={cn(MENUBAR_TRIGGER, className)}\n onClick={(e) => {\n onClick?.(e);\n setOpen(!open);\n }}\n {...props}\n />\n );\n}\n\nexport function MenubarContent({\n className,\n children,\n align = \"start\",\n ...props\n}: React.ComponentProps<\"div\"> & { align?: \"start\" | \"center\" | \"end\" }) {\n const { open, setOpen, triggerRef } = useMenu();\n const { isPresent, ref: presenceRef } = usePresence(open);\n const { floatingRef, style, side } = useFloating({\n anchorRef: triggerRef,\n open,\n side: \"bottom\",\n align,\n offset: 8,\n });\n const dismissRef = useDismissableLayer({\n enabled: open,\n onDismiss: () => setOpen(false),\n exclude: [triggerRef],\n });\n\n // Count the mounted menu items, not the children: separators, labels and\n // groups are children too, and an inline sub-menu adds items when it opens.\n const contentRef = React.useRef<HTMLDivElement | null>(null);\n const items = () =>\n Array.from(\n contentRef.current?.querySelectorAll<HTMLElement>(\"[role^='menuitem']\") ?? [],\n ).filter((el) => el.getAttribute(\"data-disabled\") === null);\n const { activeIndex, setActiveIndex, onKeyDown } = useRovingFocus({\n count: () => items().length,\n orientation: \"vertical\",\n });\n // Reset on close: reopen on the first item, never on an index past the end.\n React.useEffect(() => {\n if (!open) setActiveIndex(0);\n }, [open, setActiveIndex]);\n React.useEffect(() => {\n if (!open) return;\n items()[activeIndex]?.focus();\n }, [open, activeIndex]);\n\n if (!isPresent) return null;\n return (\n <Portal>\n <div\n ref={mergeRefs(presenceRef, floatingRef, dismissRef, contentRef)}\n data-slot=\"menubar-content\"\n data-state={open ? \"open\" : \"closed\"}\n data-side={side}\n role=\"menu\"\n style={style}\n className={cn(MENUBAR_CONTENT, className)}\n onKeyDown={onKeyDown}\n {...props}\n >\n <DismissableLayerScope layer={dismissRef}>{children}</DismissableLayerScope>\n </div>\n </Portal>\n );\n}\n\nexport function MenubarGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div data-slot=\"menubar-group\" role=\"group\" className={className} {...props} />;\n}\n\nexport function MenubarItem({\n className,\n inset,\n variant = \"neutral\",\n ...props\n}: React.ComponentProps<\"div\"> & {\n inset?: boolean;\n variant?: \"neutral\" | \"destructive\";\n}) {\n return (\n <div\n data-slot=\"menubar-item\"\n data-inset={inset}\n data-variant={variant}\n role=\"menuitem\"\n tabIndex={-1}\n className={cn(MENUBAR_ITEM, className)}\n {...props}\n />\n );\n}\n\nexport function MenubarCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: React.ComponentProps<\"div\"> & { checked?: boolean }) {\n return (\n <div\n data-slot=\"menubar-checkbox-item\"\n role=\"menuitemcheckbox\"\n aria-checked={checked}\n tabIndex={-1}\n className={cn(MENUBAR_CHECKBOX_ITEM, className)}\n {...props}\n >\n <span className={MENUBAR_ITEM_INDICATOR}>\n {checked && (\n <svg\n className=\"size-4\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n )}\n </span>\n {children}\n </div>\n );\n}\n\nexport interface MenubarRadioGroupProps {\n value?: string;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n className?: string;\n children?: React.ReactNode;\n}\n\nexport function MenubarRadioGroup({\n value,\n defaultValue = \"\",\n onValueChange,\n className,\n children,\n}: MenubarRadioGroupProps) {\n const [current, setValue] = useControllableState({\n value,\n defaultValue,\n onChange: onValueChange,\n });\n return (\n <MenubarRadioGroupContext.Provider value={{ value: current, onValueChange: setValue }}>\n <div data-slot=\"menubar-radio-group\" role=\"group\" className={className}>\n {children}\n </div>\n </MenubarRadioGroupContext.Provider>\n );\n}\n\nexport function MenubarRadioItem({\n className,\n children,\n value,\n ...props\n}: React.ComponentProps<\"div\"> & { value: string }) {\n const ctx = React.useContext(MenubarRadioGroupContext);\n const checked = ctx?.value === value;\n return (\n <div\n data-slot=\"menubar-radio-item\"\n role=\"menuitemradio\"\n aria-checked={checked}\n tabIndex={-1}\n className={cn(MENUBAR_RADIO_ITEM, className)}\n onClick={() => ctx?.onValueChange(value)}\n {...props}\n >\n <span className={MENUBAR_ITEM_INDICATOR}>\n {checked && (\n <svg className=\"size-2 fill-current\" viewBox=\"0 0 24 24\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n </svg>\n )}\n </span>\n {children}\n </div>\n );\n}\n\nexport function MenubarLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<\"div\"> & { inset?: boolean }) {\n return (\n <div\n data-slot=\"menubar-label\"\n data-inset={inset}\n className={cn(MENUBAR_LABEL, className)}\n {...props}\n />\n );\n}\n\nexport function MenubarSeparator({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"menubar-separator\"\n role=\"separator\"\n className={cn(MENUBAR_SEPARATOR, className)}\n {...props}\n />\n );\n}\n\nexport function MenubarShortcut({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"menubar-shortcut\"\n className={cn(MENUBAR_SHORTCUT, className)}\n {...props}\n />\n );\n}\n\ninterface SubCtx {\n open: boolean;\n setOpen: (open: boolean) => void;\n}\nconst MenubarSubContext = React.createContext<SubCtx | null>(null);\nfunction useSub(): SubCtx {\n const ctx = React.useContext(MenubarSubContext);\n if (!ctx) throw new Error(\"MenubarSub parts must be used within <MenubarSub>\");\n return ctx;\n}\n\nexport interface MenubarSubProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n children?: React.ReactNode;\n}\n\nexport function MenubarSub({ open, defaultOpen = false, onOpenChange, children }: MenubarSubProps) {\n const [isOpen, setOpen] = useControllableState({\n value: open,\n defaultValue: defaultOpen,\n onChange: onOpenChange,\n });\n return (\n <MenubarSubContext.Provider value={{ open: isOpen, setOpen }}>\n <div data-slot=\"menubar-sub\" className=\"relative\">\n {children}\n </div>\n </MenubarSubContext.Provider>\n );\n}\n\nexport function MenubarSubTrigger({\n className,\n inset,\n children,\n onClick,\n ...props\n}: React.ComponentProps<\"div\"> & { inset?: boolean }) {\n const { open, setOpen } = useSub();\n return (\n <div\n data-slot=\"menubar-sub-trigger\"\n data-inset={inset}\n data-state={open ? \"open\" : \"closed\"}\n role=\"menuitem\"\n tabIndex={-1}\n className={cn(MENUBAR_SUB_TRIGGER, className)}\n onClick={(e) => {\n onClick?.(e);\n setOpen(!open);\n }}\n {...props}\n >\n {children}\n <svg\n className=\"ml-auto h-4 w-4\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </div>\n );\n}\n\nexport function MenubarSubContent({ className, children, ...props }: React.ComponentProps<\"div\">) {\n const { open } = useSub();\n const { isPresent, ref } = usePresence(open);\n if (!isPresent) return null;\n return (\n <div\n ref={ref as React.RefObject<HTMLDivElement>}\n data-slot=\"menubar-sub-content\"\n data-state={open ? \"open\" : \"closed\"}\n role=\"menu\"\n className={cn(MENUBAR_SUB_CONTENT, className)}\n {...props}\n >\n {children}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -3,7 +3,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { cn } from "../lib/cn.js";
5
5
  import { useControllableState } from "../primitives/use-controllable-state.js";
6
- import { useDismissableLayer } from "../primitives/dismissable-layer.js";
6
+ import { DismissableLayerScope, useDismissableLayer } from "../primitives/dismissable-layer.js";
7
7
  import { usePresence } from "../primitives/presence.js";
8
8
  import { mergeRefs } from "../primitives/merge-refs.js";
9
9
  import { Slot } from "../primitives/slot.js";
@@ -141,7 +141,7 @@ function NavigationMenuContent({ className, children, ...props }) {
141
141
  className
142
142
  ),
143
143
  ...props,
144
- children
144
+ children: /* @__PURE__ */ jsx(DismissableLayerScope, { layer: dismissRef, children })
145
145
  }
146
146
  );
147
147
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/navigation-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useControllableState } from \"../primitives/use-controllable-state\";\nimport { useDismissableLayer } from \"../primitives/dismissable-layer\";\nimport { usePresence } from \"../primitives/presence\";\nimport { mergeRefs } from \"../primitives/merge-refs\";\nimport { Slot } from \"../primitives/slot\";\nimport {\n NAVIGATION_MENU,\n NAVIGATION_MENU_CONTENT,\n NAVIGATION_MENU_INDICATOR,\n NAVIGATION_MENU_ITEM,\n NAVIGATION_MENU_LINK,\n NAVIGATION_MENU_LIST,\n NAVIGATION_MENU_TRIGGER_STYLE,\n NAVIGATION_MENU_VIEWPORT,\n} from \"../generated/navigation-menu\";\n\n/**\n * Fused canonical trigger class string, the mirror of Rust's\n * `navigation_menu_trigger_style()`. Reuse it to style a plain link the same way\n * a `NavigationMenuTrigger` is styled.\n */\nexport function navigationMenuTriggerStyle(): string {\n return NAVIGATION_MENU_TRIGGER_STYLE;\n}\n\ninterface ItemCtx {\n open: boolean;\n setOpen: (open: boolean) => void;\n triggerRef: React.RefObject<HTMLButtonElement | null>;\n}\nconst NavigationMenuItemContext = React.createContext<ItemCtx | null>(null);\nfunction useItem(): ItemCtx {\n const ctx = React.useContext(NavigationMenuItemContext);\n if (!ctx) throw new Error(\"NavigationMenu parts must be used within <NavigationMenuItem>\");\n return ctx;\n}\n\nexport function NavigationMenu({\n className,\n children,\n viewport = true,\n ...props\n}: React.ComponentProps<\"nav\"> & { viewport?: boolean }) {\n return (\n <nav\n data-slot=\"navigation-menu\"\n data-viewport={viewport}\n role=\"navigation\"\n className={cn(\n NAVIGATION_MENU,\n className,\n )}\n {...props}\n >\n {children}\n {viewport && <NavigationMenuViewport />}\n </nav>\n );\n}\n\nexport function NavigationMenuList({ className, ...props }: React.ComponentProps<\"ul\">) {\n return (\n <ul\n data-slot=\"navigation-menu-list\"\n role=\"list\"\n className={cn(\n NAVIGATION_MENU_LIST,\n className,\n )}\n {...props}\n />\n );\n}\n\nexport interface NavigationMenuItemProps extends React.ComponentProps<\"li\"> {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\nexport function NavigationMenuItem({\n className,\n open,\n defaultOpen = false,\n onOpenChange,\n children,\n ...props\n}: NavigationMenuItemProps) {\n const [isOpen, setOpen] = useControllableState({\n value: open,\n defaultValue: defaultOpen,\n onChange: onOpenChange,\n });\n const triggerRef = React.useRef<HTMLButtonElement | null>(null);\n return (\n <NavigationMenuItemContext.Provider value={{ open: isOpen, setOpen, triggerRef }}>\n <li data-slot=\"navigation-menu-item\" className={cn(NAVIGATION_MENU_ITEM, className)} {...props}>\n {children}\n </li>\n </NavigationMenuItemContext.Provider>\n );\n}\n\nexport function NavigationMenuTrigger({\n className,\n children,\n onClick,\n ...props\n}: React.ComponentProps<\"button\">) {\n const { open, setOpen, triggerRef } = useItem();\n return (\n <button\n ref={triggerRef}\n type=\"button\"\n data-slot=\"navigation-menu-trigger\"\n data-state={open ? \"open\" : \"closed\"}\n className={cn(navigationMenuTriggerStyle(), \"group\", className)}\n onClick={(e) => {\n onClick?.(e);\n setOpen(!open);\n }}\n {...props}\n >\n {children}{\" \"}\n <svg\n className=\"relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n );\n}\n\nexport function NavigationMenuContent({ className, children, ...props }: React.ComponentProps<\"div\">) {\n const { open, setOpen, triggerRef } = useItem();\n const { isPresent, ref: presenceRef } = usePresence(open);\n const dismissRef = useDismissableLayer({\n enabled: open,\n onDismiss: () => setOpen(false),\n exclude: [triggerRef],\n });\n if (!isPresent) return null;\n return (\n <div\n ref={mergeRefs(presenceRef, dismissRef)}\n data-slot=\"navigation-menu-content\"\n data-state={open ? \"open\" : \"closed\"}\n className={cn(\n NAVIGATION_MENU_CONTENT,\n className,\n )}\n {...props}\n >\n {children}\n </div>\n );\n}\n\nexport function NavigationMenuViewport({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div className=\"absolute top-full left-0 isolate z-50 flex justify-center\">\n <div\n data-slot=\"navigation-menu-viewport\"\n className={cn(\n NAVIGATION_MENU_VIEWPORT,\n className,\n )}\n {...props}\n />\n </div>\n );\n}\n\nexport function NavigationMenuLink({\n className,\n asChild = false,\n ...props\n}: React.ComponentProps<\"a\"> & { asChild?: boolean }) {\n const Comp = asChild ? Slot : \"a\";\n return (\n <Comp\n data-slot=\"navigation-menu-link\"\n className={cn(\n NAVIGATION_MENU_LINK,\n className,\n )}\n {...(props as Record<string, unknown>)}\n />\n );\n}\n\nexport function NavigationMenuIndicator({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"navigation-menu-indicator\"\n className={cn(\n NAVIGATION_MENU_INDICATOR,\n className,\n )}\n {...props}\n >\n <div className=\"bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md\" />\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/navigation-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useControllableState } from \"../primitives/use-controllable-state\";\nimport { DismissableLayerScope, useDismissableLayer } from \"../primitives/dismissable-layer\";\nimport { usePresence } from \"../primitives/presence\";\nimport { mergeRefs } from \"../primitives/merge-refs\";\nimport { Slot } from \"../primitives/slot\";\nimport {\n NAVIGATION_MENU,\n NAVIGATION_MENU_CONTENT,\n NAVIGATION_MENU_INDICATOR,\n NAVIGATION_MENU_ITEM,\n NAVIGATION_MENU_LINK,\n NAVIGATION_MENU_LIST,\n NAVIGATION_MENU_TRIGGER_STYLE,\n NAVIGATION_MENU_VIEWPORT,\n} from \"../generated/navigation-menu\";\n\n/**\n * Fused canonical trigger class string, the mirror of Rust's\n * `navigation_menu_trigger_style()`. Reuse it to style a plain link the same way\n * a `NavigationMenuTrigger` is styled.\n */\nexport function navigationMenuTriggerStyle(): string {\n return NAVIGATION_MENU_TRIGGER_STYLE;\n}\n\ninterface ItemCtx {\n open: boolean;\n setOpen: (open: boolean) => void;\n triggerRef: React.RefObject<HTMLButtonElement | null>;\n}\nconst NavigationMenuItemContext = React.createContext<ItemCtx | null>(null);\nfunction useItem(): ItemCtx {\n const ctx = React.useContext(NavigationMenuItemContext);\n if (!ctx) throw new Error(\"NavigationMenu parts must be used within <NavigationMenuItem>\");\n return ctx;\n}\n\nexport function NavigationMenu({\n className,\n children,\n viewport = true,\n ...props\n}: React.ComponentProps<\"nav\"> & { viewport?: boolean }) {\n return (\n <nav\n data-slot=\"navigation-menu\"\n data-viewport={viewport}\n role=\"navigation\"\n className={cn(\n NAVIGATION_MENU,\n className,\n )}\n {...props}\n >\n {children}\n {viewport && <NavigationMenuViewport />}\n </nav>\n );\n}\n\nexport function NavigationMenuList({ className, ...props }: React.ComponentProps<\"ul\">) {\n return (\n <ul\n data-slot=\"navigation-menu-list\"\n role=\"list\"\n className={cn(\n NAVIGATION_MENU_LIST,\n className,\n )}\n {...props}\n />\n );\n}\n\nexport interface NavigationMenuItemProps extends React.ComponentProps<\"li\"> {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\nexport function NavigationMenuItem({\n className,\n open,\n defaultOpen = false,\n onOpenChange,\n children,\n ...props\n}: NavigationMenuItemProps) {\n const [isOpen, setOpen] = useControllableState({\n value: open,\n defaultValue: defaultOpen,\n onChange: onOpenChange,\n });\n const triggerRef = React.useRef<HTMLButtonElement | null>(null);\n return (\n <NavigationMenuItemContext.Provider value={{ open: isOpen, setOpen, triggerRef }}>\n <li data-slot=\"navigation-menu-item\" className={cn(NAVIGATION_MENU_ITEM, className)} {...props}>\n {children}\n </li>\n </NavigationMenuItemContext.Provider>\n );\n}\n\nexport function NavigationMenuTrigger({\n className,\n children,\n onClick,\n ...props\n}: React.ComponentProps<\"button\">) {\n const { open, setOpen, triggerRef } = useItem();\n return (\n <button\n ref={triggerRef}\n type=\"button\"\n data-slot=\"navigation-menu-trigger\"\n data-state={open ? \"open\" : \"closed\"}\n className={cn(navigationMenuTriggerStyle(), \"group\", className)}\n onClick={(e) => {\n onClick?.(e);\n setOpen(!open);\n }}\n {...props}\n >\n {children}{\" \"}\n <svg\n className=\"relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n );\n}\n\nexport function NavigationMenuContent({ className, children, ...props }: React.ComponentProps<\"div\">) {\n const { open, setOpen, triggerRef } = useItem();\n const { isPresent, ref: presenceRef } = usePresence(open);\n const dismissRef = useDismissableLayer({\n enabled: open,\n onDismiss: () => setOpen(false),\n exclude: [triggerRef],\n });\n if (!isPresent) return null;\n return (\n <div\n ref={mergeRefs(presenceRef, dismissRef)}\n data-slot=\"navigation-menu-content\"\n data-state={open ? \"open\" : \"closed\"}\n className={cn(\n NAVIGATION_MENU_CONTENT,\n className,\n )}\n {...props}\n >\n <DismissableLayerScope layer={dismissRef}>{children}</DismissableLayerScope>\n </div>\n );\n}\n\nexport function NavigationMenuViewport({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div className=\"absolute top-full left-0 isolate z-50 flex justify-center\">\n <div\n data-slot=\"navigation-menu-viewport\"\n className={cn(\n NAVIGATION_MENU_VIEWPORT,\n className,\n )}\n {...props}\n />\n </div>\n );\n}\n\nexport function NavigationMenuLink({\n className,\n asChild = false,\n ...props\n}: React.ComponentProps<\"a\"> & { asChild?: boolean }) {\n const Comp = asChild ? Slot : \"a\";\n return (\n <Comp\n data-slot=\"navigation-menu-link\"\n className={cn(\n NAVIGATION_MENU_LINK,\n className,\n )}\n {...(props as Record<string, unknown>)}\n />\n );\n}\n\nexport function NavigationMenuIndicator({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"navigation-menu-indicator\"\n className={cn(\n NAVIGATION_MENU_INDICATOR,\n className,\n )}\n {...props}\n >\n <div className=\"bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md\" />\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -4,7 +4,7 @@ import * as React from "react";
4
4
  import { cn } from "../lib/cn.js";
5
5
  import { useControllableState } from "../primitives/use-controllable-state.js";
6
6
  import { useFloating } from "../primitives/use-floating.js";
7
- import { useDismissableLayer } from "../primitives/dismissable-layer.js";
7
+ import { DismissableLayerScope, useDismissableLayer } from "../primitives/dismissable-layer.js";
8
8
  import { usePresence } from "../primitives/presence.js";
9
9
  import { mergeRefs } from "../primitives/merge-refs.js";
10
10
  import { Portal } from "../primitives/portal.js";
@@ -91,7 +91,7 @@ function PopoverContent({
91
91
  className
92
92
  ),
93
93
  ...props,
94
- children
94
+ children: /* @__PURE__ */ jsx(DismissableLayerScope, { layer: dismissRef, children })
95
95
  }
96
96
  ) });
97
97
  }