@music-vine/cadence 2.7.0 → 3.0.1

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 (46) hide show
  1. package/README.md +5 -44
  2. package/dist/components/accordion.js +2 -2
  3. package/dist/components/accordion.js.map +1 -1
  4. package/dist/components/badge.js +1 -1
  5. package/dist/components/badge.js.map +1 -1
  6. package/dist/components/button.js +3 -3
  7. package/dist/components/button.js.map +1 -1
  8. package/dist/components/carousel-dots.js +1 -1
  9. package/dist/components/carousel-dots.js.map +1 -1
  10. package/dist/components/carousel.js +2 -2
  11. package/dist/components/carousel.js.map +1 -1
  12. package/dist/components/checkbox.js +1 -1
  13. package/dist/components/checkbox.js.map +1 -1
  14. package/dist/components/context-menu.js +6 -6
  15. package/dist/components/context-menu.js.map +1 -1
  16. package/dist/components/dialog.js +2 -2
  17. package/dist/components/dialog.js.map +1 -1
  18. package/dist/components/input.js +2 -2
  19. package/dist/components/input.js.map +1 -1
  20. package/dist/components/popover.js +1 -1
  21. package/dist/components/popover.js.map +1 -1
  22. package/dist/components/radio-group.js +1 -1
  23. package/dist/components/radio-group.js.map +1 -1
  24. package/dist/components/scroll-drum.js +1 -1
  25. package/dist/components/scroll-drum.js.map +1 -1
  26. package/dist/components/select.js +1 -1
  27. package/dist/components/select.js.map +1 -1
  28. package/dist/components/slider.js +1 -1
  29. package/dist/components/slider.js.map +1 -1
  30. package/dist/components/stacking-card.js +1 -1
  31. package/dist/components/stacking-card.js.map +1 -1
  32. package/dist/components/tabs.js +2 -2
  33. package/dist/components/tabs.js.map +1 -1
  34. package/dist/components/toast.js +1 -1
  35. package/dist/components/toast.js.map +1 -1
  36. package/dist/components/typography/list.js +1 -1
  37. package/dist/components/typography/list.js.map +2 -2
  38. package/dist/lib/utils.d.ts +1 -1
  39. package/dist/lib/utils.d.ts.map +1 -1
  40. package/dist/lib/utils.js +7 -17
  41. package/dist/lib/utils.js.map +2 -2
  42. package/dist/styles/index.css +16 -3
  43. package/package.json +5 -11
  44. package/{tailwind.config.v4.css → tailwind.config.css} +35 -14
  45. package/dist/styles/index.v4.css +0 -49
  46. package/tailwind.config.ts +0 -313
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/context-menu.tsx"],
4
- "sourcesContent": ["/**\n * @module ContextMenu\n *\n * Right-click context menu with full keyboard navigation and accessibility.\n * Built on Radix UI Context Menu primitive.\n *\n * @see {@link https://ui.shadcn.com/docs/components/context-menu Shadcn Context Menu}\n * @see {@link https://www.radix-ui.com/primitives/docs/components/context-menu Radix Context Menu}\n *\n * @example\n * // Basic context menu\n * <ContextMenu>\n * <ContextMenuTrigger>Right click here</ContextMenuTrigger>\n * <ContextMenuContent>\n * <ContextMenuItem>Edit</ContextMenuItem>\n * <ContextMenuItem>Duplicate</ContextMenuItem>\n * <ContextMenuSeparator />\n * <ContextMenuItem>Delete</ContextMenuItem>\n * </ContextMenuContent>\n * </ContextMenu>\n *\n * @example\n * // With submenus and keyboard shortcuts\n * <ContextMenu>\n * <ContextMenuTrigger>Right click</ContextMenuTrigger>\n * <ContextMenuContent>\n * <ContextMenuItem>\n * Copy <ContextMenuShortcut>\u2318C</ContextMenuShortcut>\n * </ContextMenuItem>\n * <ContextMenuSub>\n * <ContextMenuSubTrigger>Share</ContextMenuSubTrigger>\n * <ContextMenuSubContent>\n * <ContextMenuItem>Email</ContextMenuItem>\n * <ContextMenuItem>Messages</ContextMenuItem>\n * </ContextMenuSubContent>\n * </ContextMenuSub>\n * </ContextMenuContent>\n * </ContextMenu>\n *\n * @example\n * // With checkbox and radio items\n * <ContextMenuContent>\n * <ContextMenuCheckboxItem checked={showToolbar}>\n * Show Toolbar\n * </ContextMenuCheckboxItem>\n * <ContextMenuRadioGroup value={view}>\n * <ContextMenuLabel>View</ContextMenuLabel>\n * <ContextMenuRadioItem value=\"grid\">Grid</ContextMenuRadioItem>\n * <ContextMenuRadioItem value=\"list\">List</ContextMenuRadioItem>\n * </ContextMenuRadioGroup>\n * </ContextMenuContent>\n */\nimport * as ContextMenuPrimitive from \"@radix-ui/react-context-menu\";\nimport { Check, ChevronRight, Circle } from \"lucide-react\";\nimport type * as React from \"react\";\nimport type { Ref } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** Root component that manages context menu state. */\nconst ContextMenu = ContextMenuPrimitive.Root;\n\n/** Element that triggers the context menu on right-click. */\nconst ContextMenuTrigger = ContextMenuPrimitive.Trigger;\n\n/** Groups related menu items together. */\nconst ContextMenuGroup = ContextMenuPrimitive.Group;\n\n/** Portal for rendering menu content outside the DOM hierarchy. */\nconst ContextMenuPortal = ContextMenuPrimitive.Portal;\n\n/** Container for nested submenu structure. */\nconst ContextMenuSub = ContextMenuPrimitive.Sub;\n\n/** Container for radio item selection group. */\nconst ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;\n\n/**\n * Trigger for opening a submenu. Shows chevron indicator.\n * @param inset - Add left padding to align with items that have icons\n */\ninterface ContextMenuSubTriggerProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger>,\n \"ref\"\n > {\n inset?: boolean;\n ref?: Ref<React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>>;\n}\n\nconst ContextMenuSubTrigger = ({\n className,\n inset,\n children,\n ref,\n ...props\n}: ContextMenuSubTriggerProps) => (\n <ContextMenuPrimitive.SubTrigger\n className={cn(\n \"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-gray-50 focus:text-gray-950 data-[state=open]:bg-gray-50 data-[state=open]:text-gray-950 dark:data-[state=open]:bg-gray-900 dark:data-[state=open]:text-white dark:focus:bg-gray-900 dark:focus:text-white\",\n inset && \"pl-8\",\n className\n )}\n ref={ref}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto h-4 w-4\" />\n </ContextMenuPrimitive.SubTrigger>\n);\n\n/** Content container for submenu items. Animated on open/close. */\ninterface ContextMenuSubContentProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof ContextMenuPrimitive.SubContent>>;\n}\n\nconst ContextMenuSubContent = ({\n className,\n ref,\n ...props\n}: ContextMenuSubContentProps) => (\n <ContextMenuPrimitive.SubContent\n className={cn(\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-[--radix-context-menu-content-transform-origin] overflow-hidden rounded-md border border-gray-150 bg-white p-1 text-gray-950 shadow-md data-[state=open]:animate-in dark:border-gray-800 dark:bg-gray-950 dark:text-gray-50\",\n className\n )}\n ref={ref}\n {...props}\n />\n);\n\n/** Main content container for the context menu. Renders in a portal with overlay. */\ninterface ContextMenuContentProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof ContextMenuPrimitive.Content>>;\n}\n\nconst ContextMenuContent = ({\n className,\n ref,\n ...props\n}: ContextMenuContentProps) => (\n <ContextMenuPrimitive.Portal>\n <ContextMenuPrimitive.Content\n className={cn(\n // Browser-style context menu styling - slim and clean\n \"data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1 z-50 min-w-[8rem] origin-[--radix-context-menu-content-transform-origin] overflow-hidden rounded-lg border border-gray-150 border-solid bg-white p-2 text-gray-950 shadow-lg outline-none data-[state=open]:animate-in data-[state=closed]:opacity-0 data-[state=open]:opacity-100 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-50\",\n className\n )}\n ref={ref}\n {...props}\n />\n </ContextMenuPrimitive.Portal>\n);\n\n/**\n * Clickable menu item. Closes menu on selection.\n * @param inset - Add left padding to align with items that have icons\n */\ninterface ContextMenuItemProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item>,\n \"ref\"\n > {\n inset?: boolean;\n ref?: Ref<React.ElementRef<typeof ContextMenuPrimitive.Item>>;\n}\n\nconst ContextMenuItem = ({\n className,\n inset,\n ref,\n ...props\n}: ContextMenuItemProps) => (\n <ContextMenuPrimitive.Item\n className={cn(\n // Browser-style menu item - slim padding, subtle hover\n \"relative flex cursor-default select-none items-center rounded px-2 py-1 text-sm outline-none transition-colors hover:bg-gray-50 focus:bg-gray-50 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-gray-800 dark:hover:bg-gray-800\",\n inset && \"pl-8\",\n className\n )}\n ref={ref}\n {...props}\n />\n);\n\n/** Toggleable checkbox menu item with check indicator when selected. */\ninterface ContextMenuCheckboxItemProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>>;\n}\n\nconst ContextMenuCheckboxItem = ({\n className,\n children,\n checked,\n ref,\n ...props\n}: ContextMenuCheckboxItemProps) => (\n <ContextMenuPrimitive.CheckboxItem\n checked={checked}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-none focus:bg-gray-50 focus:text-gray-950 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-gray-900 dark:focus:text-white\",\n className\n )}\n ref={ref}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <ContextMenuPrimitive.ItemIndicator>\n <Check className=\"h-4 w-4\" />\n </ContextMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </ContextMenuPrimitive.CheckboxItem>\n);\n\n/** Radio option within a ContextMenuRadioGroup. Shows dot indicator when selected. */\ninterface ContextMenuRadioItemProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof ContextMenuPrimitive.RadioItem>>;\n}\n\nconst ContextMenuRadioItem = ({\n className,\n children,\n ref,\n ...props\n}: ContextMenuRadioItemProps) => (\n <ContextMenuPrimitive.RadioItem\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-none focus:bg-gray-50 focus:text-gray-950 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-gray-900 dark:focus:text-white\",\n className\n )}\n ref={ref}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <ContextMenuPrimitive.ItemIndicator>\n <Circle className=\"h-2 w-2 fill-current\" />\n </ContextMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </ContextMenuPrimitive.RadioItem>\n);\n\n/**\n * Non-interactive label for grouping menu items.\n * @param inset - Add left padding to align with items that have icons\n */\ninterface ContextMenuLabelProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label>,\n \"ref\"\n > {\n inset?: boolean;\n ref?: Ref<React.ElementRef<typeof ContextMenuPrimitive.Label>>;\n}\n\nconst ContextMenuLabel = ({\n className,\n inset,\n ref,\n ...props\n}: ContextMenuLabelProps) => (\n <ContextMenuPrimitive.Label\n className={cn(\n \"px-2 py-1.5 font-semibold text-gray-950 text-sm dark:text-gray-50\",\n inset && \"pl-8\",\n className\n )}\n ref={ref}\n {...props}\n />\n);\n\n/** Visual divider between menu item groups. */\ninterface ContextMenuSeparatorProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof ContextMenuPrimitive.Separator>>;\n}\n\nconst ContextMenuSeparator = ({\n className,\n ref,\n ...props\n}: ContextMenuSeparatorProps) => (\n <ContextMenuPrimitive.Separator\n className={cn(\"-mx-1 my-1 h-px bg-gray-150 dark:bg-gray-800\", className)}\n ref={ref}\n {...props}\n />\n);\n\n/** Displays keyboard shortcut hint aligned to the right of a menu item. */\nconst ContextMenuShortcut = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => (\n <span\n className={cn(\n \"ml-auto text-gray-600 text-xs tracking-widest dark:text-gray-500\",\n className\n )}\n {...props}\n />\n);\nContextMenuShortcut.displayName = \"ContextMenuShortcut\";\n\nexport {\n ContextMenu,\n ContextMenuCheckboxItem,\n ContextMenuContent,\n ContextMenuGroup,\n ContextMenuItem,\n ContextMenuLabel,\n ContextMenuPortal,\n ContextMenuRadioGroup,\n ContextMenuRadioItem,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n};\n"],
4
+ "sourcesContent": ["/**\n * @module ContextMenu\n *\n * Right-click context menu with full keyboard navigation and accessibility.\n * Built on Radix UI Context Menu primitive.\n *\n * @see {@link https://ui.shadcn.com/docs/components/context-menu Shadcn Context Menu}\n * @see {@link https://www.radix-ui.com/primitives/docs/components/context-menu Radix Context Menu}\n *\n * @example\n * // Basic context menu\n * <ContextMenu>\n * <ContextMenuTrigger>Right click here</ContextMenuTrigger>\n * <ContextMenuContent>\n * <ContextMenuItem>Edit</ContextMenuItem>\n * <ContextMenuItem>Duplicate</ContextMenuItem>\n * <ContextMenuSeparator />\n * <ContextMenuItem>Delete</ContextMenuItem>\n * </ContextMenuContent>\n * </ContextMenu>\n *\n * @example\n * // With submenus and keyboard shortcuts\n * <ContextMenu>\n * <ContextMenuTrigger>Right click</ContextMenuTrigger>\n * <ContextMenuContent>\n * <ContextMenuItem>\n * Copy <ContextMenuShortcut>\u2318C</ContextMenuShortcut>\n * </ContextMenuItem>\n * <ContextMenuSub>\n * <ContextMenuSubTrigger>Share</ContextMenuSubTrigger>\n * <ContextMenuSubContent>\n * <ContextMenuItem>Email</ContextMenuItem>\n * <ContextMenuItem>Messages</ContextMenuItem>\n * </ContextMenuSubContent>\n * </ContextMenuSub>\n * </ContextMenuContent>\n * </ContextMenu>\n *\n * @example\n * // With checkbox and radio items\n * <ContextMenuContent>\n * <ContextMenuCheckboxItem checked={showToolbar}>\n * Show Toolbar\n * </ContextMenuCheckboxItem>\n * <ContextMenuRadioGroup value={view}>\n * <ContextMenuLabel>View</ContextMenuLabel>\n * <ContextMenuRadioItem value=\"grid\">Grid</ContextMenuRadioItem>\n * <ContextMenuRadioItem value=\"list\">List</ContextMenuRadioItem>\n * </ContextMenuRadioGroup>\n * </ContextMenuContent>\n */\nimport * as ContextMenuPrimitive from \"@radix-ui/react-context-menu\";\nimport { Check, ChevronRight, Circle } from \"lucide-react\";\nimport type * as React from \"react\";\nimport type { Ref } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** Root component that manages context menu state. */\nconst ContextMenu = ContextMenuPrimitive.Root;\n\n/** Element that triggers the context menu on right-click. */\nconst ContextMenuTrigger = ContextMenuPrimitive.Trigger;\n\n/** Groups related menu items together. */\nconst ContextMenuGroup = ContextMenuPrimitive.Group;\n\n/** Portal for rendering menu content outside the DOM hierarchy. */\nconst ContextMenuPortal = ContextMenuPrimitive.Portal;\n\n/** Container for nested submenu structure. */\nconst ContextMenuSub = ContextMenuPrimitive.Sub;\n\n/** Container for radio item selection group. */\nconst ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;\n\n/**\n * Trigger for opening a submenu. Shows chevron indicator.\n * @param inset - Add left padding to align with items that have icons\n */\ninterface ContextMenuSubTriggerProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger>,\n \"ref\"\n > {\n inset?: boolean;\n ref?: Ref<React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>>;\n}\n\nconst ContextMenuSubTrigger = ({\n className,\n inset,\n children,\n ref,\n ...props\n}: ContextMenuSubTriggerProps) => (\n <ContextMenuPrimitive.SubTrigger\n className={cn(\n \"flex cursor-default select-none items-center rounded-xs px-2 py-1.5 text-sm outline-hidden focus:bg-gray-50 focus:text-gray-950 data-[state=open]:bg-gray-50 data-[state=open]:text-gray-950 dark:data-[state=open]:bg-gray-900 dark:data-[state=open]:text-white dark:focus:bg-gray-900 dark:focus:text-white\",\n inset && \"pl-8\",\n className\n )}\n ref={ref}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto h-4 w-4\" />\n </ContextMenuPrimitive.SubTrigger>\n);\n\n/** Content container for submenu items. Animated on open/close. */\ninterface ContextMenuSubContentProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof ContextMenuPrimitive.SubContent>>;\n}\n\nconst ContextMenuSubContent = ({\n className,\n ref,\n ...props\n}: ContextMenuSubContentProps) => (\n <ContextMenuPrimitive.SubContent\n className={cn(\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-hidden rounded-md border border-gray-150 bg-white p-1 text-gray-950 shadow-md data-[state=open]:animate-in dark:border-gray-800 dark:bg-gray-950 dark:text-gray-50\",\n className\n )}\n ref={ref}\n {...props}\n />\n);\n\n/** Main content container for the context menu. Renders in a portal with overlay. */\ninterface ContextMenuContentProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof ContextMenuPrimitive.Content>>;\n}\n\nconst ContextMenuContent = ({\n className,\n ref,\n ...props\n}: ContextMenuContentProps) => (\n <ContextMenuPrimitive.Portal>\n <ContextMenuPrimitive.Content\n className={cn(\n // Browser-style context menu styling - slim and clean\n \"data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1 z-50 min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-hidden rounded-lg border border-gray-150 border-solid bg-white p-2 text-gray-950 shadow-lg outline-hidden data-[state=open]:animate-in data-[state=closed]:opacity-0 data-[state=open]:opacity-100 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-50\",\n className\n )}\n ref={ref}\n {...props}\n />\n </ContextMenuPrimitive.Portal>\n);\n\n/**\n * Clickable menu item. Closes menu on selection.\n * @param inset - Add left padding to align with items that have icons\n */\ninterface ContextMenuItemProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item>,\n \"ref\"\n > {\n inset?: boolean;\n ref?: Ref<React.ElementRef<typeof ContextMenuPrimitive.Item>>;\n}\n\nconst ContextMenuItem = ({\n className,\n inset,\n ref,\n ...props\n}: ContextMenuItemProps) => (\n <ContextMenuPrimitive.Item\n className={cn(\n // Browser-style menu item - slim padding, subtle hover\n \"relative flex cursor-default select-none items-center rounded px-2 py-1 text-sm outline-hidden transition-colors hover:bg-gray-50 focus:bg-gray-50 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-gray-800 dark:hover:bg-gray-800\",\n inset && \"pl-8\",\n className\n )}\n ref={ref}\n {...props}\n />\n);\n\n/** Toggleable checkbox menu item with check indicator when selected. */\ninterface ContextMenuCheckboxItemProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>>;\n}\n\nconst ContextMenuCheckboxItem = ({\n className,\n children,\n checked,\n ref,\n ...props\n}: ContextMenuCheckboxItemProps) => (\n <ContextMenuPrimitive.CheckboxItem\n checked={checked}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden focus:bg-gray-50 focus:text-gray-950 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-gray-900 dark:focus:text-white\",\n className\n )}\n ref={ref}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <ContextMenuPrimitive.ItemIndicator>\n <Check className=\"h-4 w-4\" />\n </ContextMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </ContextMenuPrimitive.CheckboxItem>\n);\n\n/** Radio option within a ContextMenuRadioGroup. Shows dot indicator when selected. */\ninterface ContextMenuRadioItemProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof ContextMenuPrimitive.RadioItem>>;\n}\n\nconst ContextMenuRadioItem = ({\n className,\n children,\n ref,\n ...props\n}: ContextMenuRadioItemProps) => (\n <ContextMenuPrimitive.RadioItem\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden focus:bg-gray-50 focus:text-gray-950 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-gray-900 dark:focus:text-white\",\n className\n )}\n ref={ref}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <ContextMenuPrimitive.ItemIndicator>\n <Circle className=\"h-2 w-2 fill-current\" />\n </ContextMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </ContextMenuPrimitive.RadioItem>\n);\n\n/**\n * Non-interactive label for grouping menu items.\n * @param inset - Add left padding to align with items that have icons\n */\ninterface ContextMenuLabelProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label>,\n \"ref\"\n > {\n inset?: boolean;\n ref?: Ref<React.ElementRef<typeof ContextMenuPrimitive.Label>>;\n}\n\nconst ContextMenuLabel = ({\n className,\n inset,\n ref,\n ...props\n}: ContextMenuLabelProps) => (\n <ContextMenuPrimitive.Label\n className={cn(\n \"px-2 py-1.5 font-semibold text-gray-950 text-sm dark:text-gray-50\",\n inset && \"pl-8\",\n className\n )}\n ref={ref}\n {...props}\n />\n);\n\n/** Visual divider between menu item groups. */\ninterface ContextMenuSeparatorProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof ContextMenuPrimitive.Separator>>;\n}\n\nconst ContextMenuSeparator = ({\n className,\n ref,\n ...props\n}: ContextMenuSeparatorProps) => (\n <ContextMenuPrimitive.Separator\n className={cn(\"-mx-1 my-1 h-px bg-gray-150 dark:bg-gray-800\", className)}\n ref={ref}\n {...props}\n />\n);\n\n/** Displays keyboard shortcut hint aligned to the right of a menu item. */\nconst ContextMenuShortcut = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => (\n <span\n className={cn(\n \"ml-auto text-gray-600 text-xs tracking-widest dark:text-gray-500\",\n className\n )}\n {...props}\n />\n);\nContextMenuShortcut.displayName = \"ContextMenuShortcut\";\n\nexport {\n ContextMenu,\n ContextMenuCheckboxItem,\n ContextMenuContent,\n ContextMenuGroup,\n ContextMenuItem,\n ContextMenuLabel,\n ContextMenuPortal,\n ContextMenuRadioGroup,\n ContextMenuRadioItem,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n};\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -35,7 +35,7 @@ const DialogContent = ({
35
35
  DialogPrimitive.Content,
36
36
  {
37
37
  className: cn(
38
- "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-gray-150 border-solid bg-white p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in sm:rounded-lg dark:border-gray-800 dark:bg-gray-950",
38
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-gray-150 border-solid bg-white p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in sm:rounded-lg dark:border-gray-800 dark:bg-gray-950",
39
39
  className
40
40
  ),
41
41
  ref,
@@ -46,7 +46,7 @@ const DialogContent = ({
46
46
  DialogPrimitive.Close,
47
47
  {
48
48
  asChild: true,
49
- className: "absolute top-4 right-4 opacity-100 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-gray-950 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-gray-100 data-[state=open]:text-gray-500 dark:ring-offset-gray-950 dark:data-[state=open]:bg-gray-800 dark:data-[state=open]:text-gray-400 dark:focus:ring-gray-300",
49
+ className: "absolute top-4 right-4 opacity-100 ring-offset-white transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-gray-950 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-gray-100 data-[state=open]:text-gray-500 dark:ring-offset-gray-950 dark:data-[state=open]:bg-gray-800 dark:data-[state=open]:text-gray-400 dark:focus:ring-gray-300",
50
50
  children: /* @__PURE__ */ jsxs(Button, { "aria-label": "Close", size: "icon", variant: "transparent", children: [
51
51
  /* @__PURE__ */ jsx(X, { className: "h-5 w-5" }),
52
52
  /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/dialog.tsx"],
4
- "sourcesContent": ["/**\n * @module Dialog\n *\n * Modal dialog overlay for focused user interaction. Built on Radix UI Dialog primitive.\n * Includes backdrop overlay, close button, and focus trapping.\n *\n * @see {@link https://ui.shadcn.com/docs/components/dialog Shadcn Dialog}\n * @see {@link https://www.radix-ui.com/primitives/docs/components/dialog Radix Dialog}\n *\n * @example\n * // Basic dialog\n * <Dialog>\n * <DialogTrigger asChild>\n * <Button>Open Dialog</Button>\n * </DialogTrigger>\n * <DialogContent>\n * <DialogHeader>\n * <DialogTitle>Are you sure?</DialogTitle>\n * <DialogDescription>\n * This action cannot be undone.\n * </DialogDescription>\n * </DialogHeader>\n * <DialogFooter>\n * <Button>Confirm</Button>\n * </DialogFooter>\n * </DialogContent>\n * </Dialog>\n *\n * @example\n * // Controlled dialog\n * const [open, setOpen] = useState(false);\n *\n * <Dialog open={open} onOpenChange={setOpen}>\n * <DialogContent>\n * <DialogHeader>\n * <DialogTitle>Edit Profile</DialogTitle>\n * </DialogHeader>\n * <form onSubmit={() => setOpen(false)}>\n * ...\n * </form>\n * </DialogContent>\n * </Dialog>\n */\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { X } from \"lucide-react\";\nimport type * as React from \"react\";\nimport type { Ref } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"./button\";\nimport { headingVariants } from \"./typography/heading\";\nimport { textVariants } from \"./typography/text\";\n\n/** Root component that manages dialog open/closed state. */\nconst Dialog = DialogPrimitive.Root;\n\n/** Element that opens the dialog when clicked. Use `asChild` to wrap custom buttons. */\nconst DialogTrigger = DialogPrimitive.Trigger;\n\n/** Portal for rendering dialog outside the DOM hierarchy. */\nconst DialogPortal = DialogPrimitive.Portal;\n\n/** Closes the dialog when clicked. Use `asChild` to wrap custom close buttons. */\nconst DialogClose = DialogPrimitive.Close;\n\n/** Semi-transparent backdrop behind the dialog. Animated fade on open/close. */\nconst DialogOverlay = ({\n className,\n ref,\n ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> & {\n ref?: Ref<React.ElementRef<typeof DialogPrimitive.Overlay>>;\n}) => (\n <DialogPrimitive.Overlay\n className={cn(\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/60 data-[state=closed]:animate-out data-[state=open]:animate-in\",\n className\n )}\n ref={ref}\n {...props}\n />\n);\n\n/**\n * Main dialog container. Centered on screen with close button.\n * Includes overlay, focus trap, and Escape key handling.\n */\nconst DialogContent = ({\n className,\n children,\n ref,\n ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {\n ref?: Ref<React.ElementRef<typeof DialogPrimitive.Content>>;\n}) => (\n <DialogPortal>\n <DialogOverlay />\n <DialogPrimitive.Content\n className={cn(\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-gray-150 border-solid bg-white p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in sm:rounded-lg dark:border-gray-800 dark:bg-gray-950\",\n className\n )}\n ref={ref}\n {...props}\n >\n {children}\n <DialogPrimitive.Close\n asChild\n className=\"absolute top-4 right-4 opacity-100 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-gray-950 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-gray-100 data-[state=open]:text-gray-500 dark:ring-offset-gray-950 dark:data-[state=open]:bg-gray-800 dark:data-[state=open]:text-gray-400 dark:focus:ring-gray-300\"\n >\n <Button aria-label=\"Close\" size=\"icon\" variant=\"transparent\">\n <X className=\"h-5 w-5\" />\n <span className=\"sr-only\">Close</span>\n </Button>\n </DialogPrimitive.Close>\n </DialogPrimitive.Content>\n </DialogPortal>\n);\n\n/** Header section for dialog title and description. Centered on mobile, left-aligned on desktop. */\nconst DialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-1.5 text-center sm:text-left\",\n className\n )}\n {...props}\n />\n);\nDialogHeader.displayName = \"DialogHeader\";\n\n/** Footer section for action buttons. Stacks on mobile, horizontal on desktop. */\nconst DialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className\n )}\n {...props}\n />\n);\nDialogFooter.displayName = \"DialogFooter\";\n\n/** Dialog title with Echo typography. Required for accessibility. */\nconst DialogTitle = ({\n className,\n ref,\n ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title> & {\n ref?: Ref<React.ElementRef<typeof DialogPrimitive.Title>>;\n}) => (\n <DialogPrimitive.Title\n className={cn(\n headingVariants({ variant: \"h5\", fontFamily: \"brand\" }),\n className\n )}\n ref={ref}\n {...props}\n />\n);\n\n/** Accessible description text below the title. */\nconst DialogDescription = ({\n className,\n ref,\n ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description> & {\n ref?: Ref<React.ElementRef<typeof DialogPrimitive.Description>>;\n}) => (\n <DialogPrimitive.Description\n className={cn(textVariants(), \"text-sm\", className)}\n ref={ref}\n {...props}\n />\n);\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n};\n"],
4
+ "sourcesContent": ["/**\n * @module Dialog\n *\n * Modal dialog overlay for focused user interaction. Built on Radix UI Dialog primitive.\n * Includes backdrop overlay, close button, and focus trapping.\n *\n * @see {@link https://ui.shadcn.com/docs/components/dialog Shadcn Dialog}\n * @see {@link https://www.radix-ui.com/primitives/docs/components/dialog Radix Dialog}\n *\n * @example\n * // Basic dialog\n * <Dialog>\n * <DialogTrigger asChild>\n * <Button>Open Dialog</Button>\n * </DialogTrigger>\n * <DialogContent>\n * <DialogHeader>\n * <DialogTitle>Are you sure?</DialogTitle>\n * <DialogDescription>\n * This action cannot be undone.\n * </DialogDescription>\n * </DialogHeader>\n * <DialogFooter>\n * <Button>Confirm</Button>\n * </DialogFooter>\n * </DialogContent>\n * </Dialog>\n *\n * @example\n * // Controlled dialog\n * const [open, setOpen] = useState(false);\n *\n * <Dialog open={open} onOpenChange={setOpen}>\n * <DialogContent>\n * <DialogHeader>\n * <DialogTitle>Edit Profile</DialogTitle>\n * </DialogHeader>\n * <form onSubmit={() => setOpen(false)}>\n * ...\n * </form>\n * </DialogContent>\n * </Dialog>\n */\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { X } from \"lucide-react\";\nimport type * as React from \"react\";\nimport type { Ref } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"./button\";\nimport { headingVariants } from \"./typography/heading\";\nimport { textVariants } from \"./typography/text\";\n\n/** Root component that manages dialog open/closed state. */\nconst Dialog = DialogPrimitive.Root;\n\n/** Element that opens the dialog when clicked. Use `asChild` to wrap custom buttons. */\nconst DialogTrigger = DialogPrimitive.Trigger;\n\n/** Portal for rendering dialog outside the DOM hierarchy. */\nconst DialogPortal = DialogPrimitive.Portal;\n\n/** Closes the dialog when clicked. Use `asChild` to wrap custom close buttons. */\nconst DialogClose = DialogPrimitive.Close;\n\n/** Semi-transparent backdrop behind the dialog. Animated fade on open/close. */\nconst DialogOverlay = ({\n className,\n ref,\n ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> & {\n ref?: Ref<React.ElementRef<typeof DialogPrimitive.Overlay>>;\n}) => (\n <DialogPrimitive.Overlay\n className={cn(\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/60 data-[state=closed]:animate-out data-[state=open]:animate-in\",\n className\n )}\n ref={ref}\n {...props}\n />\n);\n\n/**\n * Main dialog container. Centered on screen with close button.\n * Includes overlay, focus trap, and Escape key handling.\n */\nconst DialogContent = ({\n className,\n children,\n ref,\n ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {\n ref?: Ref<React.ElementRef<typeof DialogPrimitive.Content>>;\n}) => (\n <DialogPortal>\n <DialogOverlay />\n <DialogPrimitive.Content\n className={cn(\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-gray-150 border-solid bg-white p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in sm:rounded-lg dark:border-gray-800 dark:bg-gray-950\",\n className\n )}\n ref={ref}\n {...props}\n >\n {children}\n <DialogPrimitive.Close\n asChild\n className=\"absolute top-4 right-4 opacity-100 ring-offset-white transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-gray-950 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-gray-100 data-[state=open]:text-gray-500 dark:ring-offset-gray-950 dark:data-[state=open]:bg-gray-800 dark:data-[state=open]:text-gray-400 dark:focus:ring-gray-300\"\n >\n <Button aria-label=\"Close\" size=\"icon\" variant=\"transparent\">\n <X className=\"h-5 w-5\" />\n <span className=\"sr-only\">Close</span>\n </Button>\n </DialogPrimitive.Close>\n </DialogPrimitive.Content>\n </DialogPortal>\n);\n\n/** Header section for dialog title and description. Centered on mobile, left-aligned on desktop. */\nconst DialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-1.5 text-center sm:text-left\",\n className\n )}\n {...props}\n />\n);\nDialogHeader.displayName = \"DialogHeader\";\n\n/** Footer section for action buttons. Stacks on mobile, horizontal on desktop. */\nconst DialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className\n )}\n {...props}\n />\n);\nDialogFooter.displayName = \"DialogFooter\";\n\n/** Dialog title with Echo typography. Required for accessibility. */\nconst DialogTitle = ({\n className,\n ref,\n ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title> & {\n ref?: Ref<React.ElementRef<typeof DialogPrimitive.Title>>;\n}) => (\n <DialogPrimitive.Title\n className={cn(\n headingVariants({ variant: \"h5\", fontFamily: \"brand\" }),\n className\n )}\n ref={ref}\n {...props}\n />\n);\n\n/** Accessible description text below the title. */\nconst DialogDescription = ({\n className,\n ref,\n ...props\n}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description> & {\n ref?: Ref<React.ElementRef<typeof DialogPrimitive.Description>>;\n}) => (\n <DialogPrimitive.Description\n className={cn(textVariants(), \"text-sm\", className)}\n ref={ref}\n {...props}\n />\n);\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n};\n"],
5
5
  "mappings": "AAyEE,cAqCM,YArCN;AA9BF,YAAY,qBAAqB;AACjC,SAAS,SAAS;AAIlB,SAAS,UAAU;AACnB,SAAS,cAAc;AACvB,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAG7B,MAAM,SAAS,gBAAgB;AAG/B,MAAM,gBAAgB,gBAAgB;AAGtC,MAAM,eAAe,gBAAgB;AAGrC,MAAM,cAAc,gBAAgB;AAGpC,MAAM,gBAAgB,CAAC;AAAA,EACrB;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAGE;AAAA,EAAC,gBAAgB;AAAA,EAAhB;AAAA,IACC,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,IACC,GAAG;AAAA;AACN;AAOF,MAAM,gBAAgB,CAAC;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAGE,qBAAC,gBACC;AAAA,sBAAC,iBAAc;AAAA,EACf;AAAA,IAAC,gBAAgB;AAAA,IAAhB;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,QACD;AAAA,UAAC,gBAAgB;AAAA,UAAhB;AAAA,YACC,SAAO;AAAA,YACP,WAAU;AAAA,YAEV,+BAAC,UAAO,cAAW,SAAQ,MAAK,QAAO,SAAQ,eAC7C;AAAA,kCAAC,KAAE,WAAU,WAAU;AAAA,cACvB,oBAAC,UAAK,WAAU,WAAU,mBAAK;AAAA,eACjC;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAAA,GACF;AAIF,MAAM,eAAe,CAAC;AAAA,EACpB;AAAA,EACA,GAAG;AACL,MACE;AAAA,EAAC;AAAA;AAAA,IACC,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN;AAEF,aAAa,cAAc;AAG3B,MAAM,eAAe,CAAC;AAAA,EACpB;AAAA,EACA,GAAG;AACL,MACE;AAAA,EAAC;AAAA;AAAA,IACC,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN;AAEF,aAAa,cAAc;AAG3B,MAAM,cAAc,CAAC;AAAA,EACnB;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAGE;AAAA,EAAC,gBAAgB;AAAA,EAAhB;AAAA,IACC,WAAW;AAAA,MACT,gBAAgB,EAAE,SAAS,MAAM,YAAY,QAAQ,CAAC;AAAA,MACtD;AAAA,IACF;AAAA,IACA;AAAA,IACC,GAAG;AAAA;AACN;AAIF,MAAM,oBAAoB,CAAC;AAAA,EACzB;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAGE;AAAA,EAAC,gBAAgB;AAAA,EAAhB;AAAA,IACC,WAAW,GAAG,aAAa,GAAG,WAAW,SAAS;AAAA,IAClD;AAAA,IACC,GAAG;AAAA;AACN;",
6
6
  "names": []
7
7
  }
@@ -18,7 +18,7 @@ const inputWrapperVariants = cva("relative flex w-full items-center", {
18
18
  });
19
19
  const inputVariants = cva(
20
20
  [
21
- "w-full touch-manipulation self-stretch shadow-none outline-none outline-0 transition duration-200 ease-out disabled:cursor-not-allowed dark:disabled:cursor-not-allowed",
21
+ "w-full touch-manipulation self-stretch shadow-none outline-hidden outline-0 transition duration-200 ease-out disabled:cursor-not-allowed dark:disabled:cursor-not-allowed",
22
22
  // text
23
23
  "font-sans text-base text-black antialiased disabled:text-black/60 dark:text-white dark:disabled:text-white/60",
24
24
  // placeholder
@@ -166,7 +166,7 @@ const ClearInputButton = ({
166
166
  className: cn(
167
167
  "absolute top-1/2 -translate-y-1/2 text-gray-950 dark:text-gray-300",
168
168
  "focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-gray-100",
169
- "rounded-full focus-visible:outline-none dark:focus-visible:ring-[var(--focus-ring)] dark:focus-visible:ring-offset-gray-800",
169
+ "rounded-full focus-visible:outline-hidden dark:focus-visible:ring-[var(--focus-ring)] dark:focus-visible:ring-offset-gray-800",
170
170
  className
171
171
  ),
172
172
  ref,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/input.tsx"],
4
- "sourcesContent": ["/**\n * @module Input\n *\n * Styled text input with support for icons, sizes, and clear button.\n * Includes focus state management and dark mode support.\n *\n * @example\n * // Basic input\n * <Input placeholder=\"Enter your email\" type=\"email\" />\n *\n * @example\n * // With icons\n * <Input\n * leftIcon={<Search />}\n * rightIcon={<ClearInputButton onClick={clearValue} />}\n * placeholder=\"Search...\"\n * />\n *\n * @example\n * // Small size\n * <Input size=\"sm\" placeholder=\"Compact input\" />\n *\n * @example\n * // With clear button\n * const [value, setValue] = useState('');\n *\n * <Input\n * value={value}\n * onChange={(e) => setValue(e.target.value)}\n * rightIcon={\n * value && <ClearInputButton onClick={() => setValue('')} />\n * }\n * />\n */\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { X } from \"lucide-react\";\nimport { Slot as SlotPrimitive } from \"radix-ui\";\nimport type { Ref } from \"react\";\nimport { useState } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\nconst inputWrapperVariants = cva(\"relative flex w-full items-center\", {\n variants: {\n size: {\n auto: \"h-auto w-auto\",\n default: \"h-10\",\n sm: \"h-7\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n});\n\nconst inputVariants = cva(\n [\n \"w-full touch-manipulation self-stretch shadow-none outline-none outline-0 transition duration-200 ease-out disabled:cursor-not-allowed dark:disabled:cursor-not-allowed\",\n // text\n \"font-sans text-base text-black antialiased disabled:text-black/60 dark:text-white dark:disabled:text-white/60\",\n // placeholder\n \"placeholder-gray-700 placeholder:font-sans dark:placeholder-gray-200\",\n // background\n \"bg-white focus:bg-white enabled:hover:bg-white disabled:bg-white/60 dark:bg-black dark:disabled:bg-black/60 dark:focus:bg-black dark:enabled:hover:bg-black\",\n // borders (light)\n \"rounded-lg border border-gray-150 border-solid invalid:border-red invalid:hover:border-red focus:border-brand-primary enabled:hover:border-gray-200 enabled:focus:hover:border-brand-primary disabled:border-gray-150/60\", // borders light\n // borders (dark)\n \"dark:border-gray-800 dark:disabled:border-gray-900 dark:focus:border-white dark:enabled:hover:border-gray-700 dark:enabled:focus:hover:border-white dark:invalid:border-red dark:invalid:hover:border-red\", // borders dark\n ],\n {\n variants: {\n size: {\n default: \"px-4\",\n sm: \"px-3\",\n auto: \"px-4\",\n },\n hasLeftIcon: {\n true: \"\",\n false: \"\",\n },\n hasRightIcon: {\n true: \"\",\n false: \"\",\n },\n // Scoped to type=\"search\" only: the Keeper password manager extension\n // misidentifies inputs that style ::-webkit-search-cancel-button as\n // search fields and blocks paste, so non-search inputs must not match.\n type: {\n search: \"dark:[&::-webkit-search-cancel-button]:hidden\",\n },\n },\n compoundVariants: [\n {\n hasLeftIcon: true,\n size: \"default\",\n class: \"pl-10\",\n },\n {\n hasLeftIcon: true,\n size: \"sm\",\n class: \"pl-8\",\n },\n {\n hasRightIcon: true,\n size: \"default\",\n class: \"pr-10\",\n },\n {\n hasRightIcon: true,\n size: \"sm\",\n class: \"pr-8\",\n },\n ],\n defaultVariants: {\n size: \"default\",\n hasLeftIcon: false,\n hasRightIcon: false,\n },\n }\n);\n\ntype InputPropsWithoutSize = Omit<\n React.InputHTMLAttributes<HTMLInputElement>,\n \"size\"\n>;\n\ntype InputVariantsProps = VariantProps<typeof inputVariants>;\n\n// Omit internal-only variants from the public API. `type` is excluded so\n// consumers keep the full HTMLInputTypeAttribute union; CVA still picks up\n// the runtime value via the `type` argument passed in inputVariants().\ntype PublicInputVariantsProps = Omit<\n InputVariantsProps,\n \"hasLeftIcon\" | \"hasRightIcon\" | \"type\"\n>;\n\n/**\n * Props for the Input component.\n * @property size - Input size: `\"default\"`, `\"sm\"`, or `\"auto\"`\n * @property htmlSize - Native HTML size attribute for input width\n * @property leftIcon - Icon element displayed on the left side\n * @property rightIcon - Icon element displayed on the right side\n */\nexport interface InputProps\n extends InputPropsWithoutSize,\n PublicInputVariantsProps {\n htmlSize?: number;\n leftIcon?: React.ReactNode;\n ref?: Ref<HTMLInputElement>;\n rightIcon?: React.ReactNode;\n}\n\nconst Input = ({\n className,\n size,\n type = \"text\",\n htmlSize,\n leftIcon,\n rightIcon,\n placeholder,\n ref,\n ...props\n}: InputProps) => {\n const [isFocused, setIsFocused] = useState(false);\n\n return (\n // biome-ignore lint/a11y/noNoninteractiveElementInteractions: container needs onBlur to coordinate focus state across child input and icon slots\n // biome-ignore lint/a11y/noStaticElementInteractions: container needs onBlur to coordinate focus state across child input and icon slots\n <div\n className={cn(inputWrapperVariants({ size }))}\n onBlur={() => {\n setTimeout(() => {\n setIsFocused(false);\n }, 50);\n }}\n >\n {!!leftIcon && (\n <SlotPrimitive.Slot\n className={cn(\n \"absolute top-1/2 -translate-y-1/2 text-gray-950 dark:text-gray-300 [&:is(svg)]:pointer-events-none\",\n size === \"sm\" ? \"left-3 size-3\" : \"left-4 size-4\"\n )}\n >\n {leftIcon}\n </SlotPrimitive.Slot>\n )}\n <input\n className={cn(\n inputVariants({\n size,\n hasLeftIcon: !!leftIcon,\n hasRightIcon: !!rightIcon,\n type: type === \"search\" ? \"search\" : undefined,\n className,\n })\n )}\n onFocus={(e) => {\n setIsFocused(true);\n props.onFocus?.(e);\n }}\n placeholder={isFocused ? \" \" : placeholder}\n ref={ref}\n size={htmlSize}\n type={type}\n {...props}\n />\n {!!rightIcon && (\n <SlotPrimitive.Slot\n className={cn(\n \"absolute top-1/2 -translate-y-1/2 text-gray-950 dark:text-gray-300 [&:is(svg)]:pointer-events-none\",\n size === \"sm\" ? \"right-3 size-3\" : \"right-4 size-4\"\n )}\n >\n {rightIcon}\n </SlotPrimitive.Slot>\n )}\n </div>\n );\n};\n\ninterface ClearInputButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n ref?: Ref<HTMLButtonElement>;\n}\n\n/**\n * Clear/reset button designed for use as Input's rightIcon.\n * Displays an X icon and handles focus states.\n */\nconst ClearInputButton = ({\n className,\n ref,\n ...props\n}: ClearInputButtonProps) => (\n <button\n className={cn(\n \"absolute top-1/2 -translate-y-1/2 text-gray-950 dark:text-gray-300\",\n \"focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-gray-100\",\n \"rounded-full focus-visible:outline-none dark:focus-visible:ring-[var(--focus-ring)] dark:focus-visible:ring-offset-gray-800\",\n className\n )}\n ref={ref}\n type=\"button\"\n {...props}\n >\n <X className=\"absolute inset-0 size-full\" strokeWidth={3} />\n </button>\n);\n\nexport { ClearInputButton, Input, inputVariants };\n"],
4
+ "sourcesContent": ["/**\n * @module Input\n *\n * Styled text input with support for icons, sizes, and clear button.\n * Includes focus state management and dark mode support.\n *\n * @example\n * // Basic input\n * <Input placeholder=\"Enter your email\" type=\"email\" />\n *\n * @example\n * // With icons\n * <Input\n * leftIcon={<Search />}\n * rightIcon={<ClearInputButton onClick={clearValue} />}\n * placeholder=\"Search...\"\n * />\n *\n * @example\n * // Small size\n * <Input size=\"sm\" placeholder=\"Compact input\" />\n *\n * @example\n * // With clear button\n * const [value, setValue] = useState('');\n *\n * <Input\n * value={value}\n * onChange={(e) => setValue(e.target.value)}\n * rightIcon={\n * value && <ClearInputButton onClick={() => setValue('')} />\n * }\n * />\n */\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { X } from \"lucide-react\";\nimport { Slot as SlotPrimitive } from \"radix-ui\";\nimport type { Ref } from \"react\";\nimport { useState } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\nconst inputWrapperVariants = cva(\"relative flex w-full items-center\", {\n variants: {\n size: {\n auto: \"h-auto w-auto\",\n default: \"h-10\",\n sm: \"h-7\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n});\n\nconst inputVariants = cva(\n [\n \"w-full touch-manipulation self-stretch shadow-none outline-hidden outline-0 transition duration-200 ease-out disabled:cursor-not-allowed dark:disabled:cursor-not-allowed\",\n // text\n \"font-sans text-base text-black antialiased disabled:text-black/60 dark:text-white dark:disabled:text-white/60\",\n // placeholder\n \"placeholder-gray-700 placeholder:font-sans dark:placeholder-gray-200\",\n // background\n \"bg-white focus:bg-white enabled:hover:bg-white disabled:bg-white/60 dark:bg-black dark:disabled:bg-black/60 dark:focus:bg-black dark:enabled:hover:bg-black\",\n // borders (light)\n \"rounded-lg border border-gray-150 border-solid invalid:border-red invalid:hover:border-red focus:border-brand-primary enabled:hover:border-gray-200 enabled:focus:hover:border-brand-primary disabled:border-gray-150/60\", // borders light\n // borders (dark)\n \"dark:border-gray-800 dark:disabled:border-gray-900 dark:focus:border-white dark:enabled:hover:border-gray-700 dark:enabled:focus:hover:border-white dark:invalid:border-red dark:invalid:hover:border-red\", // borders dark\n ],\n {\n variants: {\n size: {\n default: \"px-4\",\n sm: \"px-3\",\n auto: \"px-4\",\n },\n hasLeftIcon: {\n true: \"\",\n false: \"\",\n },\n hasRightIcon: {\n true: \"\",\n false: \"\",\n },\n // Scoped to type=\"search\" only: the Keeper password manager extension\n // misidentifies inputs that style ::-webkit-search-cancel-button as\n // search fields and blocks paste, so non-search inputs must not match.\n type: {\n search: \"dark:[&::-webkit-search-cancel-button]:hidden\",\n },\n },\n compoundVariants: [\n {\n hasLeftIcon: true,\n size: \"default\",\n class: \"pl-10\",\n },\n {\n hasLeftIcon: true,\n size: \"sm\",\n class: \"pl-8\",\n },\n {\n hasRightIcon: true,\n size: \"default\",\n class: \"pr-10\",\n },\n {\n hasRightIcon: true,\n size: \"sm\",\n class: \"pr-8\",\n },\n ],\n defaultVariants: {\n size: \"default\",\n hasLeftIcon: false,\n hasRightIcon: false,\n },\n }\n);\n\ntype InputPropsWithoutSize = Omit<\n React.InputHTMLAttributes<HTMLInputElement>,\n \"size\"\n>;\n\ntype InputVariantsProps = VariantProps<typeof inputVariants>;\n\n// Omit internal-only variants from the public API. `type` is excluded so\n// consumers keep the full HTMLInputTypeAttribute union; CVA still picks up\n// the runtime value via the `type` argument passed in inputVariants().\ntype PublicInputVariantsProps = Omit<\n InputVariantsProps,\n \"hasLeftIcon\" | \"hasRightIcon\" | \"type\"\n>;\n\n/**\n * Props for the Input component.\n * @property size - Input size: `\"default\"`, `\"sm\"`, or `\"auto\"`\n * @property htmlSize - Native HTML size attribute for input width\n * @property leftIcon - Icon element displayed on the left side\n * @property rightIcon - Icon element displayed on the right side\n */\nexport interface InputProps\n extends InputPropsWithoutSize,\n PublicInputVariantsProps {\n htmlSize?: number;\n leftIcon?: React.ReactNode;\n ref?: Ref<HTMLInputElement>;\n rightIcon?: React.ReactNode;\n}\n\nconst Input = ({\n className,\n size,\n type = \"text\",\n htmlSize,\n leftIcon,\n rightIcon,\n placeholder,\n ref,\n ...props\n}: InputProps) => {\n const [isFocused, setIsFocused] = useState(false);\n\n return (\n // biome-ignore lint/a11y/noNoninteractiveElementInteractions: container needs onBlur to coordinate focus state across child input and icon slots\n // biome-ignore lint/a11y/noStaticElementInteractions: container needs onBlur to coordinate focus state across child input and icon slots\n <div\n className={cn(inputWrapperVariants({ size }))}\n onBlur={() => {\n setTimeout(() => {\n setIsFocused(false);\n }, 50);\n }}\n >\n {!!leftIcon && (\n <SlotPrimitive.Slot\n className={cn(\n \"absolute top-1/2 -translate-y-1/2 text-gray-950 dark:text-gray-300 [&:is(svg)]:pointer-events-none\",\n size === \"sm\" ? \"left-3 size-3\" : \"left-4 size-4\"\n )}\n >\n {leftIcon}\n </SlotPrimitive.Slot>\n )}\n <input\n className={cn(\n inputVariants({\n size,\n hasLeftIcon: !!leftIcon,\n hasRightIcon: !!rightIcon,\n type: type === \"search\" ? \"search\" : undefined,\n className,\n })\n )}\n onFocus={(e) => {\n setIsFocused(true);\n props.onFocus?.(e);\n }}\n placeholder={isFocused ? \" \" : placeholder}\n ref={ref}\n size={htmlSize}\n type={type}\n {...props}\n />\n {!!rightIcon && (\n <SlotPrimitive.Slot\n className={cn(\n \"absolute top-1/2 -translate-y-1/2 text-gray-950 dark:text-gray-300 [&:is(svg)]:pointer-events-none\",\n size === \"sm\" ? \"right-3 size-3\" : \"right-4 size-4\"\n )}\n >\n {rightIcon}\n </SlotPrimitive.Slot>\n )}\n </div>\n );\n};\n\ninterface ClearInputButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n ref?: Ref<HTMLButtonElement>;\n}\n\n/**\n * Clear/reset button designed for use as Input's rightIcon.\n * Displays an X icon and handles focus states.\n */\nconst ClearInputButton = ({\n className,\n ref,\n ...props\n}: ClearInputButtonProps) => (\n <button\n className={cn(\n \"absolute top-1/2 -translate-y-1/2 text-gray-950 dark:text-gray-300\",\n \"focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-gray-100\",\n \"rounded-full focus-visible:outline-hidden dark:focus-visible:ring-[var(--focus-ring)] dark:focus-visible:ring-offset-gray-800\",\n className\n )}\n ref={ref}\n type=\"button\"\n {...props}\n >\n <X className=\"absolute inset-0 size-full\" strokeWidth={3} />\n </button>\n);\n\nexport { ClearInputButton, Input, inputVariants };\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -16,7 +16,7 @@ const PopoverContent = ({
16
16
  {
17
17
  align,
18
18
  className: cn(
19
- "data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1 z-50 origin-[var(--radix-popover-content-transform-origin)] rounded-md border border-gray-150 border-solid bg-white fill-mode-forwards p-4 text-gray-950 shadow-md outline-none data-[state=closed]:animate-out data-[state=open]:animate-in data-[state=closed]:opacity-0 data-[state=open]:opacity-100 dark:border-gray-800 dark:bg-gray-950 dark:text-gray-50",
19
+ "data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1 z-50 origin-[var(--radix-popover-content-transform-origin)] rounded-md border border-gray-150 border-solid bg-white fill-mode-forwards p-4 text-gray-950 shadow-md outline-hidden data-[state=closed]:animate-out data-[state=open]:animate-in data-[state=closed]:opacity-0 data-[state=open]:opacity-100 dark:border-gray-800 dark:bg-gray-950 dark:text-gray-50",
20
20
  className
21
21
  ),
22
22
  ref,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/popover.tsx"],
4
- "sourcesContent": ["/**\n * @module Popover\n *\n * Floating content panel anchored to a trigger element. Built on Radix UI Popover primitive.\n * Supports controlled/uncontrolled modes, custom positioning, and focus management.\n *\n * @see {@link https://ui.shadcn.com/docs/components/popover Shadcn Popover}\n * @see {@link https://www.radix-ui.com/primitives/docs/components/popover Radix Popover}\n *\n * @example\n * // Basic popover\n * <Popover>\n * <PopoverTrigger asChild>\n * <Button>Open Popover</Button>\n * </PopoverTrigger>\n * <PopoverContent>\n * <p>Popover content here</p>\n * </PopoverContent>\n * </Popover>\n *\n * @example\n * // Controlled popover with custom positioning\n * const [open, setOpen] = useState(false);\n *\n * <Popover open={open} onOpenChange={setOpen}>\n * <PopoverTrigger>Settings</PopoverTrigger>\n * <PopoverContent align=\"start\" sideOffset={8}>\n * <SettingsForm onSave={() => setOpen(false)} />\n * </PopoverContent>\n * </Popover>\n *\n * @example\n * // With custom anchor point\n * <Popover>\n * <PopoverAnchor asChild>\n * <div>Anchor element (popover positions relative to this)</div>\n * </PopoverAnchor>\n * <PopoverTrigger>Open</PopoverTrigger>\n * <PopoverContent>Content</PopoverContent>\n * </Popover>\n */\nimport { Popover as PopoverPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\nimport type { Ref } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** Root component that manages popover open/closed state. */\nconst Popover = PopoverPrimitive.Root;\n\n/** Element that toggles the popover when clicked. Use `asChild` to wrap custom elements. */\nconst PopoverTrigger = PopoverPrimitive.Trigger;\n\n/** Alternative anchor point for popover positioning (separate from trigger). */\nconst PopoverAnchor = PopoverPrimitive.Anchor;\n\n/**\n * Popover content container. Animated on open/close.\n * @param align - Horizontal alignment: `\"start\"`, `\"center\"` (default), or `\"end\"`\n * @param sideOffset - Distance from anchor in pixels (default: 4)\n * @param forceMount - Keep mounted in DOM even when closed\n */\nconst PopoverContent = ({\n className,\n forceMount,\n align = \"center\",\n sideOffset = 4,\n ref,\n ...props\n}: React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> & {\n ref?: Ref<React.ElementRef<typeof PopoverPrimitive.Content>>;\n}) => (\n <PopoverPrimitive.Portal forceMount={forceMount}>\n <PopoverPrimitive.Content\n align={align}\n className={cn(\n \"data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1 z-50 origin-[var(--radix-popover-content-transform-origin)] rounded-md border border-gray-150 border-solid bg-white fill-mode-forwards p-4 text-gray-950 shadow-md outline-none data-[state=closed]:animate-out data-[state=open]:animate-in data-[state=closed]:opacity-0 data-[state=open]:opacity-100 dark:border-gray-800 dark:bg-gray-950 dark:text-gray-50\",\n className\n )}\n ref={ref}\n sideOffset={sideOffset}\n {...props}\n />\n </PopoverPrimitive.Portal>\n);\n\nexport { Popover, PopoverAnchor, PopoverContent, PopoverTrigger };\n"],
4
+ "sourcesContent": ["/**\n * @module Popover\n *\n * Floating content panel anchored to a trigger element. Built on Radix UI Popover primitive.\n * Supports controlled/uncontrolled modes, custom positioning, and focus management.\n *\n * @see {@link https://ui.shadcn.com/docs/components/popover Shadcn Popover}\n * @see {@link https://www.radix-ui.com/primitives/docs/components/popover Radix Popover}\n *\n * @example\n * // Basic popover\n * <Popover>\n * <PopoverTrigger asChild>\n * <Button>Open Popover</Button>\n * </PopoverTrigger>\n * <PopoverContent>\n * <p>Popover content here</p>\n * </PopoverContent>\n * </Popover>\n *\n * @example\n * // Controlled popover with custom positioning\n * const [open, setOpen] = useState(false);\n *\n * <Popover open={open} onOpenChange={setOpen}>\n * <PopoverTrigger>Settings</PopoverTrigger>\n * <PopoverContent align=\"start\" sideOffset={8}>\n * <SettingsForm onSave={() => setOpen(false)} />\n * </PopoverContent>\n * </Popover>\n *\n * @example\n * // With custom anchor point\n * <Popover>\n * <PopoverAnchor asChild>\n * <div>Anchor element (popover positions relative to this)</div>\n * </PopoverAnchor>\n * <PopoverTrigger>Open</PopoverTrigger>\n * <PopoverContent>Content</PopoverContent>\n * </Popover>\n */\nimport { Popover as PopoverPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\nimport type { Ref } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** Root component that manages popover open/closed state. */\nconst Popover = PopoverPrimitive.Root;\n\n/** Element that toggles the popover when clicked. Use `asChild` to wrap custom elements. */\nconst PopoverTrigger = PopoverPrimitive.Trigger;\n\n/** Alternative anchor point for popover positioning (separate from trigger). */\nconst PopoverAnchor = PopoverPrimitive.Anchor;\n\n/**\n * Popover content container. Animated on open/close.\n * @param align - Horizontal alignment: `\"start\"`, `\"center\"` (default), or `\"end\"`\n * @param sideOffset - Distance from anchor in pixels (default: 4)\n * @param forceMount - Keep mounted in DOM even when closed\n */\nconst PopoverContent = ({\n className,\n forceMount,\n align = \"center\",\n sideOffset = 4,\n ref,\n ...props\n}: React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> & {\n ref?: Ref<React.ElementRef<typeof PopoverPrimitive.Content>>;\n}) => (\n <PopoverPrimitive.Portal forceMount={forceMount}>\n <PopoverPrimitive.Content\n align={align}\n className={cn(\n \"data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1 z-50 origin-[var(--radix-popover-content-transform-origin)] rounded-md border border-gray-150 border-solid bg-white fill-mode-forwards p-4 text-gray-950 shadow-md outline-hidden data-[state=closed]:animate-out data-[state=open]:animate-in data-[state=closed]:opacity-0 data-[state=open]:opacity-100 dark:border-gray-800 dark:bg-gray-950 dark:text-gray-50\",\n className\n )}\n ref={ref}\n sideOffset={sideOffset}\n {...props}\n />\n </PopoverPrimitive.Portal>\n);\n\nexport { Popover, PopoverAnchor, PopoverContent, PopoverTrigger };\n"],
5
5
  "mappings": "AAyEI;AAhCJ,SAAS,WAAW,wBAAwB;AAI5C,SAAS,UAAU;AAGnB,MAAM,UAAU,iBAAiB;AAGjC,MAAM,iBAAiB,iBAAiB;AAGxC,MAAM,gBAAgB,iBAAiB;AAQvC,MAAM,iBAAiB,CAAC;AAAA,EACtB;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,aAAa;AAAA,EACb;AAAA,EACA,GAAG;AACL,MAGE,oBAAC,iBAAiB,QAAjB,EAAwB,YACvB;AAAA,EAAC,iBAAiB;AAAA,EAAjB;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACC,GAAG;AAAA;AACN,GACF;",
6
6
  "names": []
7
7
  }
@@ -46,7 +46,7 @@ const RadioGroupItem = ({ className, ref, ...props }) => {
46
46
  RadioGroupPrimitive.Item,
47
47
  {
48
48
  className: cn(
49
- "relative aspect-square size-4 h-4 w-4 rounded-full border border-gray-500 border-solid p-0.5 text-brand-primary ring-offset-brand-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-offset focus-visible:ring-[var(--focus-ring)] disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-brand-primary",
49
+ "relative aspect-square size-4 h-4 w-4 rounded-full border border-gray-500 border-solid p-0.5 text-brand-primary ring-offset-brand-primary focus:outline-hidden focus-visible:ring-2 focus-visible:ring-offset focus-visible:ring-[var(--focus-ring)] disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-brand-primary",
50
50
  className
51
51
  ),
52
52
  ref: setRefs,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/radio-group.tsx"],
4
- "sourcesContent": ["/**\n * @module RadioGroup\n *\n * Single-selection radio button group with animated indicators. Built on Radix UI Radio Group primitive.\n *\n * @see {@link https://ui.shadcn.com/docs/components/radio-group Shadcn Radio Group}\n * @see {@link https://www.radix-ui.com/primitives/docs/components/radio-group Radix Radio Group}\n *\n * @example\n * // Basic radio group\n * <RadioGroup defaultValue=\"option1\">\n * <div className=\"flex items-center gap-2\">\n * <RadioGroupItem value=\"option1\" id=\"option1\" />\n * <Label htmlFor=\"option1\">Option 1</Label>\n * </div>\n * <div className=\"flex items-center gap-2\">\n * <RadioGroupItem value=\"option2\" id=\"option2\" />\n * <Label htmlFor=\"option2\">Option 2</Label>\n * </div>\n * </RadioGroup>\n *\n * @example\n * // Controlled radio group\n * const [value, setValue] = useState(\"default\");\n *\n * <RadioGroup value={value} onValueChange={setValue}>\n * <RadioGroupItem value=\"a\" id=\"a\" />\n * <RadioGroupItem value=\"b\" id=\"b\" />\n * </RadioGroup>\n */\nimport { Circle } from \"lucide-react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport { RadioGroup as RadioGroupPrimitive } from \"radix-ui\";\nimport type { Ref } from \"react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\ninterface RadioGroupProps\n extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root> {\n ref?: Ref<React.ElementRef<typeof RadioGroupPrimitive.Root>>;\n}\n\n/** Container for radio items. Manages selection state. */\nconst RadioGroup = ({ className, ref, ...props }: RadioGroupProps) => (\n <RadioGroupPrimitive.Root\n className={cn(\"grid gap-2\", className)}\n {...props}\n ref={ref}\n />\n);\n\ninterface RadioGroupItemProps\n extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item> {\n ref?: Ref<React.ElementRef<typeof RadioGroupPrimitive.Item>>;\n}\n\n/** Individual radio button with animated selection indicator. */\nconst RadioGroupItem = ({ className, ref, ...props }: RadioGroupItemProps) => {\n const [isChecked, setIsChecked] = React.useState(false);\n const itemRef = React.useRef<HTMLButtonElement | null>(null);\n\n React.useEffect(() => {\n const observer = new MutationObserver((mutations) => {\n mutations.forEach((mutation) => {\n if (\n mutation.type === \"attributes\" &&\n mutation.attributeName === \"data-state\"\n ) {\n const newState = itemRef.current?.getAttribute(\"data-state\");\n\n setIsChecked(newState === \"checked\");\n }\n });\n });\n\n if (itemRef.current) {\n observer.observe(itemRef.current, { attributes: true });\n }\n\n return () => {\n observer.disconnect();\n };\n }, []);\n\n // Forward the ref to both our local ref and the passed ref\n const setRefs = React.useCallback(\n (element: HTMLButtonElement | null) => {\n itemRef.current = element;\n\n // Handle function refs\n if (typeof ref === \"function\") {\n ref(element);\n } else if (ref && \"current\" in ref) {\n ref.current = element;\n }\n },\n [ref]\n );\n\n return (\n <RadioGroupPrimitive.Item\n className={cn(\n \"relative aspect-square size-4 h-4 w-4 rounded-full border border-gray-500 border-solid p-0.5 text-brand-primary ring-offset-brand-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-offset focus-visible:ring-[var(--focus-ring)] disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-brand-primary\",\n className\n )}\n ref={setRefs}\n {...props}\n >\n <AnimatePresence>\n {isChecked && (\n <motion.div\n animate={{ scale: 2, opacity: 0 }}\n className=\"absolute inset-0 z-0 rounded-full bg-brand-primary\"\n exit={{ scale: 0, opacity: 0 }}\n initial={{ scale: 0, opacity: 0.5 }}\n transition={{ duration: 0.4 }}\n />\n )}\n </AnimatePresence>\n <motion.div\n animate={isChecked ? { scale: 1.1 } : { scale: 1 }}\n className=\"relative\"\n transition={{ type: \"spring\", stiffness: 300, damping: 20 }}\n >\n <RadioGroupPrimitive.Indicator className=\"flex items-center justify-center\">\n <Circle className=\"size-2.5 fill-current text-current\" />\n </RadioGroupPrimitive.Indicator>\n </motion.div>\n </RadioGroupPrimitive.Item>\n );\n};\n\nexport { RadioGroup, RadioGroupItem };\n"],
4
+ "sourcesContent": ["/**\n * @module RadioGroup\n *\n * Single-selection radio button group with animated indicators. Built on Radix UI Radio Group primitive.\n *\n * @see {@link https://ui.shadcn.com/docs/components/radio-group Shadcn Radio Group}\n * @see {@link https://www.radix-ui.com/primitives/docs/components/radio-group Radix Radio Group}\n *\n * @example\n * // Basic radio group\n * <RadioGroup defaultValue=\"option1\">\n * <div className=\"flex items-center gap-2\">\n * <RadioGroupItem value=\"option1\" id=\"option1\" />\n * <Label htmlFor=\"option1\">Option 1</Label>\n * </div>\n * <div className=\"flex items-center gap-2\">\n * <RadioGroupItem value=\"option2\" id=\"option2\" />\n * <Label htmlFor=\"option2\">Option 2</Label>\n * </div>\n * </RadioGroup>\n *\n * @example\n * // Controlled radio group\n * const [value, setValue] = useState(\"default\");\n *\n * <RadioGroup value={value} onValueChange={setValue}>\n * <RadioGroupItem value=\"a\" id=\"a\" />\n * <RadioGroupItem value=\"b\" id=\"b\" />\n * </RadioGroup>\n */\nimport { Circle } from \"lucide-react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport { RadioGroup as RadioGroupPrimitive } from \"radix-ui\";\nimport type { Ref } from \"react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\ninterface RadioGroupProps\n extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root> {\n ref?: Ref<React.ElementRef<typeof RadioGroupPrimitive.Root>>;\n}\n\n/** Container for radio items. Manages selection state. */\nconst RadioGroup = ({ className, ref, ...props }: RadioGroupProps) => (\n <RadioGroupPrimitive.Root\n className={cn(\"grid gap-2\", className)}\n {...props}\n ref={ref}\n />\n);\n\ninterface RadioGroupItemProps\n extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item> {\n ref?: Ref<React.ElementRef<typeof RadioGroupPrimitive.Item>>;\n}\n\n/** Individual radio button with animated selection indicator. */\nconst RadioGroupItem = ({ className, ref, ...props }: RadioGroupItemProps) => {\n const [isChecked, setIsChecked] = React.useState(false);\n const itemRef = React.useRef<HTMLButtonElement | null>(null);\n\n React.useEffect(() => {\n const observer = new MutationObserver((mutations) => {\n mutations.forEach((mutation) => {\n if (\n mutation.type === \"attributes\" &&\n mutation.attributeName === \"data-state\"\n ) {\n const newState = itemRef.current?.getAttribute(\"data-state\");\n\n setIsChecked(newState === \"checked\");\n }\n });\n });\n\n if (itemRef.current) {\n observer.observe(itemRef.current, { attributes: true });\n }\n\n return () => {\n observer.disconnect();\n };\n }, []);\n\n // Forward the ref to both our local ref and the passed ref\n const setRefs = React.useCallback(\n (element: HTMLButtonElement | null) => {\n itemRef.current = element;\n\n // Handle function refs\n if (typeof ref === \"function\") {\n ref(element);\n } else if (ref && \"current\" in ref) {\n ref.current = element;\n }\n },\n [ref]\n );\n\n return (\n <RadioGroupPrimitive.Item\n className={cn(\n \"relative aspect-square size-4 h-4 w-4 rounded-full border border-gray-500 border-solid p-0.5 text-brand-primary ring-offset-brand-primary focus:outline-hidden focus-visible:ring-2 focus-visible:ring-offset focus-visible:ring-[var(--focus-ring)] disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-brand-primary\",\n className\n )}\n ref={setRefs}\n {...props}\n >\n <AnimatePresence>\n {isChecked && (\n <motion.div\n animate={{ scale: 2, opacity: 0 }}\n className=\"absolute inset-0 z-0 rounded-full bg-brand-primary\"\n exit={{ scale: 0, opacity: 0 }}\n initial={{ scale: 0, opacity: 0.5 }}\n transition={{ duration: 0.4 }}\n />\n )}\n </AnimatePresence>\n <motion.div\n animate={isChecked ? { scale: 1.1 } : { scale: 1 }}\n className=\"relative\"\n transition={{ type: \"spring\", stiffness: 300, damping: 20 }}\n >\n <RadioGroupPrimitive.Indicator className=\"flex items-center justify-center\">\n <Circle className=\"size-2.5 fill-current text-current\" />\n </RadioGroupPrimitive.Indicator>\n </motion.div>\n </RadioGroupPrimitive.Item>\n );\n};\n\nexport { RadioGroup, RadioGroupItem };\n"],
5
5
  "mappings": "AA6CE,cAwDE,YAxDF;AAfF,SAAS,cAAc;AACvB,SAAS,iBAAiB,cAAc;AACxC,SAAS,cAAc,2BAA2B;AAElD,YAAY,WAAW;AAEvB,SAAS,UAAU;AAQnB,MAAM,aAAa,CAAC,EAAE,WAAW,KAAK,GAAG,MAAM,MAC7C;AAAA,EAAC,oBAAoB;AAAA,EAApB;AAAA,IACC,WAAW,GAAG,cAAc,SAAS;AAAA,IACpC,GAAG;AAAA,IACJ;AAAA;AACF;AASF,MAAM,iBAAiB,CAAC,EAAE,WAAW,KAAK,GAAG,MAAM,MAA2B;AAC5E,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,KAAK;AACtD,QAAM,UAAU,MAAM,OAAiC,IAAI;AAE3D,QAAM,UAAU,MAAM;AACpB,UAAM,WAAW,IAAI,iBAAiB,CAAC,cAAc;AACnD,gBAAU,QAAQ,CAAC,aAAa;AAC9B,YACE,SAAS,SAAS,gBAClB,SAAS,kBAAkB,cAC3B;AACA,gBAAM,WAAW,QAAQ,SAAS,aAAa,YAAY;AAE3D,uBAAa,aAAa,SAAS;AAAA,QACrC;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,QAAI,QAAQ,SAAS;AACnB,eAAS,QAAQ,QAAQ,SAAS,EAAE,YAAY,KAAK,CAAC;AAAA,IACxD;AAEA,WAAO,MAAM;AACX,eAAS,WAAW;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,QAAM,UAAU,MAAM;AAAA,IACpB,CAAC,YAAsC;AACrC,cAAQ,UAAU;AAGlB,UAAI,OAAO,QAAQ,YAAY;AAC7B,YAAI,OAAO;AAAA,MACb,WAAW,OAAO,aAAa,KAAK;AAClC,YAAI,UAAU;AAAA,MAChB;AAAA,IACF;AAAA,IACA,CAAC,GAAG;AAAA,EACN;AAEA,SACE;AAAA,IAAC,oBAAoB;AAAA,IAApB;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACA,KAAK;AAAA,MACJ,GAAG;AAAA,MAEJ;AAAA,4BAAC,mBACE,uBACC;AAAA,UAAC,OAAO;AAAA,UAAP;AAAA,YACC,SAAS,EAAE,OAAO,GAAG,SAAS,EAAE;AAAA,YAChC,WAAU;AAAA,YACV,MAAM,EAAE,OAAO,GAAG,SAAS,EAAE;AAAA,YAC7B,SAAS,EAAE,OAAO,GAAG,SAAS,IAAI;AAAA,YAClC,YAAY,EAAE,UAAU,IAAI;AAAA;AAAA,QAC9B,GAEJ;AAAA,QACA;AAAA,UAAC,OAAO;AAAA,UAAP;AAAA,YACC,SAAS,YAAY,EAAE,OAAO,IAAI,IAAI,EAAE,OAAO,EAAE;AAAA,YACjD,WAAU;AAAA,YACV,YAAY,EAAE,MAAM,UAAU,WAAW,KAAK,SAAS,GAAG;AAAA,YAE1D,8BAAC,oBAAoB,WAApB,EAA8B,WAAU,oCACvC,8BAAC,UAAO,WAAU,sCAAqC,GACzD;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -259,7 +259,7 @@ const ScrollDrum = ({
259
259
  "aria-label": ariaLabel,
260
260
  "aria-orientation": "vertical",
261
261
  className: cn(
262
- "relative h-full w-full cursor-grab touch-none select-none overflow-hidden bg-white outline-none active:cursor-grabbing focus-visible:[box-shadow:inset_0_0_0_2px_var(--brand-primary)] dark:bg-gray-900",
262
+ "relative h-full w-full cursor-grab touch-none select-none overflow-hidden bg-white outline-hidden active:cursor-grabbing focus-visible:[box-shadow:inset_0_0_0_2px_var(--brand-primary)] dark:bg-gray-900",
263
263
  className
264
264
  ),
265
265
  onKeyDown,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/scroll-drum.tsx"],
4
- "sourcesContent": ["/**\n * @module ScrollDrum\n *\n * iOS-style picker columns for selecting a value from a constrained list \u2014\n * durations, time, dates, BPM, etc. Supports wheel/trackpad scrolling, mouse\n * and touch drag with momentum, click-to-center, full keyboard control, and\n * optional infinite looping.\n *\n * @example\n * // Single drum: count-in bars\n * const [val, setVal] = useState(\"8\");\n * const items = Array.from({ length: 31 }, (_, i) => String(i));\n *\n * <ScrollDrumGroup>\n * <ScrollDrumColumn label=\"bars\">\n * <ScrollDrum items={items} value={val} onChange={setVal} ariaLabel=\"Bars\" />\n * </ScrollDrumColumn>\n * </ScrollDrumGroup>\n *\n * @example\n * // 12-hour time picker with separator\n * <ScrollDrumGroup separator=\":\">\n * <ScrollDrumColumn label=\"hour\">\n * <ScrollDrum items={hours} value={h} onChange={setH} ariaLabel=\"Hour\" />\n * </ScrollDrumColumn>\n * <ScrollDrumColumn label=\"min\">\n * <ScrollDrum items={minutes} value={m} onChange={setM} ariaLabel=\"Minute\" />\n * </ScrollDrumColumn>\n * <ScrollDrumColumn label=\"\">\n * <ScrollDrum items={[\"AM\", \"PM\"]} value={p} onChange={setP} loop={false} />\n * </ScrollDrumColumn>\n * </ScrollDrumGroup>\n */\nimport {\n Children,\n Fragment,\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n type PointerEvent as ReactPointerEvent,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\nconst DEFAULT_ITEM_HEIGHT = 52;\nconst DEFAULT_VISIBLE = 3;\nconst DEFAULT_MAX_CHARS = 4;\n\nconst SNAP_DURATION_MS = 280;\nconst WHEEL_SETTLE_MS = 110;\nconst COAST_FACTOR = 220 * 0.55;\n\nconst clamp = (n: number, lo: number, hi: number): number =>\n Math.max(lo, Math.min(hi, n));\n\n// Positive modulo (handles negatives) \u2014 required for stable wrap math.\nconst pmod = (n: number, m: number): number => ((n % m) + m) % m;\n\ninterface ScrollDrumProps {\n /** Accessible name for the listbox. */\n ariaLabel?: string;\n /** Additional class names merged onto the drum element. */\n className?: string;\n /** Vertical pixel size of one row slot. Defaults to 52. */\n itemHeight?: number;\n /** Ordered list of selectable strings. Order is the visual order. */\n items: string[];\n /** When `true` (default), scrolling past the end wraps to the start. */\n loop?: boolean;\n /** Hard character cap per item. Long labels are truncated for layout. */\n maxChars?: number;\n /** Fires with `(newValue, newIndex)` when the user lands on a new row. */\n onChange?: (value: string, index: number) => void;\n /** Currently selected item. Must exist in `items`. */\n value: string;\n /** How many rows are visible at once (odd numbers center cleanly). */\n visibleCount?: number;\n}\n\n/**\n * A single scrollable column. Designed to be wrapped in a {@link ScrollDrumColumn}\n * and grouped via {@link ScrollDrumGroup}.\n */\nconst ScrollDrum = ({\n items,\n value,\n onChange,\n itemHeight = DEFAULT_ITEM_HEIGHT,\n visibleCount = DEFAULT_VISIBLE,\n loop: loopProp = true,\n maxChars = DEFAULT_MAX_CHARS,\n ariaLabel,\n className,\n}: ScrollDrumProps): ReactNode => {\n const uid = useId();\n const optionId = (idx: number): string => `${uid}-opt-${idx}`;\n const containerRef = useRef<HTMLDivElement | null>(null);\n const animRef = useRef<number>(0);\n const wheelTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const dragRef = useRef({\n active: false,\n startY: 0,\n startIndex: 0,\n lastY: 0,\n lastT: 0,\n vy: 0,\n moved: false,\n });\n\n const N = items.length;\n // Looping past zero items would call pmod(n, 0) and yield NaN, breaking the\n // render math. Force non-looping internally when there's nothing to loop\n // through; the render bails on N === 0.\n const loop = loopProp && N > 1;\n\n const truncate = useCallback(\n (label: string): string =>\n label.length > maxChars ? label.slice(0, maxChars) : label,\n [maxChars]\n );\n\n const initialIndex = Math.max(0, items.indexOf(value));\n const [floatIndex, setFloatIndex] = useState<number>(initialIndex);\n const floatIndexRef = useRef<number>(floatIndex);\n useEffect(() => {\n floatIndexRef.current = floatIndex;\n }, [floatIndex]);\n\n const resolveIndex = useCallback(\n (f: number): number => {\n if (loop) {\n return pmod(Math.round(f), N);\n }\n return clamp(Math.round(f), 0, N - 1);\n },\n [loop, N]\n );\n\n const animateTo = useCallback(\n (targetFloat: number): void => {\n cancelAnimationFrame(animRef.current);\n const start = performance.now();\n const from = floatIndexRef.current;\n const ease = (t: number): number => 1 - (1 - t) ** 3;\n const step = (): void => {\n const t = clamp((performance.now() - start) / SNAP_DURATION_MS, 0, 1);\n const v = from + (targetFloat - from) * ease(t);\n setFloatIndex(v);\n if (t < 1) {\n animRef.current = requestAnimationFrame(step);\n } else {\n const final = loop\n ? pmod(targetFloat, N)\n : clamp(targetFloat, 0, N - 1);\n setFloatIndex(final);\n const idx = resolveIndex(final);\n const next = items[idx];\n if (next !== undefined && next !== value) {\n onChange?.(next, idx);\n }\n }\n };\n animRef.current = requestAnimationFrame(step);\n },\n [items, loop, N, onChange, resolveIndex, value]\n );\n\n // External value -> internal float, animated on the shortest path. Tracked\n // by value's resolved index rather than the items reference, so an unstable\n // `items` array (fresh ref every render) doesn't cancel an in-flight\n // animation, but a real reorder (where `value` lands at a different index)\n // still resyncs the drum.\n const targetIdx = N > 0 ? Math.max(0, items.indexOf(value)) : 0;\n const lastSyncedTargetIdx = useRef<number>(targetIdx);\n useEffect(() => {\n if (targetIdx === lastSyncedTargetIdx.current) {\n return;\n }\n lastSyncedTargetIdx.current = targetIdx;\n if (N === 0) {\n return;\n }\n const cur = floatIndexRef.current;\n let target = targetIdx;\n if (loop) {\n const cycles = Math.round((cur - targetIdx) / N);\n target = targetIdx + cycles * N;\n }\n if (Math.abs(target - cur) > 0.001) {\n animateTo(target);\n }\n // animateTo intentionally omitted to avoid retriggering on every render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [targetIdx]);\n\n // Wheel: native non-passive listener so we can preventDefault.\n useEffect(() => {\n const el = containerRef.current;\n if (!el) {\n return;\n }\n const onWheel = (e: WheelEvent): void => {\n e.preventDefault();\n cancelAnimationFrame(animRef.current);\n const delta = e.deltaY / itemHeight;\n const raw = floatIndexRef.current + delta;\n setFloatIndex(loop ? raw : clamp(raw, 0, N - 1));\n if (wheelTimer.current) {\n clearTimeout(wheelTimer.current);\n }\n wheelTimer.current = setTimeout(() => {\n const cur = floatIndexRef.current;\n const target = loop\n ? Math.round(cur)\n : clamp(Math.round(cur), 0, N - 1);\n animateTo(target);\n }, WHEEL_SETTLE_MS);\n };\n el.addEventListener(\"wheel\", onWheel, { passive: false });\n return () => {\n el.removeEventListener(\"wheel\", onWheel);\n if (wheelTimer.current) {\n clearTimeout(wheelTimer.current);\n }\n };\n }, [animateTo, N, itemHeight, loop]);\n\n useEffect(\n () => () => {\n cancelAnimationFrame(animRef.current);\n },\n []\n );\n\n const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>): void => {\n if (e.pointerType === \"mouse\" && e.button !== 0) {\n return;\n }\n cancelAnimationFrame(animRef.current);\n containerRef.current?.setPointerCapture(e.pointerId);\n dragRef.current = {\n active: true,\n startY: e.clientY,\n startIndex: floatIndexRef.current,\n lastY: e.clientY,\n lastT: performance.now(),\n vy: 0,\n moved: false,\n };\n };\n\n const onPointerMove = (e: ReactPointerEvent<HTMLDivElement>): void => {\n const d = dragRef.current;\n if (!d.active) {\n return;\n }\n const dy = e.clientY - d.startY;\n if (Math.abs(dy) > 3) {\n d.moved = true;\n }\n const raw = d.startIndex - dy / itemHeight;\n setFloatIndex(loop ? raw : clamp(raw, 0, N - 1));\n const now = performance.now();\n const dt = Math.max(1, now - d.lastT);\n d.vy = (e.clientY - d.lastY) / dt;\n d.lastY = e.clientY;\n d.lastT = now;\n };\n\n const onPointerUp = (e: ReactPointerEvent<HTMLDivElement>): void => {\n const d = dragRef.current;\n if (!d.active) {\n return;\n }\n d.active = false;\n try {\n containerRef.current?.releasePointerCapture(e.pointerId);\n } catch {\n /* pointer may already be released */\n }\n const coastPx = d.vy * COAST_FACTOR;\n const projected = floatIndexRef.current - coastPx / itemHeight;\n const target = loop\n ? Math.round(projected)\n : clamp(Math.round(projected), 0, N - 1);\n animateTo(target);\n };\n\n const onKeyDown = (e: ReactKeyboardEvent<HTMLDivElement>): void => {\n let target = Math.round(floatIndexRef.current);\n if (e.key === \"ArrowUp\") {\n target -= 1;\n } else if (e.key === \"ArrowDown\") {\n target += 1;\n } else if (e.key === \"PageUp\") {\n target -= 5;\n } else if (e.key === \"PageDown\") {\n target += 5;\n } else if (e.key === \"Home\") {\n const cur = Math.round(floatIndexRef.current);\n target = loop ? cur - pmod(cur, N) : 0;\n } else if (e.key === \"End\") {\n const cur = Math.round(floatIndexRef.current);\n target = loop ? cur - pmod(cur, N) + N - 1 : N - 1;\n } else {\n return;\n }\n e.preventDefault();\n if (!loop) {\n target = clamp(target, 0, N - 1);\n }\n animateTo(target);\n };\n\n const halfVisible = Math.floor(visibleCount / 2);\n const windowRadius = halfVisible + 2;\n const centerInt = Math.round(floatIndex);\n\n const visibleItems: Array<{\n key: string;\n itemIdx: number;\n offsetSlot: number;\n label: string;\n }> = [];\n for (let off = -windowRadius; off <= windowRadius; off++) {\n const rawIdx = centerInt + off;\n if (!loop && (rawIdx < 0 || rawIdx >= N)) {\n continue;\n }\n const itemIdx = pmod(rawIdx, N);\n const label = items[itemIdx];\n if (label === undefined) {\n continue;\n }\n visibleItems.push({\n key: String(rawIdx),\n itemIdx,\n offsetSlot: rawIdx,\n label,\n });\n }\n\n const rowOffset = (slot: number): number => (slot - floatIndex) * itemHeight;\n const selectedIndex = N > 0 ? resolveIndex(floatIndex) : 0;\n\n if (N === 0) {\n return (\n <div\n aria-label={ariaLabel}\n className={cn(\n \"relative h-full w-full overflow-hidden bg-white dark:bg-gray-900\",\n className\n )}\n role=\"listbox\"\n />\n );\n }\n\n return (\n <div\n aria-activedescendant={optionId(selectedIndex)}\n aria-label={ariaLabel}\n aria-orientation=\"vertical\"\n className={cn(\n \"relative h-full w-full cursor-grab touch-none select-none overflow-hidden bg-white outline-none active:cursor-grabbing focus-visible:[box-shadow:inset_0_0_0_2px_var(--brand-primary)] dark:bg-gray-900\",\n className\n )}\n onKeyDown={onKeyDown}\n onPointerCancel={onPointerUp}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n ref={containerRef}\n role=\"listbox\"\n style={{ \"--sd-item-h\": `${itemHeight}px` } as React.CSSProperties}\n tabIndex={0}\n >\n <div\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-x-0 top-[-1px] z-[2] h-9 bg-gradient-to-b from-white from-[12%] to-transparent dark:from-gray-900\"\n />\n <div\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-x-0 bottom-[-1px] z-[2] h-9 bg-gradient-to-t from-white from-[12%] to-transparent dark:from-gray-900\"\n />\n <div\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-x-2 top-1/2 z-0 h-[41px] -translate-y-1/2 rounded-sm border border-brand-primary bg-brand-secondary\"\n />\n\n <div className=\"pointer-events-none absolute inset-0\">\n {visibleItems.map(({ key, itemIdx, offsetSlot, label }) => {\n const isSelected =\n itemIdx === selectedIndex &&\n Math.abs(offsetSlot - floatIndex) <= 0.5;\n return (\n <button\n aria-selected={isSelected}\n className={cn(\n \"pointer-events-auto absolute top-1/2 left-1/2 z-[1] m-0 box-border flex h-[var(--sd-item-h,52px)] w-full cursor-pointer items-center justify-center overflow-hidden border-0 bg-transparent px-1.5 py-0 transition-colors duration-150\",\n isSelected\n ? \"text-brand-primary-hover dark:text-white\"\n : \"text-gray-600 dark:text-gray-300\"\n )}\n id={isSelected ? optionId(itemIdx) : undefined}\n key={key}\n onClick={() => {\n if (dragRef.current.moved) {\n return;\n }\n animateTo(offsetSlot);\n }}\n role=\"option\"\n style={{\n transform: `translate3d(-50%, calc(-50% + ${rowOffset(offsetSlot)}px), 0)`,\n }}\n tabIndex={-1}\n type=\"button\"\n >\n <span className=\"inline-block whitespace-nowrap text-center font-sans font-semibold text-[30px] leading-9 tracking-[-1px] [font-feature-settings:'ss03']\">\n {truncate(label)}\n </span>\n </button>\n );\n })}\n </div>\n </div>\n );\n};\n\ninterface ScrollDrumGroupProps {\n /** One or more {@link ScrollDrumColumn} children. */\n children: ReactNode;\n /** Additional class names merged onto the group container. */\n className?: string;\n /** Glyph rendered between adjacent columns. Ignored when `showSeparators` is false. */\n separator?: string;\n /** When `false`, the gutter between columns is preserved but no glyph is rendered. */\n showSeparators?: boolean;\n}\n\n/**\n * Gray container that holds one or more {@link ScrollDrumColumn} children.\n * Optionally renders a glyph between columns (e.g. `:` for time, `/` for date).\n */\nconst ScrollDrumGroup = ({\n children,\n separator = \":\",\n showSeparators = true,\n className,\n}: ScrollDrumGroupProps): ReactNode => {\n const cols = Children.toArray(children);\n return (\n <div\n className={cn(\n \"inline-flex flex-row items-center justify-center rounded-lg bg-gray-100 px-8 pt-6 pb-4 dark:bg-gray-800\",\n className\n )}\n >\n {cols.map((col, idx) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: columns are static and not reordered\n <Fragment key={idx}>\n {col}\n {idx < cols.length - 1 && (\n <div\n aria-hidden=\"true\"\n className=\"flex h-[120px] w-8 flex-none items-center justify-center self-start\"\n >\n {showSeparators && (\n <span className=\"text-center font-sans font-semibold text-[36px] text-gray-600 leading-10 tracking-[-1.5px] [font-feature-settings:'ss03'] dark:text-gray-400\">\n {separator}\n </span>\n )}\n </div>\n )}\n </Fragment>\n ))}\n </div>\n );\n};\n\ninterface ScrollDrumColumnProps {\n /** Should be a single {@link ScrollDrum}. */\n children: ReactNode;\n /** Additional class names merged onto the column wrapper. */\n className?: string;\n /** Caption rendered below the drum slab. Pass `\"\"` for an invisible spacer. */\n label?: string;\n /** Hard character cap that drives the auto-computed column width. */\n maxChars?: number;\n /** Explicit pixel width override. When omitted, scales with `maxChars`. */\n width?: number;\n}\n\n/**\n * Pairs a {@link ScrollDrum} with an optional caption underneath. When `width`\n * is omitted the column auto-sizes via `Math.max(72, 24 + maxChars * 16)`, so\n * a 4-char drum (e.g. `\"2026\"`) lands at 88px and a 2-char drum stays at the\n * 72px floor.\n */\nconst ScrollDrumColumn = ({\n label,\n width,\n maxChars = DEFAULT_MAX_CHARS,\n children,\n className,\n}: ScrollDrumColumnProps): ReactNode => {\n const computed = width ?? Math.max(72, 24 + maxChars * 16);\n return (\n <div\n className={cn(\"flex flex-none flex-col gap-2 p-0\", className)}\n style={{ width: computed }}\n >\n <div className=\"flex h-[120px] flex-none items-center justify-center bg-white dark:bg-gray-900\">\n {children}\n </div>\n {label !== undefined && (\n <div className=\"h-6 text-center font-sans font-semibold text-base text-gray-600 leading-6 [font-feature-settings:'ss03'] dark:text-gray-300\">\n {label || \"\u00A0\"}\n </div>\n )}\n </div>\n );\n};\n\nexport type { ScrollDrumColumnProps, ScrollDrumGroupProps, ScrollDrumProps };\nexport { ScrollDrum, ScrollDrumColumn, ScrollDrumGroup };\n"],
4
+ "sourcesContent": ["/**\n * @module ScrollDrum\n *\n * iOS-style picker columns for selecting a value from a constrained list \u2014\n * durations, time, dates, BPM, etc. Supports wheel/trackpad scrolling, mouse\n * and touch drag with momentum, click-to-center, full keyboard control, and\n * optional infinite looping.\n *\n * @example\n * // Single drum: count-in bars\n * const [val, setVal] = useState(\"8\");\n * const items = Array.from({ length: 31 }, (_, i) => String(i));\n *\n * <ScrollDrumGroup>\n * <ScrollDrumColumn label=\"bars\">\n * <ScrollDrum items={items} value={val} onChange={setVal} ariaLabel=\"Bars\" />\n * </ScrollDrumColumn>\n * </ScrollDrumGroup>\n *\n * @example\n * // 12-hour time picker with separator\n * <ScrollDrumGroup separator=\":\">\n * <ScrollDrumColumn label=\"hour\">\n * <ScrollDrum items={hours} value={h} onChange={setH} ariaLabel=\"Hour\" />\n * </ScrollDrumColumn>\n * <ScrollDrumColumn label=\"min\">\n * <ScrollDrum items={minutes} value={m} onChange={setM} ariaLabel=\"Minute\" />\n * </ScrollDrumColumn>\n * <ScrollDrumColumn label=\"\">\n * <ScrollDrum items={[\"AM\", \"PM\"]} value={p} onChange={setP} loop={false} />\n * </ScrollDrumColumn>\n * </ScrollDrumGroup>\n */\nimport {\n Children,\n Fragment,\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n type PointerEvent as ReactPointerEvent,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\nconst DEFAULT_ITEM_HEIGHT = 52;\nconst DEFAULT_VISIBLE = 3;\nconst DEFAULT_MAX_CHARS = 4;\n\nconst SNAP_DURATION_MS = 280;\nconst WHEEL_SETTLE_MS = 110;\nconst COAST_FACTOR = 220 * 0.55;\n\nconst clamp = (n: number, lo: number, hi: number): number =>\n Math.max(lo, Math.min(hi, n));\n\n// Positive modulo (handles negatives) \u2014 required for stable wrap math.\nconst pmod = (n: number, m: number): number => ((n % m) + m) % m;\n\ninterface ScrollDrumProps {\n /** Accessible name for the listbox. */\n ariaLabel?: string;\n /** Additional class names merged onto the drum element. */\n className?: string;\n /** Vertical pixel size of one row slot. Defaults to 52. */\n itemHeight?: number;\n /** Ordered list of selectable strings. Order is the visual order. */\n items: string[];\n /** When `true` (default), scrolling past the end wraps to the start. */\n loop?: boolean;\n /** Hard character cap per item. Long labels are truncated for layout. */\n maxChars?: number;\n /** Fires with `(newValue, newIndex)` when the user lands on a new row. */\n onChange?: (value: string, index: number) => void;\n /** Currently selected item. Must exist in `items`. */\n value: string;\n /** How many rows are visible at once (odd numbers center cleanly). */\n visibleCount?: number;\n}\n\n/**\n * A single scrollable column. Designed to be wrapped in a {@link ScrollDrumColumn}\n * and grouped via {@link ScrollDrumGroup}.\n */\nconst ScrollDrum = ({\n items,\n value,\n onChange,\n itemHeight = DEFAULT_ITEM_HEIGHT,\n visibleCount = DEFAULT_VISIBLE,\n loop: loopProp = true,\n maxChars = DEFAULT_MAX_CHARS,\n ariaLabel,\n className,\n}: ScrollDrumProps): ReactNode => {\n const uid = useId();\n const optionId = (idx: number): string => `${uid}-opt-${idx}`;\n const containerRef = useRef<HTMLDivElement | null>(null);\n const animRef = useRef<number>(0);\n const wheelTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const dragRef = useRef({\n active: false,\n startY: 0,\n startIndex: 0,\n lastY: 0,\n lastT: 0,\n vy: 0,\n moved: false,\n });\n\n const N = items.length;\n // Looping past zero items would call pmod(n, 0) and yield NaN, breaking the\n // render math. Force non-looping internally when there's nothing to loop\n // through; the render bails on N === 0.\n const loop = loopProp && N > 1;\n\n const truncate = useCallback(\n (label: string): string =>\n label.length > maxChars ? label.slice(0, maxChars) : label,\n [maxChars]\n );\n\n const initialIndex = Math.max(0, items.indexOf(value));\n const [floatIndex, setFloatIndex] = useState<number>(initialIndex);\n const floatIndexRef = useRef<number>(floatIndex);\n useEffect(() => {\n floatIndexRef.current = floatIndex;\n }, [floatIndex]);\n\n const resolveIndex = useCallback(\n (f: number): number => {\n if (loop) {\n return pmod(Math.round(f), N);\n }\n return clamp(Math.round(f), 0, N - 1);\n },\n [loop, N]\n );\n\n const animateTo = useCallback(\n (targetFloat: number): void => {\n cancelAnimationFrame(animRef.current);\n const start = performance.now();\n const from = floatIndexRef.current;\n const ease = (t: number): number => 1 - (1 - t) ** 3;\n const step = (): void => {\n const t = clamp((performance.now() - start) / SNAP_DURATION_MS, 0, 1);\n const v = from + (targetFloat - from) * ease(t);\n setFloatIndex(v);\n if (t < 1) {\n animRef.current = requestAnimationFrame(step);\n } else {\n const final = loop\n ? pmod(targetFloat, N)\n : clamp(targetFloat, 0, N - 1);\n setFloatIndex(final);\n const idx = resolveIndex(final);\n const next = items[idx];\n if (next !== undefined && next !== value) {\n onChange?.(next, idx);\n }\n }\n };\n animRef.current = requestAnimationFrame(step);\n },\n [items, loop, N, onChange, resolveIndex, value]\n );\n\n // External value -> internal float, animated on the shortest path. Tracked\n // by value's resolved index rather than the items reference, so an unstable\n // `items` array (fresh ref every render) doesn't cancel an in-flight\n // animation, but a real reorder (where `value` lands at a different index)\n // still resyncs the drum.\n const targetIdx = N > 0 ? Math.max(0, items.indexOf(value)) : 0;\n const lastSyncedTargetIdx = useRef<number>(targetIdx);\n useEffect(() => {\n if (targetIdx === lastSyncedTargetIdx.current) {\n return;\n }\n lastSyncedTargetIdx.current = targetIdx;\n if (N === 0) {\n return;\n }\n const cur = floatIndexRef.current;\n let target = targetIdx;\n if (loop) {\n const cycles = Math.round((cur - targetIdx) / N);\n target = targetIdx + cycles * N;\n }\n if (Math.abs(target - cur) > 0.001) {\n animateTo(target);\n }\n // animateTo intentionally omitted to avoid retriggering on every render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [targetIdx]);\n\n // Wheel: native non-passive listener so we can preventDefault.\n useEffect(() => {\n const el = containerRef.current;\n if (!el) {\n return;\n }\n const onWheel = (e: WheelEvent): void => {\n e.preventDefault();\n cancelAnimationFrame(animRef.current);\n const delta = e.deltaY / itemHeight;\n const raw = floatIndexRef.current + delta;\n setFloatIndex(loop ? raw : clamp(raw, 0, N - 1));\n if (wheelTimer.current) {\n clearTimeout(wheelTimer.current);\n }\n wheelTimer.current = setTimeout(() => {\n const cur = floatIndexRef.current;\n const target = loop\n ? Math.round(cur)\n : clamp(Math.round(cur), 0, N - 1);\n animateTo(target);\n }, WHEEL_SETTLE_MS);\n };\n el.addEventListener(\"wheel\", onWheel, { passive: false });\n return () => {\n el.removeEventListener(\"wheel\", onWheel);\n if (wheelTimer.current) {\n clearTimeout(wheelTimer.current);\n }\n };\n }, [animateTo, N, itemHeight, loop]);\n\n useEffect(\n () => () => {\n cancelAnimationFrame(animRef.current);\n },\n []\n );\n\n const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>): void => {\n if (e.pointerType === \"mouse\" && e.button !== 0) {\n return;\n }\n cancelAnimationFrame(animRef.current);\n containerRef.current?.setPointerCapture(e.pointerId);\n dragRef.current = {\n active: true,\n startY: e.clientY,\n startIndex: floatIndexRef.current,\n lastY: e.clientY,\n lastT: performance.now(),\n vy: 0,\n moved: false,\n };\n };\n\n const onPointerMove = (e: ReactPointerEvent<HTMLDivElement>): void => {\n const d = dragRef.current;\n if (!d.active) {\n return;\n }\n const dy = e.clientY - d.startY;\n if (Math.abs(dy) > 3) {\n d.moved = true;\n }\n const raw = d.startIndex - dy / itemHeight;\n setFloatIndex(loop ? raw : clamp(raw, 0, N - 1));\n const now = performance.now();\n const dt = Math.max(1, now - d.lastT);\n d.vy = (e.clientY - d.lastY) / dt;\n d.lastY = e.clientY;\n d.lastT = now;\n };\n\n const onPointerUp = (e: ReactPointerEvent<HTMLDivElement>): void => {\n const d = dragRef.current;\n if (!d.active) {\n return;\n }\n d.active = false;\n try {\n containerRef.current?.releasePointerCapture(e.pointerId);\n } catch {\n /* pointer may already be released */\n }\n const coastPx = d.vy * COAST_FACTOR;\n const projected = floatIndexRef.current - coastPx / itemHeight;\n const target = loop\n ? Math.round(projected)\n : clamp(Math.round(projected), 0, N - 1);\n animateTo(target);\n };\n\n const onKeyDown = (e: ReactKeyboardEvent<HTMLDivElement>): void => {\n let target = Math.round(floatIndexRef.current);\n if (e.key === \"ArrowUp\") {\n target -= 1;\n } else if (e.key === \"ArrowDown\") {\n target += 1;\n } else if (e.key === \"PageUp\") {\n target -= 5;\n } else if (e.key === \"PageDown\") {\n target += 5;\n } else if (e.key === \"Home\") {\n const cur = Math.round(floatIndexRef.current);\n target = loop ? cur - pmod(cur, N) : 0;\n } else if (e.key === \"End\") {\n const cur = Math.round(floatIndexRef.current);\n target = loop ? cur - pmod(cur, N) + N - 1 : N - 1;\n } else {\n return;\n }\n e.preventDefault();\n if (!loop) {\n target = clamp(target, 0, N - 1);\n }\n animateTo(target);\n };\n\n const halfVisible = Math.floor(visibleCount / 2);\n const windowRadius = halfVisible + 2;\n const centerInt = Math.round(floatIndex);\n\n const visibleItems: Array<{\n key: string;\n itemIdx: number;\n offsetSlot: number;\n label: string;\n }> = [];\n for (let off = -windowRadius; off <= windowRadius; off++) {\n const rawIdx = centerInt + off;\n if (!loop && (rawIdx < 0 || rawIdx >= N)) {\n continue;\n }\n const itemIdx = pmod(rawIdx, N);\n const label = items[itemIdx];\n if (label === undefined) {\n continue;\n }\n visibleItems.push({\n key: String(rawIdx),\n itemIdx,\n offsetSlot: rawIdx,\n label,\n });\n }\n\n const rowOffset = (slot: number): number => (slot - floatIndex) * itemHeight;\n const selectedIndex = N > 0 ? resolveIndex(floatIndex) : 0;\n\n if (N === 0) {\n return (\n <div\n aria-label={ariaLabel}\n className={cn(\n \"relative h-full w-full overflow-hidden bg-white dark:bg-gray-900\",\n className\n )}\n role=\"listbox\"\n />\n );\n }\n\n return (\n <div\n aria-activedescendant={optionId(selectedIndex)}\n aria-label={ariaLabel}\n aria-orientation=\"vertical\"\n className={cn(\n \"relative h-full w-full cursor-grab touch-none select-none overflow-hidden bg-white outline-hidden active:cursor-grabbing focus-visible:[box-shadow:inset_0_0_0_2px_var(--brand-primary)] dark:bg-gray-900\",\n className\n )}\n onKeyDown={onKeyDown}\n onPointerCancel={onPointerUp}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n ref={containerRef}\n role=\"listbox\"\n style={{ \"--sd-item-h\": `${itemHeight}px` } as React.CSSProperties}\n tabIndex={0}\n >\n <div\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-x-0 top-[-1px] z-[2] h-9 bg-gradient-to-b from-white from-[12%] to-transparent dark:from-gray-900\"\n />\n <div\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-x-0 bottom-[-1px] z-[2] h-9 bg-gradient-to-t from-white from-[12%] to-transparent dark:from-gray-900\"\n />\n <div\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-x-2 top-1/2 z-0 h-[41px] -translate-y-1/2 rounded-sm border border-brand-primary bg-brand-secondary\"\n />\n\n <div className=\"pointer-events-none absolute inset-0\">\n {visibleItems.map(({ key, itemIdx, offsetSlot, label }) => {\n const isSelected =\n itemIdx === selectedIndex &&\n Math.abs(offsetSlot - floatIndex) <= 0.5;\n return (\n <button\n aria-selected={isSelected}\n className={cn(\n \"pointer-events-auto absolute top-1/2 left-1/2 z-[1] m-0 box-border flex h-[var(--sd-item-h,52px)] w-full cursor-pointer items-center justify-center overflow-hidden border-0 bg-transparent px-1.5 py-0 transition-colors duration-150\",\n isSelected\n ? \"text-brand-primary-hover dark:text-white\"\n : \"text-gray-600 dark:text-gray-300\"\n )}\n id={isSelected ? optionId(itemIdx) : undefined}\n key={key}\n onClick={() => {\n if (dragRef.current.moved) {\n return;\n }\n animateTo(offsetSlot);\n }}\n role=\"option\"\n style={{\n transform: `translate3d(-50%, calc(-50% + ${rowOffset(offsetSlot)}px), 0)`,\n }}\n tabIndex={-1}\n type=\"button\"\n >\n <span className=\"inline-block whitespace-nowrap text-center font-sans font-semibold text-[30px] leading-9 tracking-[-1px] [font-feature-settings:'ss03']\">\n {truncate(label)}\n </span>\n </button>\n );\n })}\n </div>\n </div>\n );\n};\n\ninterface ScrollDrumGroupProps {\n /** One or more {@link ScrollDrumColumn} children. */\n children: ReactNode;\n /** Additional class names merged onto the group container. */\n className?: string;\n /** Glyph rendered between adjacent columns. Ignored when `showSeparators` is false. */\n separator?: string;\n /** When `false`, the gutter between columns is preserved but no glyph is rendered. */\n showSeparators?: boolean;\n}\n\n/**\n * Gray container that holds one or more {@link ScrollDrumColumn} children.\n * Optionally renders a glyph between columns (e.g. `:` for time, `/` for date).\n */\nconst ScrollDrumGroup = ({\n children,\n separator = \":\",\n showSeparators = true,\n className,\n}: ScrollDrumGroupProps): ReactNode => {\n const cols = Children.toArray(children);\n return (\n <div\n className={cn(\n \"inline-flex flex-row items-center justify-center rounded-lg bg-gray-100 px-8 pt-6 pb-4 dark:bg-gray-800\",\n className\n )}\n >\n {cols.map((col, idx) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: columns are static and not reordered\n <Fragment key={idx}>\n {col}\n {idx < cols.length - 1 && (\n <div\n aria-hidden=\"true\"\n className=\"flex h-[120px] w-8 flex-none items-center justify-center self-start\"\n >\n {showSeparators && (\n <span className=\"text-center font-sans font-semibold text-[36px] text-gray-600 leading-10 tracking-[-1.5px] [font-feature-settings:'ss03'] dark:text-gray-400\">\n {separator}\n </span>\n )}\n </div>\n )}\n </Fragment>\n ))}\n </div>\n );\n};\n\ninterface ScrollDrumColumnProps {\n /** Should be a single {@link ScrollDrum}. */\n children: ReactNode;\n /** Additional class names merged onto the column wrapper. */\n className?: string;\n /** Caption rendered below the drum slab. Pass `\"\"` for an invisible spacer. */\n label?: string;\n /** Hard character cap that drives the auto-computed column width. */\n maxChars?: number;\n /** Explicit pixel width override. When omitted, scales with `maxChars`. */\n width?: number;\n}\n\n/**\n * Pairs a {@link ScrollDrum} with an optional caption underneath. When `width`\n * is omitted the column auto-sizes via `Math.max(72, 24 + maxChars * 16)`, so\n * a 4-char drum (e.g. `\"2026\"`) lands at 88px and a 2-char drum stays at the\n * 72px floor.\n */\nconst ScrollDrumColumn = ({\n label,\n width,\n maxChars = DEFAULT_MAX_CHARS,\n children,\n className,\n}: ScrollDrumColumnProps): ReactNode => {\n const computed = width ?? Math.max(72, 24 + maxChars * 16);\n return (\n <div\n className={cn(\"flex flex-none flex-col gap-2 p-0\", className)}\n style={{ width: computed }}\n >\n <div className=\"flex h-[120px] flex-none items-center justify-center bg-white dark:bg-gray-900\">\n {children}\n </div>\n {label !== undefined && (\n <div className=\"h-6 text-center font-sans font-semibold text-base text-gray-600 leading-6 [font-feature-settings:'ss03'] dark:text-gray-300\">\n {label || \"\u00A0\"}\n </div>\n )}\n </div>\n );\n};\n\nexport type { ScrollDrumColumnProps, ScrollDrumGroupProps, ScrollDrumProps };\nexport { ScrollDrum, ScrollDrumColumn, ScrollDrumGroup };\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -143,7 +143,7 @@ const SelectItem = ({
143
143
  SelectPrimitive.Item,
144
144
  {
145
145
  className: cn(
146
- "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pr-2 pl-8 text-base outline-none focus:bg-gray-50 focus:text-gray-950 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-gray-900 dark:focus:text-white",
146
+ "relative flex w-full cursor-default select-none items-center rounded-xs py-1.5 pr-2 pl-8 text-base outline-hidden focus:bg-gray-50 focus:text-gray-950 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-gray-900 dark:focus:text-white",
147
147
  className
148
148
  ),
149
149
  ref,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/select.tsx"],
4
- "sourcesContent": ["/**\n * @module Select\n *\n * Dropdown select menu for single value selection. Built on Radix UI Select primitive.\n * Includes keyboard navigation, typeahead, and customizable styling.\n *\n * @see {@link https://ui.shadcn.com/docs/components/select Shadcn Select}\n * @see {@link https://www.radix-ui.com/primitives/docs/components/select Radix Select}\n *\n * @example\n * // Basic select\n * <Select>\n * <SelectTrigger className=\"w-48\">\n * <SelectValue placeholder=\"Select option\" />\n * </SelectTrigger>\n * <SelectContent>\n * <SelectItem value=\"a\">Option A</SelectItem>\n * <SelectItem value=\"b\">Option B</SelectItem>\n * </SelectContent>\n * </Select>\n *\n * @example\n * // Grouped options\n * <SelectContent>\n * <SelectGroup>\n * <SelectLabel>Fruits</SelectLabel>\n * <SelectItem value=\"apple\">Apple</SelectItem>\n * <SelectItem value=\"banana\">Banana</SelectItem>\n * </SelectGroup>\n * <SelectSeparator />\n * <SelectGroup>\n * <SelectLabel>Vegetables</SelectLabel>\n * <SelectItem value=\"carrot\">Carrot</SelectItem>\n * </SelectGroup>\n * </SelectContent>\n */\nimport { Check, ChevronDown, ChevronUp } from \"lucide-react\";\nimport { Select as SelectPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\nimport type { Ref } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** Root component that manages select state. */\nconst Select = SelectPrimitive.Root;\n\n/** Container for grouping related select items with a label. */\nconst SelectGroup = SelectPrimitive.Group;\n\n/** Displays the selected value or placeholder text. */\nconst SelectValue = SelectPrimitive.Value;\n\n/**\n * Button that opens the select dropdown.\n * @param icon - Custom dropdown icon (defaults to ChevronDown)\n */\ninterface SelectTriggerProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>,\n \"ref\"\n > {\n icon?: React.ReactNode;\n ref?: Ref<React.ElementRef<typeof SelectPrimitive.Trigger>>;\n}\n\nconst SelectTrigger = ({\n className,\n children,\n icon,\n ref,\n ...props\n}: SelectTriggerProps) => (\n <SelectPrimitive.Trigger\n className={cn(\n \"group flex h-10 w-full min-w-44 items-center justify-between gap-2 rounded-lg border border-gray-200 border-solid bg-white px-4 py-2 text-base transition-colors focus-visible:border-gray-400 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)] focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1\",\n \"dark:border-gray-800 dark:bg-gray-950 dark:text-white dark:focus-visible:border-gray-600 dark:focus-visible:ring-[var(--focus-ring)] dark:focus-visible:ring-offset-gray-950\",\n className\n )}\n ref={ref}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n {icon ?? <ChevronDown className=\"h-5 w-5\" />}\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n);\n\ninterface SelectScrollUpButtonProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof SelectPrimitive.ScrollUpButton>>;\n}\n\nconst SelectScrollUpButton = ({\n className,\n ref,\n ...props\n}: SelectScrollUpButtonProps) => (\n <SelectPrimitive.ScrollUpButton\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n ref={ref}\n {...props}\n >\n <ChevronUp className=\"h-5 w-5\" />\n </SelectPrimitive.ScrollUpButton>\n);\n\ninterface SelectScrollDownButtonProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof SelectPrimitive.ScrollDownButton>>;\n}\n\nconst SelectScrollDownButton = ({\n className,\n ref,\n ...props\n}: SelectScrollDownButtonProps) => (\n <SelectPrimitive.ScrollDownButton\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n ref={ref}\n {...props}\n >\n <ChevronDown className=\"h-4 w-4\" />\n </SelectPrimitive.ScrollDownButton>\n);\n\ninterface SelectContentProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof SelectPrimitive.Content>>;\n}\n\nconst SelectContent = ({\n className,\n children,\n position,\n ref,\n ...props\n}: SelectContentProps) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n className={cn(\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-96 min-w-[8rem] rounded-lg border border-gray-200 border-solid bg-white text-gray-950 shadow-[0px_2px_4px_0px_rgba(0,_0,_0,_0.15)] data-[state=closed]:animate-out data-[state=open]:animate-in dark:border-gray-800 dark:bg-gray-950 dark:text-white\",\n position === \"popper\" &&\n \"data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1\",\n className\n )}\n position={position}\n ref={ref}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n \"p-1\",\n position === \"popper\" &&\n \"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]\"\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n);\n\ninterface SelectContentPopperProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof SelectPrimitive.Content>>;\n}\n\nconst SelectContentPopper = ({\n className,\n children,\n position = \"popper\",\n ref,\n ...props\n}: SelectContentPopperProps) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n className={cn(\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-lg border border-gray-200 border-solid bg-white text-gray-950 shadow-100 data-[state=closed]:animate-out data-[state=open]:animate-in dark:border-gray-800 dark:bg-gray-950 dark:text-white\",\n position === \"popper\" &&\n \"data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1\",\n className\n )}\n position={position}\n ref={ref}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n \"p-1\",\n position === \"popper\" &&\n \"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]\"\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n);\n\ninterface SelectLabelProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof SelectPrimitive.Label>>;\n}\n\nconst SelectLabel = ({ className, ref, ...props }: SelectLabelProps) => (\n <SelectPrimitive.Label\n className={cn(\"py-1.5 pr-2 pl-8 font-semibold text-base\", className)}\n ref={ref}\n {...props}\n />\n);\n\ninterface SelectItemProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>,\n \"ref\"\n > {\n hideCheck?: boolean;\n ref?: Ref<React.ElementRef<typeof SelectPrimitive.Item>>;\n}\n\nconst SelectItem = ({\n className,\n children,\n hideCheck,\n ref,\n ...props\n}: SelectItemProps) => (\n <SelectPrimitive.Item\n className={cn(\n \"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pr-2 pl-8 text-base outline-none focus:bg-gray-50 focus:text-gray-950 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-gray-900 dark:focus:text-white\",\n className\n )}\n ref={ref}\n {...props}\n >\n {hideCheck ? null : (\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <Check className=\"h-4 w-4\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n )}\n\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n);\n\ninterface SelectSeparatorProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof SelectPrimitive.Separator>>;\n}\n\nconst SelectSeparator = ({\n className,\n ref,\n ...props\n}: SelectSeparatorProps) => (\n <SelectPrimitive.Separator\n className={cn(\"-mx-1 my-1 h-px bg-gray-150 dark:bg-gray-800\", className)}\n ref={ref}\n {...props}\n />\n);\n\nexport {\n Select,\n SelectContent,\n SelectContentPopper,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectScrollDownButton,\n SelectScrollUpButton,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n};\n"],
4
+ "sourcesContent": ["/**\n * @module Select\n *\n * Dropdown select menu for single value selection. Built on Radix UI Select primitive.\n * Includes keyboard navigation, typeahead, and customizable styling.\n *\n * @see {@link https://ui.shadcn.com/docs/components/select Shadcn Select}\n * @see {@link https://www.radix-ui.com/primitives/docs/components/select Radix Select}\n *\n * @example\n * // Basic select\n * <Select>\n * <SelectTrigger className=\"w-48\">\n * <SelectValue placeholder=\"Select option\" />\n * </SelectTrigger>\n * <SelectContent>\n * <SelectItem value=\"a\">Option A</SelectItem>\n * <SelectItem value=\"b\">Option B</SelectItem>\n * </SelectContent>\n * </Select>\n *\n * @example\n * // Grouped options\n * <SelectContent>\n * <SelectGroup>\n * <SelectLabel>Fruits</SelectLabel>\n * <SelectItem value=\"apple\">Apple</SelectItem>\n * <SelectItem value=\"banana\">Banana</SelectItem>\n * </SelectGroup>\n * <SelectSeparator />\n * <SelectGroup>\n * <SelectLabel>Vegetables</SelectLabel>\n * <SelectItem value=\"carrot\">Carrot</SelectItem>\n * </SelectGroup>\n * </SelectContent>\n */\nimport { Check, ChevronDown, ChevronUp } from \"lucide-react\";\nimport { Select as SelectPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\nimport type { Ref } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** Root component that manages select state. */\nconst Select = SelectPrimitive.Root;\n\n/** Container for grouping related select items with a label. */\nconst SelectGroup = SelectPrimitive.Group;\n\n/** Displays the selected value or placeholder text. */\nconst SelectValue = SelectPrimitive.Value;\n\n/**\n * Button that opens the select dropdown.\n * @param icon - Custom dropdown icon (defaults to ChevronDown)\n */\ninterface SelectTriggerProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>,\n \"ref\"\n > {\n icon?: React.ReactNode;\n ref?: Ref<React.ElementRef<typeof SelectPrimitive.Trigger>>;\n}\n\nconst SelectTrigger = ({\n className,\n children,\n icon,\n ref,\n ...props\n}: SelectTriggerProps) => (\n <SelectPrimitive.Trigger\n className={cn(\n \"group flex h-10 w-full min-w-44 items-center justify-between gap-2 rounded-lg border border-gray-200 border-solid bg-white px-4 py-2 text-base transition-colors focus-visible:border-gray-400 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)] focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1\",\n \"dark:border-gray-800 dark:bg-gray-950 dark:text-white dark:focus-visible:border-gray-600 dark:focus-visible:ring-[var(--focus-ring)] dark:focus-visible:ring-offset-gray-950\",\n className\n )}\n ref={ref}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n {icon ?? <ChevronDown className=\"h-5 w-5\" />}\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n);\n\ninterface SelectScrollUpButtonProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof SelectPrimitive.ScrollUpButton>>;\n}\n\nconst SelectScrollUpButton = ({\n className,\n ref,\n ...props\n}: SelectScrollUpButtonProps) => (\n <SelectPrimitive.ScrollUpButton\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n ref={ref}\n {...props}\n >\n <ChevronUp className=\"h-5 w-5\" />\n </SelectPrimitive.ScrollUpButton>\n);\n\ninterface SelectScrollDownButtonProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof SelectPrimitive.ScrollDownButton>>;\n}\n\nconst SelectScrollDownButton = ({\n className,\n ref,\n ...props\n}: SelectScrollDownButtonProps) => (\n <SelectPrimitive.ScrollDownButton\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n ref={ref}\n {...props}\n >\n <ChevronDown className=\"h-4 w-4\" />\n </SelectPrimitive.ScrollDownButton>\n);\n\ninterface SelectContentProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof SelectPrimitive.Content>>;\n}\n\nconst SelectContent = ({\n className,\n children,\n position,\n ref,\n ...props\n}: SelectContentProps) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n className={cn(\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-96 min-w-[8rem] rounded-lg border border-gray-200 border-solid bg-white text-gray-950 shadow-[0px_2px_4px_0px_rgba(0,_0,_0,_0.15)] data-[state=closed]:animate-out data-[state=open]:animate-in dark:border-gray-800 dark:bg-gray-950 dark:text-white\",\n position === \"popper\" &&\n \"data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1\",\n className\n )}\n position={position}\n ref={ref}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n \"p-1\",\n position === \"popper\" &&\n \"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]\"\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n);\n\ninterface SelectContentPopperProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof SelectPrimitive.Content>>;\n}\n\nconst SelectContentPopper = ({\n className,\n children,\n position = \"popper\",\n ref,\n ...props\n}: SelectContentPopperProps) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n className={cn(\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-lg border border-gray-200 border-solid bg-white text-gray-950 shadow-100 data-[state=closed]:animate-out data-[state=open]:animate-in dark:border-gray-800 dark:bg-gray-950 dark:text-white\",\n position === \"popper\" &&\n \"data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1\",\n className\n )}\n position={position}\n ref={ref}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n \"p-1\",\n position === \"popper\" &&\n \"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]\"\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n);\n\ninterface SelectLabelProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof SelectPrimitive.Label>>;\n}\n\nconst SelectLabel = ({ className, ref, ...props }: SelectLabelProps) => (\n <SelectPrimitive.Label\n className={cn(\"py-1.5 pr-2 pl-8 font-semibold text-base\", className)}\n ref={ref}\n {...props}\n />\n);\n\ninterface SelectItemProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>,\n \"ref\"\n > {\n hideCheck?: boolean;\n ref?: Ref<React.ElementRef<typeof SelectPrimitive.Item>>;\n}\n\nconst SelectItem = ({\n className,\n children,\n hideCheck,\n ref,\n ...props\n}: SelectItemProps) => (\n <SelectPrimitive.Item\n className={cn(\n \"relative flex w-full cursor-default select-none items-center rounded-xs py-1.5 pr-2 pl-8 text-base outline-hidden focus:bg-gray-50 focus:text-gray-950 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-gray-900 dark:focus:text-white\",\n className\n )}\n ref={ref}\n {...props}\n >\n {hideCheck ? null : (\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <Check className=\"h-4 w-4\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n )}\n\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n);\n\ninterface SelectSeparatorProps\n extends Omit<\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>,\n \"ref\"\n > {\n ref?: Ref<React.ElementRef<typeof SelectPrimitive.Separator>>;\n}\n\nconst SelectSeparator = ({\n className,\n ref,\n ...props\n}: SelectSeparatorProps) => (\n <SelectPrimitive.Separator\n className={cn(\"-mx-1 my-1 h-px bg-gray-150 dark:bg-gray-800\", className)}\n ref={ref}\n {...props}\n />\n);\n\nexport {\n Select,\n SelectContent,\n SelectContentPopper,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectScrollDownButton,\n SelectScrollUpButton,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n};\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -72,7 +72,7 @@ const Slider = React.memo(
72
72
  (props.value ?? props.defaultValue ?? []).map((_, index) => /* @__PURE__ */ jsx(
73
73
  SliderPrimitive.Thumb,
74
74
  {
75
- className: "block h-3 w-3 rounded-full border-2 border-gray-900 bg-brand-primary ring-offset-white transition-colors hover:cursor-grab focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-950 focus-visible:ring-offset-2 active:cursor-grabbing disabled:pointer-events-none disabled:opacity-50 dark:border-gray-50 dark:ring-offset-gray-950 dark:focus-visible:ring-gray-300"
75
+ className: "block h-3 w-3 rounded-full border-2 border-brand-primary bg-brand-primary ring-offset-white transition-colors hover:cursor-grab focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-gray-950 focus-visible:ring-offset-2 active:cursor-grabbing disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-gray-950 dark:focus-visible:ring-gray-300"
76
76
  },
77
77
  index
78
78
  ))
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/slider.tsx"],
4
- "sourcesContent": ["/**\n * @module Slider\n *\n * Range input slider with draggable thumb. Built on Radix UI Slider primitive.\n *\n * @see {@link https://ui.shadcn.com/docs/components/slider Shadcn Slider}\n * @see {@link https://www.radix-ui.com/primitives/docs/components/slider Radix Slider}\n *\n * @example\n * // Basic slider\n * <Slider defaultValue={[50]} max={100} step={1} />\n *\n * @example\n * // With value display\n * <Slider defaultValue={[50]} max={100} showValue />\n *\n * @example\n * // Controlled slider\n * const [value, setValue] = useState([25]);\n *\n * <Slider value={value} onValueChange={setValue} max={100} />\n *\n * @example\n * // Vertical orientation\n * <Slider orientation=\"vertical\" className=\"h-48\" />\n */\nimport { cva } from \"class-variance-authority\";\nimport { Slider as SliderPrimitive } from \"radix-ui\";\nimport type { Ref } from \"react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\nconst sliderVariants = cva(\n \"relative flex h-full w-full touch-none select-none items-center justify-center\",\n {\n variants: {\n variant: {\n default: \"\",\n dynamic: \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\nconst trackVariants = cva(\n \"relative overflow-hidden rounded-full bg-gray-200 hover:cursor-pointer\",\n {\n variants: {\n variant: {\n default: \"bg-gray-200\",\n dynamic: \"bg-gray-100 dark:bg-gray-700\",\n },\n orientation: {\n horizontal: \"h-1 w-full\",\n vertical: \"h-full w-1\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n orientation: \"horizontal\",\n },\n }\n);\n\n/**\n * Props for the Slider component.\n * @property variant - Visual style: `\"default\"` or `\"dynamic\"`\n * @property showValue - Display current value next to slider (horizontal only)\n */\ninterface SliderProps\n extends React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> {\n ref?: Ref<React.ElementRef<typeof SliderPrimitive.Root>>;\n /** Display the current value to the right of the slider */\n showValue?: boolean;\n variant?: \"default\" | \"dynamic\";\n}\n\nconst Slider = React.memo(\n ({\n className,\n orientation = \"horizontal\",\n variant,\n showValue = false,\n ref,\n ...props\n }: SliderProps) => {\n const sliderElement = (\n <SliderPrimitive.Root\n className={cn(sliderVariants({ variant, className }))}\n orientation={orientation}\n ref={ref}\n {...props}\n >\n <SliderPrimitive.Track\n className={cn(trackVariants({ variant, orientation }))}\n >\n <SliderPrimitive.Range\n className={cn(\n \"absolute bg-brand-primary\",\n orientation === \"horizontal\" ? \"h-full\" : \"right-0 w-full\"\n )}\n data-orientation={orientation}\n />\n </SliderPrimitive.Track>\n {(props.value ?? props.defaultValue ?? []).map((_, index) => (\n <SliderPrimitive.Thumb\n className=\"block h-3 w-3 rounded-full border-2 border-gray-900 bg-brand-primary ring-offset-white transition-colors hover:cursor-grab focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-950 focus-visible:ring-offset-2 active:cursor-grabbing disabled:pointer-events-none disabled:opacity-50 dark:border-gray-50 dark:ring-offset-gray-950 dark:focus-visible:ring-gray-300\"\n key={index}\n />\n ))}\n </SliderPrimitive.Root>\n );\n\n if (showValue && orientation === \"horizontal\") {\n return (\n <div className=\"flex items-center gap-3\">\n {sliderElement}\n <span className=\"min-w-[2rem] text-right text-gray-700 text-sm tabular-nums dark:text-gray-200\">\n {props.value?.at(0) ?? props.defaultValue?.at(0) ?? 0}\n </span>\n </div>\n );\n }\n\n return sliderElement;\n }\n);\n\nexport type { SliderProps };\nexport { Slider, sliderVariants };\n"],
4
+ "sourcesContent": ["/**\n * @module Slider\n *\n * Range input slider with draggable thumb. Built on Radix UI Slider primitive.\n *\n * @see {@link https://ui.shadcn.com/docs/components/slider Shadcn Slider}\n * @see {@link https://www.radix-ui.com/primitives/docs/components/slider Radix Slider}\n *\n * @example\n * // Basic slider\n * <Slider defaultValue={[50]} max={100} step={1} />\n *\n * @example\n * // With value display\n * <Slider defaultValue={[50]} max={100} showValue />\n *\n * @example\n * // Controlled slider\n * const [value, setValue] = useState([25]);\n *\n * <Slider value={value} onValueChange={setValue} max={100} />\n *\n * @example\n * // Vertical orientation\n * <Slider orientation=\"vertical\" className=\"h-48\" />\n */\nimport { cva } from \"class-variance-authority\";\nimport { Slider as SliderPrimitive } from \"radix-ui\";\nimport type { Ref } from \"react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\nconst sliderVariants = cva(\n \"relative flex h-full w-full touch-none select-none items-center justify-center\",\n {\n variants: {\n variant: {\n default: \"\",\n dynamic: \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\nconst trackVariants = cva(\n \"relative overflow-hidden rounded-full bg-gray-200 hover:cursor-pointer\",\n {\n variants: {\n variant: {\n default: \"bg-gray-200\",\n dynamic: \"bg-gray-100 dark:bg-gray-700\",\n },\n orientation: {\n horizontal: \"h-1 w-full\",\n vertical: \"h-full w-1\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n orientation: \"horizontal\",\n },\n }\n);\n\n/**\n * Props for the Slider component.\n * @property variant - Visual style: `\"default\"` or `\"dynamic\"`\n * @property showValue - Display current value next to slider (horizontal only)\n */\ninterface SliderProps\n extends React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> {\n ref?: Ref<React.ElementRef<typeof SliderPrimitive.Root>>;\n /** Display the current value to the right of the slider */\n showValue?: boolean;\n variant?: \"default\" | \"dynamic\";\n}\n\nconst Slider = React.memo(\n ({\n className,\n orientation = \"horizontal\",\n variant,\n showValue = false,\n ref,\n ...props\n }: SliderProps) => {\n const sliderElement = (\n <SliderPrimitive.Root\n className={cn(sliderVariants({ variant, className }))}\n orientation={orientation}\n ref={ref}\n {...props}\n >\n <SliderPrimitive.Track\n className={cn(trackVariants({ variant, orientation }))}\n >\n <SliderPrimitive.Range\n className={cn(\n \"absolute bg-brand-primary\",\n orientation === \"horizontal\" ? \"h-full\" : \"right-0 w-full\"\n )}\n data-orientation={orientation}\n />\n </SliderPrimitive.Track>\n {(props.value ?? props.defaultValue ?? []).map((_, index) => (\n <SliderPrimitive.Thumb\n className=\"block h-3 w-3 rounded-full border-2 border-brand-primary bg-brand-primary ring-offset-white transition-colors hover:cursor-grab focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-gray-950 focus-visible:ring-offset-2 active:cursor-grabbing disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-gray-950 dark:focus-visible:ring-gray-300\"\n key={index}\n />\n ))}\n </SliderPrimitive.Root>\n );\n\n if (showValue && orientation === \"horizontal\") {\n return (\n <div className=\"flex items-center gap-3\">\n {sliderElement}\n <span className=\"min-w-[2rem] text-right text-gray-700 text-sm tabular-nums dark:text-gray-200\">\n {props.value?.at(0) ?? props.defaultValue?.at(0) ?? 0}\n </span>\n </div>\n );\n }\n\n return sliderElement;\n }\n);\n\nexport type { SliderProps };\nexport { Slider, sliderVariants };\n"],
5
5
  "mappings": "AA2FM,SASI,KATJ;AAjEN,SAAS,WAAW;AACpB,SAAS,UAAU,uBAAuB;AAE1C,YAAY,WAAW;AAEvB,SAAS,UAAU;AAEnB,MAAM,iBAAiB;AAAA,EACrB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAEA,MAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,SAAS;AAAA,MACX;AAAA,MACA,aAAa;AAAA,QACX,YAAY;AAAA,QACZ,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,EACF;AACF;AAeA,MAAM,SAAS,MAAM;AAAA,EACnB,CAAC;AAAA,IACC;AAAA,IACA,cAAc;AAAA,IACd;AAAA,IACA,YAAY;AAAA,IACZ;AAAA,IACA,GAAG;AAAA,EACL,MAAmB;AACjB,UAAM,gBACJ;AAAA,MAAC,gBAAgB;AAAA,MAAhB;AAAA,QACC,WAAW,GAAG,eAAe,EAAE,SAAS,UAAU,CAAC,CAAC;AAAA,QACpD;AAAA,QACA;AAAA,QACC,GAAG;AAAA,QAEJ;AAAA;AAAA,YAAC,gBAAgB;AAAA,YAAhB;AAAA,cACC,WAAW,GAAG,cAAc,EAAE,SAAS,YAAY,CAAC,CAAC;AAAA,cAErD;AAAA,gBAAC,gBAAgB;AAAA,gBAAhB;AAAA,kBACC,WAAW;AAAA,oBACT;AAAA,oBACA,gBAAgB,eAAe,WAAW;AAAA,kBAC5C;AAAA,kBACA,oBAAkB;AAAA;AAAA,cACpB;AAAA;AAAA,UACF;AAAA,WACE,MAAM,SAAS,MAAM,gBAAgB,CAAC,GAAG,IAAI,CAAC,GAAG,UACjD;AAAA,YAAC,gBAAgB;AAAA,YAAhB;AAAA,cACC,WAAU;AAAA;AAAA,YACL;AAAA,UACP,CACD;AAAA;AAAA;AAAA,IACH;AAGF,QAAI,aAAa,gBAAgB,cAAc;AAC7C,aACE,qBAAC,SAAI,WAAU,2BACZ;AAAA;AAAA,QACD,oBAAC,UAAK,WAAU,iFACb,gBAAM,OAAO,GAAG,CAAC,KAAK,MAAM,cAAc,GAAG,CAAC,KAAK,GACtD;AAAA,SACF;AAAA,IAEJ;AAEA,WAAO;AAAA,EACT;AACF;",
6
6
  "names": []
7
7
  }
@@ -233,7 +233,7 @@ function StackingCard({
233
233
  "aria-pressed": !isInGroup && selectable ? isSelected : void 0,
234
234
  className: cn(
235
235
  "relative flex w-full min-w-64 max-w-96 flex-col overflow-hidden border border-solid",
236
- "rounded-2xl shadow-sm transition-colors",
236
+ "rounded-2xl shadow-xs transition-colors",
237
237
  selectable && "cursor-pointer",
238
238
  isSelected ? "border-gray-950 dark:border-white" : "border-gray-150 dark:border-gray-800",
239
239
  "focus-visible:ring-[var(--focus-ring)] focus-visible:ring-offset-2",