@nextlyhq/ui 0.0.2-alpha.62 → 0.0.2-alpha.64

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/button.tsx","../src/lib/utils.ts","../src/components/input.tsx","../src/components/textarea.tsx","../src/components/label.tsx","../src/components/form-label-with-tooltip.tsx","../src/components/tooltip.tsx","../src/providers/portal-provider.tsx","../src/components/badge.tsx","../src/components/card.tsx","../src/components/layout.tsx","../src/components/alert.tsx","../src/components/separator.tsx","../src/components/skeleton.tsx","../src/components/progress.tsx","../src/components/checkbox.tsx","../src/components/radio-group.tsx","../src/components/switch.tsx","../src/components/collapsible.tsx","../src/components/accordion.tsx","../src/components/avatar.tsx","../src/components/tabs.tsx","../src/components/popover.tsx","../src/components/dialog.tsx","../src/components/alert-dialog.tsx","../src/components/dropdown-menu.tsx","../src/components/select.tsx","../src/components/sheet.tsx","../src/components/command.tsx","../src/components/spinner.tsx","../src/components/toaster.tsx","../src/components/table.tsx","../src/components/table-search.tsx","../src/components/table-states.tsx","../src/components/table-skeleton.tsx","../src/components/color-picker.tsx","../src/lib/color/convert.ts","../src/lib/color/hex.ts","../src/lib/color/picker-geometry.ts","../src/lib/isomorphic-layout-effect.ts","../src/components/context-menu.tsx","../src/components/resizable.tsx","../src/components/tree-view.tsx","../src/components/slider.tsx","../src/lib/dev-warn.ts","../src/lib/shortcuts/react.tsx","../src/lib/shortcuts/key-spec.ts","../src/lib/shortcuts/manager.ts","../src/components/field-shell.tsx","../src/components/form-section.tsx","../src/components/form-actions.tsx","../src/components/page-shell.tsx","../src/components/page-header.tsx"],"sourcesContent":["/**\n * The presentational half of the plugin-author API surface.\n *\n * Export groups below carry a TSDoc release tag mirroring `STABILITY.md`, which\n * is the authoritative ledger — where the two disagree, the ledger wins. A\n * group is `@public` only once a first-party plugin exercises it; everything\n * else is `@experimental` and may change in any release.\n *\n * `cn` and the Tailwind preset are deliberately NOT re-exported here: this\n * barrel ships a `\"use client\"` banner (see tsup.config.ts), because all but a\n * couple of these modules use hooks, context, forwardRef or Radix and cannot\n * render in a Server Component. Those two contain no React runtime and are\n * published as \"@nextlyhq/ui/utils\" and \"@nextlyhq/ui/tailwind-preset\" so\n * server code and build tooling can import them.\n */\n\n/** @public Button. Exercised by form-builder and page-builder. */\n// Components — Button\nexport { Button } from \"./components/button\";\n\n/** @experimental Styling helper; no first-party plugin imports it. */\nexport { buttonVariants } from \"./components/button\";\n/** @public */\nexport type { ButtonProps } from \"./types/button\";\n\n/** @public Form controls (input, textarea, label, tooltip label). */\n// Components — Input\nexport { Input } from \"./components/input\";\n\n/** @experimental Styling helper; no first-party plugin imports it. */\nexport { inputVariants } from \"./components/input\";\n/** @public */\nexport type { InputProps } from \"./components/input\";\n/** @public */\nexport { Textarea } from \"./components/textarea\";\n/** @public */\nexport { Label } from \"./components/label\";\n/** @public */\nexport { FormLabelWithTooltip } from \"./components/form-label-with-tooltip\";\n/** @public */\nexport type { FormLabelWithTooltipProps } from \"./components/form-label-with-tooltip\";\n\n// Components — Display. Release tags are per clause below.\n/** @public */\nexport { Badge } from \"./components/badge\";\n\n/** @experimental */\nexport { badgeVariants } from \"./components/badge\";\n/** @public */\nexport type { BadgeProps } from \"./components/badge\";\n/** @experimental */\nexport {\n Card,\n CardHeader,\n CardFooter,\n CardTitle,\n CardAction,\n CardDescription,\n CardContent,\n cardVariants,\n} from \"./components/card\";\n/** @experimental */\nexport type {\n CardProps,\n CardHeaderProps,\n CardTitleProps,\n CardDescriptionProps,\n CardActionProps,\n CardContentProps,\n CardFooterProps,\n} from \"./components/card\";\n/** @experimental */\nexport { Stack, Grid, Stat } from \"./components/layout\";\n/** @experimental */\nexport type { StackProps, GridProps, StatProps } from \"./components/layout\";\n/** @experimental */\nexport {\n Alert,\n AlertTitle,\n AlertDescription,\n alertVariants,\n} from \"./components/alert\";\n/** @experimental */\nexport type {\n AlertProps,\n AlertTitleProps,\n AlertDescriptionProps,\n} from \"./components/alert\";\n/** @experimental */\nexport { Separator } from \"./components/separator\";\n/** @experimental */\nexport { Skeleton } from \"./components/skeleton\";\n/** @experimental */\nexport type { SkeletonProps } from \"./components/skeleton\";\n/** @experimental */\nexport { Progress, progressVariants } from \"./components/progress\";\n/** @experimental */\nexport type { ProgressProps } from \"./components/progress\";\n\n/** @public Checkbox, switch and radio group. */\n// Components — Toggle\nexport { Checkbox } from \"./components/checkbox\";\n/** @public */\nexport { RadioGroup, RadioGroupItem } from \"./components/radio-group\";\n/** @public */\nexport { Switch } from \"./components/switch\";\n/** @experimental */\nexport {\n Collapsible,\n CollapsibleTrigger,\n CollapsibleContent,\n} from \"./components/collapsible\";\n\n// Components — Radix Primitives. Release tags are per clause below.\n/** @experimental */\nexport {\n Accordion,\n AccordionItem,\n AccordionTrigger,\n AccordionContent,\n} from \"./components/accordion\";\n/** @experimental */\nexport type {\n AccordionProps,\n AccordionItemProps,\n AccordionTriggerProps,\n AccordionContentProps,\n} from \"./types/accordion\";\n\n/** @experimental */\nexport {\n Avatar,\n AvatarImage,\n AvatarFallback,\n avatarVariants,\n} from \"./components/avatar\";\n/** @experimental */\nexport type {\n AvatarProps,\n AvatarImageProps,\n AvatarFallbackProps,\n} from \"./types/avatar\";\n\n/** @public */\nexport { Tabs, TabsList, TabsTrigger, TabsContent } from \"./components/tabs\";\n/** @public */\nexport type { TabsProps, TabsContentProps } from \"./types/tabs\";\n/**\n * From the COMPONENT module, not from `./types/tabs`.\n *\n * `./types/tabs` describes the Radix props alone, so an alias taken from there\n * rejects `variant` and `size` — and this barrel is what a consumer imports, so\n * exporting the derived aliases from the component file alone leaves them\n * unreachable.\n * @public\n */\nexport type { TabsListProps, TabsTriggerProps } from \"./components/tabs\";\n\n/** @public */\nexport { Tooltip, TooltipTrigger, TooltipContent } from \"./components/tooltip\";\n\n/** @experimental */\nexport { TooltipProvider } from \"./components/tooltip\";\n\n/** @experimental */\nexport {\n Popover,\n PopoverTrigger,\n PopoverContent,\n PopoverAnchor,\n} from \"./components/popover\";\n\n// Components — Dialog. Exercised by page-builder.\n/** @public */\nexport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogFooter,\n DialogTitle,\n DialogDescription,\n} from \"./components/dialog\";\n\n/** @experimental */\nexport {\n DialogPortal,\n DialogOverlay,\n DialogClose,\n DialogTrigger,\n dialogContentVariants,\n} from \"./components/dialog\";\n/** @public Prop types carry the same guarantee as their component. */\nexport type {\n DialogContentProps,\n DialogHeaderProps,\n DialogFooterProps,\n DialogTitleProps,\n DialogDescriptionProps,\n} from \"./components/dialog\";\n\n/** @experimental */\nexport type { DialogOverlayProps } from \"./components/dialog\";\n\n/** @experimental No first-party plugin depends on it yet. */\n// Components — AlertDialog\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n} from \"./components/alert-dialog\";\n/** @experimental */\nexport type {\n AlertDialogOverlayProps,\n AlertDialogContentProps,\n AlertDialogHeaderProps,\n AlertDialogFooterProps,\n AlertDialogTitleProps,\n AlertDialogDescriptionProps,\n AlertDialogActionProps,\n AlertDialogCancelProps,\n} from \"./components/alert-dialog\";\n\n// Components — DropdownMenu. Exercised by page-builder.\n/** @public */\nexport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuSeparator,\n} from \"./components/dropdown-menu\";\n\n/** @experimental */\nexport {\n DropdownMenuRadioItem,\n DropdownMenuLabel,\n DropdownMenuShortcut,\n DropdownMenuGroup,\n DropdownMenuPortal,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuRadioGroup,\n} from \"./components/dropdown-menu\";\n/** @public Prop types carry the same guarantee as their component. */\nexport type {\n DropdownMenuContentProps,\n DropdownMenuItemProps,\n DropdownMenuCheckboxItemProps,\n DropdownMenuSeparatorProps,\n} from \"./types/dropdown-menu\";\n\n/** @experimental */\nexport type {\n DropdownMenuSubTriggerProps,\n DropdownMenuSubContentProps,\n DropdownMenuRadioItemProps,\n DropdownMenuLabelProps,\n DropdownMenuShortcutProps,\n} from \"./types/dropdown-menu\";\n\n// Components — Select. Exercised by both first-party plugins.\n/** @public */\nexport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"./components/select\";\n\n/** @experimental */\nexport {\n SelectGroup,\n SelectLabel,\n SelectScrollDownButton,\n SelectScrollUpButton,\n SelectSeparator,\n selectTriggerVariants,\n} from \"./components/select\";\n/** @public */\nexport type { SelectTriggerProps } from \"./components/select\";\n\n// Components — Sheet. Exercised by page-builder.\n/** @public */\nexport {\n Sheet,\n SheetContent,\n SheetHeader,\n SheetTitle,\n SheetDescription,\n} from \"./components/sheet\";\n\n/** @experimental */\nexport {\n SheetPortal,\n SheetOverlay,\n SheetTrigger,\n SheetClose,\n SheetFooter,\n sheetVariants,\n} from \"./components/sheet\";\n/** @public */\nexport type { SheetContentProps } from \"./components/sheet\";\n/** @public Prop types carry the same guarantee as their component. */\nexport type {\n SheetProps,\n SheetHeaderProps,\n SheetTitleProps,\n SheetDescriptionProps,\n} from \"./types/sheet\";\n\n/** @experimental */\nexport type {\n SheetTriggerProps,\n SheetCloseProps,\n SheetOverlayProps,\n SheetFooterProps,\n SheetOverlayRef,\n SheetContentRef,\n SheetTitleRef,\n SheetDescriptionRef,\n} from \"./types/sheet\";\n\n/** @experimental No first-party plugin depends on it yet. */\n// Components — Command\nexport {\n Command,\n CommandDialog,\n CommandInput,\n CommandList,\n CommandEmpty,\n CommandGroup,\n CommandItem,\n commandDefaultFilter,\n useCommandHighlight,\n CommandSeparator,\n CommandShortcut,\n} from \"./components/command\";\n/** @experimental */\nexport type {\n CommandProps,\n CommandDialogProps,\n CommandInputProps,\n CommandListProps,\n CommandEmptyProps,\n CommandGroupProps,\n CommandItemProps,\n CommandSeparatorProps,\n CommandShortcutProps,\n} from \"./components/command\";\n\n/** @experimental No first-party plugin depends on it yet. */\n// Components — Spinner\nexport { Spinner, spinnerVariants } from \"./components/spinner\";\n/** @experimental */\nexport type { SpinnerProps } from \"./components/spinner\";\n\n// Components — Toaster\n/** @public */\nexport { toast } from \"./components/toaster\";\n\n/** @experimental */\nexport { Toaster } from \"./components/toaster\";\n/** @experimental */\nexport type { ToasterProps } from \"sonner\";\n\n/** @experimental No first-party plugin depends on them yet. */\n// Components — Table Primitives\nexport {\n Table,\n TableHeader,\n TableBody,\n TableFooter,\n TableHead,\n TableRow,\n TableCell,\n TableCaption,\n} from \"./components/table\";\n\n/** @experimental No first-party plugin depends on them yet. */\n// Components — Table Utilities\nexport { TableSearch } from \"./components/table-search\";\n/** @experimental */\nexport type { TableSearchProps } from \"./components/table-search\";\n\n/** @experimental */\nexport {\n TableError,\n TableLoading,\n TableEmpty,\n} from \"./components/table-states\";\n/** @experimental */\nexport type {\n TableErrorProps,\n TableEmptyProps,\n} from \"./components/table-states\";\n\n/** @experimental */\nexport { TableSkeleton } from \"./components/table-skeleton\";\n/** @experimental */\nexport type { TableSkeletonProps } from \"./components/table-skeleton\";\n\n// Components — ColorPicker. A colour control that knows nothing about tokens:\n// a swatch carries an opaque `value` it hands back untouched, so a host storing\n// a token reference keeps it rather than receiving the colour it resolved to.\n/** @experimental */\nexport { ColorPicker } from \"./components/color-picker\";\n/** @experimental */\nexport type { ColorPickerProps, ColorSwatch } from \"./components/color-picker\";\n\n/** @experimental */\n// Types: Table\nexport type {\n PaginationMeta,\n SortInfo,\n FilterInfo,\n TableParams,\n ListResponse,\n PaginationConfig,\n ActionCallbacks,\n DataFetcher,\n} from \"./types/table\";\n\n/** @public Required to use styles.scoped.css correctly; see STABILITY.md. */\n// Providers\nexport {\n PortalProvider,\n usePortalContainer,\n} from \"./providers/portal-provider\";\n\n// Utilities\n\n// Tailwind Preset\n\n/**\n * @experimental Editor-shell primitives.\n *\n * A right-click menu and a resizable split. Nothing in a first-party plugin imports them yet, so\n * they stay experimental: this kit graduates a surface only once one does.\n */\nexport {\n ContextMenu,\n ContextMenuCheckboxItem,\n ContextMenuContent,\n ContextMenuGroup,\n ContextMenuItem,\n ContextMenuLabel,\n ContextMenuRadioGroup,\n ContextMenuRadioItem,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n} from \"./components/context-menu\";\n\n/** @experimental */\nexport {\n ResizableHandle,\n ResizablePanel,\n ResizablePanelGroup,\n} from \"./components/resizable\";\n\n/**\n * @experimental A virtualized, keyboard-operable tree — the layers panel of an editor.\n *\n * Renders only the visible window, which is what makes a document of thousands of blocks usable\n * and what forces the flat `aria-level` markup: an item's children may not be in the DOM at all.\n */\nexport { TreeView } from \"./components/tree-view\";\n/** @experimental The node shape a tree is built from, and the control's props. */\nexport type { TreeNode, TreeViewProps } from \"./components/tree-view\";\n\n/**\n * @experimental A bounded numeric value chosen by dragging.\n *\n * Every inspector is full of these — opacity, blur radius, letter spacing, a colour's alpha —\n * and each is a property where \"more or less?\" is the useful question. `value` is an ARRAY even\n * for one thumb, which is what makes a range slider the same component rather than a second one.\n */\nexport { Slider } from \"./components/slider\";\n/**\n * @experimental The slider's props, and the per-thumb attributes assistive\n * technology reads — which are read from the THUMB and inherited from nothing,\n * so they cannot be passed through the root.\n */\nexport type { SliderProps, SliderThumbProps } from \"./components/slider\";\n\n/**\n * @experimental One owner for the shortcuts registered through it.\n *\n * It is the single listener for ITS OWN bindings, and it becomes the application's single owner\n * only once the surfaces with their own listeners adopt it. A component that still calls\n * `addEventListener(\"keydown\", ...)` is unaffected by anything here.\n *\n * The reason to adopt it: per-component `document` listeners cannot decide who owns a key —\n * `stopPropagation` does not stop siblings on the same node, so every global handler runs and\n * the winner is whichever component mounted first. Precedence here follows the component tree,\n * and a blocking layer lets a drag or a modal hold the keyboard while it is up.\n */\nexport {\n ShortcutProvider,\n ShortcutScope,\n useActiveShortcuts,\n useShortcutManager,\n useShortcuts,\n} from \"./lib/shortcuts/react\";\n/** @experimental The provider's props, and the options a layer registers with. */\nexport type {\n ShortcutProviderProps,\n UseShortcutsOptions,\n} from \"./lib/shortcuts/react\";\n/** @experimental The binding shape, and the manager for a host that drives its own events. */\nexport { createShortcutManager } from \"./lib/shortcuts/manager\";\n/**\n * @experimental The types a host needs to register shortcuts and inspect what is active:\n * `ShortcutBinding` is one shortcut, `ShortcutLayerOptions` its precedence and blocking policy,\n * `ShortcutRegistration` the handle for updating or removing it, and `ActiveShortcut` a binding\n * as a help panel sees it.\n */\nexport type {\n ActiveShortcut,\n ShortcutBinding,\n ShortcutLayerOptions,\n ShortcutManager,\n ShortcutManagerOptions,\n ShortcutRegistration,\n} from \"./lib/shortcuts/manager\";\n/** @experimental Key-spec parsing, for a host rendering its own shortcut hints. */\nexport { parseKeys } from \"./lib/shortcuts/key-spec\";\n/**\n * @experimental A parsed key spec, for rendering a shortcut hint from the same source the matcher\n * uses rather than re-splitting the string.\n */\nexport type { KeyChord, KeySequence } from \"./lib/shortcuts/key-spec\";\n/**\n * @experimental Deciding whether a keystroke IS a given chord, for a surface that must act on one\n * before the manager sees it — a capture-phase listener flushing uncommitted work ahead of a form's\n * own submit. Exported so that surface asks the same question the manager asks, rather than keeping\n * a second definition that is broader: `event.key === \"s\" && (metaKey || ctrlKey)` also fires on\n * Ctrl+Shift+S, which the manager rejects and the browser uses for Save As.\n */\nexport { chordMatches, detectApplePlatform } from \"./lib/shortcuts/key-spec\";\n/** @experimental The modifier flags {@link chordMatches} reads; a `KeyboardEvent` satisfies it. */\nexport type { ModifierState } from \"./lib/shortcuts/key-spec\";\n\n/** @experimental Form layout. No first-party plugin has exercised it in production yet. */\nexport { FieldShell } from \"./components/field-shell\";\n/** @experimental */\nexport type {\n FieldShellProps,\n FieldShellRenderProps,\n FieldWidth,\n} from \"./types/form-layout\";\n\n/**\n * @experimental A labelled card holding a group of fields, composing `Card`\n * rather than hand-rolling its own chrome. No first-party plugin has\n * exercised it in production yet.\n */\nexport { FormSection } from \"./components/form-section\";\n/** @experimental */\nexport type { FormSectionProps } from \"./components/form-section\";\n\n/**\n * @experimental A form's single action bar. The page measure it used to sit\n * beside is `PageShell`'s, reached through the page rather than the form. No\n * first-party plugin has exercised it in production yet.\n */\nexport { FormActions } from \"./components/form-actions\";\n/** @experimental */\nexport type { FormActionsProps } from \"./types/form-layout\";\n\n/**\n * @experimental The page shell: the gutter, the measure and the sanctioned\n * full-bleed escape, spent as grid columns so a second wrapper cannot add a\n * second inset and a full-bleed child does not have to be rendered outside the\n * measure in order to escape it. No first-party plugin has exercised it yet.\n */\nexport { Bleed, PageShell, SHELL_MEASURE } from \"./components/page-shell\";\n/**\n * @experimental A page's own identity — trail, name, summary and actions — fed\n * entirely by props, so a page declares what it is instead of a foreign file\n * deriving it from the URL. No first-party plugin has exercised it yet.\n */\nexport { PageHeader } from \"./components/page-header\";\n/** @experimental */\nexport type { PageHeaderProps } from \"./components/page-header\";\n/** @experimental */\nexport type { BleedProps, PageShellProps } from \"./components/page-shell\";\n","import { Slot } from \"@radix-ui/react-slot\";\nimport { cva } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport type { ButtonProps } from \"../types/button\";\n\n/**\n * Button Component - Design System Specification\n *\n * Interactive button element for user actions. Supports multiple variants,\n * sizes, and the asChild pattern for composition.\n *\n * Variants:\n * - default/primary: Primary action button (blue background, white text)\n * - secondary: Secondary action button (gray background)\n * - destructive: Destructive action button (red background)\n * - outline: Outlined button (transparent background, border)\n * - ghost: Minimal button (transparent, no border)\n * - link: Link-style button (underlined text)\n *\n * Note: 'primary' is a semantic alias for 'default' variant for better code readability\n * @experimental\n */\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium cursor-pointer transition-all duration-150 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-0 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed active:scale-[0.98] [&_svg]:text-current\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground border border-transparent hover:opacity-90\",\n primary:\n \"bg-primary text-primary-foreground border border-transparent hover:opacity-90\",\n // Solid fill uses the emphasis token so on-color text stays AA in dark\n // mode (the base token is the readable text color, too light here).\n // Hover darkens to a deeper shade rather than opacity-90, which would\n // composite the fill toward the page and drop the label under 4.5:1.\n // One step, not two: the label is white in light mode and black in\n // dark, so mixing the fill toward black moves it away from the label in\n // one mode and into it in the other. `-600` clears both (5.92:1 light,\n // 5.67:1 dark); `-700` reads at 3.70:1 against the dark label.\n destructive:\n \"bg-destructive-solid text-destructive-foreground border border-transparent hover:bg-destructive-600\",\n // border-border is the decorative separator token, and it is the right\n // one here: a button is identified by its label and fill, so its edge\n // carries no meaning on its own, unlike border-input, which is the\n // token for controls identified by their boundary (that token is now\n // below 1.4.11's 3:1 in light mode; see contrast/accepted.ts). It is\n // still used in preference to a faint primary alpha, which reads as a\n // tint of the brand colour rather than as an edge.\n outline:\n \"border border-border text-foreground hover-unified bg-background\",\n secondary:\n \"bg-background border border-border text-foreground hover:bg-primary/5\",\n ghost: \"text-foreground border border-transparent hover-unified\",\n link: \"text-primary border border-transparent underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-[var(--nx-control-height)] px-6 py-2\",\n sm: \"h-[var(--nx-control-height-md)] px-4 text-sm\",\n md: \"h-[var(--nx-control-height)] px-6 text-sm\",\n lg: \"h-[var(--nx-control-height-lg)] px-8 text-base\",\n icon: \"h-[var(--nx-control-height)] w-[var(--nx-control-height)] p-0\",\n \"icon-sm\":\n \"h-[var(--nx-control-height-md)] w-[var(--nx-control-height-md)] p-0\",\n \"icon-lg\":\n \"h-[var(--nx-control-height-lg)] w-[var(--nx-control-height-lg)] p-0\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"md\",\n },\n }\n);\n\n/** @public */\nconst Button = forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n className,\n variant = \"default\",\n size = \"md\",\n asChild = false,\n children,\n ...props\n },\n ref\n ) => {\n const Comp = asChild ? Slot : \"button\";\n\n // Automatically apply gap-2 if there are multiple children (e.g., icon + text)\n const hasMultipleChildren = React.Children.count(children) > 1;\n\n return (\n <Comp\n data-slot={`button.${variant}`}\n className={cn(\n buttonVariants({ variant, size, className }),\n hasMultipleChildren && \"gap-1.5\"\n )}\n ref={ref}\n {...props}\n >\n {children}\n </Comp>\n );\n }\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n","import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Utility function to merge class names with Tailwind CSS support.\n *\n * Combines clsx for conditional class names with tailwind-merge\n * to properly handle Tailwind CSS class conflicts.\n *\n * @example\n * ```typescript\n * cn('px-2 py-1', 'px-4') // => 'py-1 px-4'\n * cn('text-muted-foreground', condition && 'text-foreground')\n * ```\n *\n * @experimental\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { cva, type VariantProps } from \"class-variance-authority\";\nimport { forwardRef, type ComponentProps } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * Input Component - Design System Specification\n *\n * Text input fields for collecting user data. Supports various types (text,\n * email, password, number) and three size variants.\n *\n * Accessibility:\n * - Full keyboard navigation support\n * - Proper focus indicators (2px ring with offset)\n * - Error state support via aria-invalid\n * - Label association via htmlFor/id\n * - Placeholder text for guidance (not a replacement for labels)\n *\n * Design Specs:\n * - Height: sm=36px, default=40px, lg=44px\n * - Padding: Horizontal varies by size (sm=10px, default=12px, lg=16px)\n * - Border radius: `rounded-md`, the control step of the `--radius` scale\n * - Border: 1px solid, changes on focus/error\n * - Transition: 150ms (consistent with design system)\n * - Font size: sm/default=14px (text-sm), lg=16px (text-base)\n *\n * Size Variants:\n * - sm: Height 36px - Compact forms and filters, matching a small Button\n * - default: Height 40px (h-10) - Standard forms\n * - lg: Height 44px (h-11) - Prominent inputs, marketing forms\n *\n * Supported Types:\n * - text: General text input\n * - email: Email validation\n * - password: Hidden text input\n * - number: Numeric input with steppers\n * - tel: Phone number input\n * - url: URL validation\n * - search: Search input with clear button\n * @experimental\n */\nconst inputVariants = cva(\n // `text-foreground` is explicit rather than inherited. Tailwind's preflight\n // sets `color: inherit` on form controls, so without it the typed value takes\n // whatever colour an ancestor happens to carry -- muted inside a\n // `text-muted-foreground` block, red inside a `text-destructive` one. Select\n // and Textarea have always pinned it; Input was the one control that did not,\n // and callers were compensating by putting the token on a wrapper.\n \"file:text-foreground text-foreground placeholder:text-muted-foreground placeholder:opacity-50 selection:bg-primary selection:text-primary-foreground w-full min-w-0 rounded-md border border-input bg-background text-sm transition-all duration-150 outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 focus:ring-0 focus:ring-offset-0 focus:outline-none focus:border-primary! focus-visible:border-primary! aria-invalid:border-destructive aria-invalid:focus:border-destructive! data-[invalid=true]:border-destructive data-[invalid=true]:focus:border-destructive!\",\n {\n variants: {\n size: {\n // `-md` rather than `-sm`, so that a small input is the same height as\n // a small button standing beside it in a toolbar or a filter row.\n // Button's `sm` has always used this step; an input reading `-sm` made\n // `size=\"sm\"` mean 36px on one control and 32px on another, and a form\n // row mixing them sat 4px out of line.\n sm: \"h-[var(--nx-control-height-md)] px-2.5 py-2 text-sm\",\n default: \"h-[var(--nx-control-height)] px-3 py-2.5 text-sm\",\n lg: \"h-[var(--nx-control-height-lg)] px-4 py-3 text-base\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n }\n);\n\n/** @public */\nexport interface InputProps\n extends Omit<ComponentProps<\"input\">, \"size\">,\n VariantProps<typeof inputVariants> {}\n\n/** @public */\nconst Input = forwardRef<HTMLInputElement, InputProps>(\n ({ className, type, size, ...props }, ref) => {\n return (\n <input\n type={type}\n data-slot=\"input\"\n className={cn(inputVariants({ size, className }))}\n ref={ref}\n {...props}\n />\n );\n }\n);\n\nInput.displayName = \"Input\";\n\nexport { Input, inputVariants };\n","import type { TextareaHTMLAttributes } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** @public */\nconst Textarea = forwardRef<\n HTMLTextAreaElement,\n TextareaHTMLAttributes<HTMLTextAreaElement>\n>(({ className, ...props }, ref) => {\n return (\n <textarea\n data-slot=\"textarea\"\n className={cn(\n // hover:border-primary (full strength) keeps the hover boundary more\n // visible than the resting border-input, not a fainter alpha of it.\n \"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground placeholder:opacity-50 transition-all duration-200 focus:border-primary! focus-visible:border-primary! focus:outline-none hover:border-primary disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-primary/5 resize-y\",\n \"aria-invalid:border-destructive aria-invalid:focus:border-destructive!\",\n className\n )}\n ref={ref}\n {...props}\n />\n );\n});\nTextarea.displayName = \"Textarea\";\n\nexport { Textarea };\n","import { Root as LabelRoot } from \"@radix-ui/react-label\";\nimport type { ComponentProps } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** @public */\nfunction Label({ className, ...props }: ComponentProps<typeof LabelRoot>) {\n return (\n <LabelRoot\n data-slot=\"label\"\n className={cn(\n \"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Label };\n","import { Info } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\nimport { Label } from \"./label\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"./tooltip\";\n\n/** @public */\nexport interface FormLabelWithTooltipProps\n extends React.ComponentPropsWithoutRef<typeof Label> {\n label: React.ReactNode;\n description?: React.ReactNode;\n required?: boolean;\n labelClassName?: string;\n tooltipClassName?: string;\n}\n\n/** @public */\nexport const FormLabelWithTooltip = React.forwardRef<\n React.ElementRef<typeof Label>,\n FormLabelWithTooltipProps\n>(\n (\n {\n className,\n labelClassName,\n tooltipClassName,\n label,\n description,\n required,\n ...props\n },\n ref\n ) => {\n return (\n <div className={cn(\"flex items-center gap-2\", className)}>\n <Label ref={ref} className={labelClassName} {...props}>\n {label}\n {required && <span className=\"text-destructive ml-1\">*</span>}\n </Label>\n {description && (\n <TooltipProvider>\n <Tooltip delayDuration={200}>\n <TooltipTrigger\n type=\"button\"\n tabIndex={-1}\n className=\"shrink-0 text-muted-foreground hover:text-foreground focus:outline-none focus:text-foreground transition-colors cursor-help\"\n >\n <Info className=\"h-3.5 w-3.5\" />\n <span className=\"sr-only\">Toggle description</span>\n </TooltipTrigger>\n <TooltipContent\n side=\"right\"\n className={cn(\n \"max-w-[250px] text-xs break-words relative z-[100] shadow-md border border-border bg-primary text-primary-foreground px-3 py-2 rounded-lg\",\n tooltipClassName\n )}\n >\n {description}\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n )}\n </div>\n );\n }\n);\nFormLabelWithTooltip.displayName = \"FormLabelWithTooltip\";\n","import {\n Provider,\n Root,\n Trigger,\n Portal,\n Content,\n} from \"@radix-ui/react-tooltip\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\n\n/** @experimental */\nconst TooltipProvider = Provider;\n\n/** @public */\nconst Tooltip = Root;\n\n/** @public */\nconst TooltipTrigger = Trigger;\n\n/** @public */\nconst TooltipContent = forwardRef<\n React.ElementRef<typeof Content>,\n React.ComponentPropsWithoutRef<typeof Content>\n>(({ className, sideOffset = 4, ...props }, ref) => {\n const portalContainer = usePortalContainer();\n\n return (\n // Portalled for the same reason as every other overlay here, plus one\n // specific to the tooltip: the positioner measures against the nearest\n // containing block, and it counts `container-type` as one while the\n // browser does not. Left inline under a `@container` element, the content\n // is offset by that element's own position. Portalling lifts it out of any\n // such ancestor, so the two agree again.\n <Portal container={portalContainer}>\n <Content\n ref={ref}\n sideOffset={sideOffset}\n data-slot=\"tooltip-content\"\n className={cn(\n \"z-50 overflow-hidden rounded-lg px-3 py-1.5 text-xs shadow-lg border border-border bg-popover text-popover-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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\",\n className\n )}\n {...props}\n />\n </Portal>\n );\n});\nTooltipContent.displayName = Content.displayName;\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };\n","\"use client\";\n\nimport { createContext, useContext, type ReactNode } from \"react\";\n\ntype PortalContextValue = {\n container: HTMLElement | null;\n};\n\nconst PortalContext = createContext<PortalContextValue>({ container: null });\n\ninterface PortalProviderProps {\n /** The DOM element to portal overlay content into. Defaults to document.body (Radix default). */\n container: HTMLElement | null;\n children: ReactNode;\n}\n\n/** @public */\nfunction PortalProvider({ container, children }: PortalProviderProps) {\n return (\n <PortalContext.Provider value={{ container }}>\n {children}\n </PortalContext.Provider>\n );\n}\n\n/** @public */\nfunction usePortalContainer(): HTMLElement | undefined {\n const { container } = useContext(PortalContext);\n return container ?? undefined; // undefined = Radix default (document.body)\n}\n\nexport { PortalProvider, usePortalContainer };\n","import { cva, type VariantProps } from \"class-variance-authority\";\nimport type { HTMLAttributes } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * Badge Component - Design System Specification\n *\n * Badges are non-interactive elements used to highlight important information,\n * such as status indicators, counts, or labels. They should not be focusable\n * or interactive.\n *\n * Accessibility:\n * - Badges are non-interactive (no keyboard focus or click handlers)\n * - Color is not the only indicator - text conveys meaning\n * - Use aria-label for icon-only badges to provide context\n * - Provide contextual information in surrounding UI\n *\n * Design Specs:\n * - Height: 22px\n * - Padding: 2px 10px (vertical × horizontal)\n * - Border radius: Full (pill shape)\n * - Font: 12px (text-xs), medium weight (500)\n * - Colors: Light backgrounds with dark text for visibility in both light/dark modes\n *\n * Variants (6 total per design spec):\n * - default: Light gray background\n * - primary: Light blue background\n * - success: Light green background\n * - warning: Light amber background\n * - destructive: Light red background\n * - outline: Transparent background with border border-border\n * @experimental\n */\nconst badgeVariants = cva(\n \"inline-flex items-center rounded-sm px-2.5 py-0.5 h-[22px] text-xs font-medium transition-colors\",\n {\n variants: {\n variant: {\n // Clear, legible chip in both modes (was bg-primary/5 at ~5% opacity,\n // which was nearly invisible on dark backgrounds).\n default: \"bg-muted text-foreground\",\n primary: \"bg-primary/10 text-primary dark:bg-primary/20\",\n success:\n \"bg-success-100 text-success-700 dark:bg-success-900 dark:text-success-100\",\n warning:\n \"bg-warning-100 text-warning-700 dark:bg-warning-900 dark:text-warning-100\",\n destructive:\n \"bg-destructive-100 text-destructive-700 dark:bg-destructive-900 dark:text-destructive-100\",\n /*\n * The border colour is NOT important-marked. The base sets no border\n * colour, so nothing inside this component competes for it — the only\n * thing a mark could win against is the caller's own class. Seven\n * outline badges pass one, including a status pill whose comment gives\n * a 3:1 contrast reason for the colour it asks for, and every one of\n * them was being overridden without any sign that it had been.\n */\n outline:\n \"border border-border bg-transparent text-foreground dark:text-muted-foreground dark:border-border\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/** @public */\nexport interface BadgeProps\n extends HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof badgeVariants> {}\n\n/** @public */\nfunction Badge({ className, variant = \"default\", ...props }: BadgeProps) {\n return (\n <div\n data-slot={`badge.${variant}`}\n className={cn(badgeVariants({ variant }), className)}\n {...props}\n />\n );\n}\n\nexport { Badge, badgeVariants };\n","import { cva, type VariantProps } from \"class-variance-authority\";\nimport type { HTMLAttributes } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * Card Component - Design System Specification\n *\n * A container component for grouping related content with clear visual separation.\n * Cards provide a structured layout with header, content, and footer sections.\n *\n * Design Specs:\n * - Border radius: `rounded-lg`, the container step of the `--radius` scale\n * - Padding: 24px (p-6) for header/content, 16px 24px for footer\n * - Shadow: sm (default), md (hover/elevated)\n * - Border: 1px solid border border-border color\n *\n * Variants:\n * - default: Standard card with subtle shadow\n * - interactive: Hover effects for clickable cards (border border-border highlight, shadow increase)\n * ⚠️ IMPORTANT: When using the interactive variant, you MUST add appropriate\n * accessibility attributes:\n * - Add role=\"button\" or use an actual <button> wrapper\n * - Add tabIndex={0} to make it keyboard accessible\n * - Add onClick handler for mouse/touch interaction\n * - Add onKeyDown handler to support Enter/Space keys\n * - Add aria-label or aria-labelledby to describe the action\n * Example:\n * <Card\n * variant=\"interactive\"\n * role=\"button\"\n * tabIndex={0}\n * onClick={handleClick}\n * onKeyDown={(e) => e.key === 'Enter' && handleClick()}\n * aria-label=\"View user details\"\n * >\n * - elevated: More prominent shadow for emphasis\n *\n * Structure:\n * <Card>\n * <CardHeader>\n * <CardTitle>Title</CardTitle>\n * <CardDescription>Description</CardDescription>\n * <CardAction>Action buttons</CardAction>\n * </CardHeader>\n * <CardContent>Main content</CardContent>\n * <CardFooter>Footer actions</CardFooter>\n * </Card>\n *\n * Accessibility:\n * - Semantic HTML structure supports screen readers\n * - Interactive cards MUST have role, tabIndex, and keyboard handlers (see above)\n * - Ensure sufficient color contrast for all text (WCAG 2.2 AA minimum)\n * - Use aria-label or aria-labelledby for cards without visible text labels\n * @experimental\n */\nconst cardVariants = cva(\n \"bg-card text-foreground rounded-lg border border-border transition-all duration-200\",\n {\n variants: {\n variant: {\n default: \"\",\n interactive: \"cursor-pointer hover:border-primary active:scale-[0.99]\",\n elevated: \"shadow-md\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/** @experimental */\nexport type CardProps = HTMLAttributes<HTMLDivElement> &\n VariantProps<typeof cardVariants>;\n\n/** @experimental */\nconst Card = forwardRef<HTMLDivElement, CardProps>(\n ({ className, variant, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot={`card.${variant || \"default\"}`}\n className={cn(cardVariants({ variant }), className)}\n {...props}\n />\n );\n }\n);\nCard.displayName = \"Card\";\n\n/** @experimental */\nexport interface CardHeaderProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Whether to hide the bottom border border-border separator between header and content.\n * Default: false (border border-border is shown per design spec)\n */\n noBorder?: boolean;\n}\n\n/** @experimental */\nconst CardHeader = forwardRef<HTMLDivElement, CardHeaderProps>(\n ({ className, noBorder = false, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"card-header\"\n className={cn(\n // Mirrors CardFooter: a header that carries its own tint runs the full\n // width of the card, so at a nonzero --radius it would paint square\n // across the card's curved top corners. `inherit` takes the parent's\n // computed radius rather than restating a step. It only helps when the\n // header is a direct child of the card; a header nested inside another\n // wrapper inherits that wrapper's radius instead, and such a card needs\n // `overflow-hidden` to clip the fill.\n \"flex flex-col rounded-t-[inherit] p-4\",\n !noBorder && \"border-b border-border\",\n className\n )}\n {...props}\n />\n );\n }\n);\nCardHeader.displayName = \"CardHeader\";\n\n/** @experimental */\nexport type CardTitleProps = HTMLAttributes<HTMLHeadingElement>;\n\n/** @experimental */\nconst CardTitle = forwardRef<HTMLHeadingElement, CardTitleProps>(\n ({ className, ...props }, ref) => {\n return (\n <h3\n ref={ref}\n data-slot=\"card-title\"\n className={cn(\"text-xl font-semibold leading-none\", className)}\n {...props}\n />\n );\n }\n);\nCardTitle.displayName = \"CardTitle\";\n\n/** @experimental */\nexport type CardDescriptionProps = HTMLAttributes<HTMLParagraphElement>;\n\n/** @experimental */\nconst CardDescription = forwardRef<HTMLParagraphElement, CardDescriptionProps>(\n ({ className, ...props }, ref) => {\n return (\n <p\n ref={ref}\n data-slot=\"card-description\"\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n );\n }\n);\nCardDescription.displayName = \"CardDescription\";\n\n/** @experimental */\nexport type CardActionProps = HTMLAttributes<HTMLDivElement>;\n\n/** @experimental */\nconst CardAction = forwardRef<HTMLDivElement, CardActionProps>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"card-action\"\n className={cn(\"flex items-center justify-end\", className)}\n {...props}\n />\n );\n }\n);\nCardAction.displayName = \"CardAction\";\n\n/** @experimental */\nexport type CardContentProps = HTMLAttributes<HTMLDivElement>;\n\n/** @experimental */\nconst CardContent = forwardRef<HTMLDivElement, CardContentProps>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"card-content\"\n className={cn(\"p-6\", className)}\n {...props}\n />\n );\n }\n);\nCardContent.displayName = \"CardContent\";\n\n/** @experimental */\nexport type CardFooterProps = HTMLAttributes<HTMLDivElement>;\n\n/** @experimental */\nconst CardFooter = forwardRef<HTMLDivElement, CardFooterProps>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"card-footer\"\n className={cn(\n // The footer's tint runs the full width of the card, so at a nonzero\n // --radius it would paint square across the card's curved bottom\n // corners. `inherit` takes the card's own computed radius rather than\n // restating a step, so a card whose radius is overridden stays\n // matched, and it can never disagree with the card at any --radius,\n // including the shipped 0 where `rounded-lg` is 0.\n \"flex items-center px-6 py-4 border-t border-border bg-primary/5 rounded-b-[inherit]\",\n className\n )}\n {...props}\n />\n );\n }\n);\nCardFooter.displayName = \"CardFooter\";\n\nexport {\n Card,\n CardHeader,\n CardFooter,\n CardTitle,\n CardAction,\n CardDescription,\n CardContent,\n cardVariants,\n};\n","/**\n * Layout primitives for admin UI (plugins included).\n *\n * Token/utility-driven wrappers so a plugin can build common layouts —\n * vertical/horizontal stacks, responsive grids, labelled stat blocks — from the\n * admin's compiled stylesheet with no plugin build step. Gap/column values are\n * mapped to literal class names (not template strings) so Tailwind's scanner\n * detects and emits them.\n */\nimport { forwardRef, type HTMLAttributes, type ReactNode } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\ntype Gap = 0 | 1 | 2 | 3 | 4 | 6 | 8;\ntype Cols = 1 | 2 | 3 | 4 | 6;\n\nconst GAP: Record<Gap, string> = {\n 0: \"gap-0\",\n 1: \"gap-1\",\n 2: \"gap-2\",\n 3: \"gap-3\",\n 4: \"gap-4\",\n 6: \"gap-6\",\n 8: \"gap-8\",\n};\n\nconst COLS: Record<Cols, string> = {\n 1: \"grid-cols-1\",\n 2: \"grid-cols-2\",\n 3: \"grid-cols-3\",\n 4: \"grid-cols-4\",\n 6: \"grid-cols-6\",\n};\n\n/**\n * Container-query column counts, used when `responsive` is set.\n *\n * The grid starts at one column and widens at ITS OWN container's breakpoint\n * rather than the viewport's or an ancestor's. Unnamed `@` variants resolve\n * against the nearest container ancestor, which `responsive` mode guarantees\n * by rendering its own `@container` wrapper below — so this works wherever the\n * grid is mounted, with no dependency on a named container declared elsewhere.\n * Literal class names, not template strings, so Tailwind's scanner emits them.\n */\nconst RESPONSIVE_COLS: Record<Cols, string> = {\n 1: \"grid-cols-1\",\n 2: \"grid-cols-1 @2xl:grid-cols-2\",\n 3: \"grid-cols-1 @2xl:grid-cols-3\",\n 4: \"grid-cols-1 @2xl:grid-cols-4\",\n 6: \"grid-cols-1 @2xl:grid-cols-6\",\n};\n\n/** @experimental */\nexport interface StackProps extends HTMLAttributes<HTMLDivElement> {\n /** Main-axis direction. Default `col`. */\n direction?: \"col\" | \"row\";\n /** Gap between children (Tailwind spacing step). Default `4`. */\n gap?: Gap;\n}\n\n/** Flex stack: vertical by default, horizontal with `direction=\"row\"`.\n * @experimental\n */\nexport const Stack = forwardRef<HTMLDivElement, StackProps>(\n ({ direction = \"col\", gap = 4, className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n \"flex\",\n direction === \"col\" ? \"flex-col\" : \"flex-row\",\n GAP[gap],\n className\n )}\n {...props}\n />\n )\n);\nStack.displayName = \"Stack\";\n\n/** @experimental */\nexport interface GridProps extends HTMLAttributes<HTMLDivElement> {\n /** Column count. Default `2`. */\n cols?: Cols;\n /** Gap between cells. Default `4`. */\n gap?: Gap;\n /**\n * Collapse to one column in a narrow container. Off by default so existing\n * callers keep the fixed column count they were written against.\n */\n responsive?: boolean;\n}\n\n/** Simple fixed-column grid, or a container-responsive one via `responsive`.\n * @experimental\n */\nexport const Grid = forwardRef<HTMLDivElement, GridProps>(\n (\n { cols = 2, gap = 4, responsive = false, className, children, ...rest },\n ref\n ) => {\n if (!responsive) {\n // No wrapper: the single element IS the grid, exactly as before\n // `responsive` existed, so an existing caller's className, style and\n // other HTML attributes keep landing on the one node it renders.\n return (\n <div\n ref={ref}\n className={cn(\"grid\", COLS[cols], GAP[gap], className)}\n {...rest}\n >\n {children}\n </div>\n );\n }\n\n // Responsive mode renders its own unnamed `@container` wrapper so the\n // grid queries the space IT has, not any ancestor's — no dependency on a\n // named container declared elsewhere in the tree.\n //\n // That wrapper is the element that actually participates in the PARENT's\n // layout, so everything describing how this Grid sits in its parent —\n // `className`, `style` and the rest of the HTML attributes, plus `ref` —\n // belongs on it rather than on the inner grid. `cols` and `gap` describe\n // the grid's OWN internal layout and stay on the inner element regardless\n // of which mode is active. A caller passing spacing through `className`\n // instead of `gap` is already misusing the prop, not losing information.\n return (\n <div ref={ref} className={cn(\"@container\", className)} {...rest}>\n <div className={cn(\"grid\", RESPONSIVE_COLS[cols], GAP[gap])}>\n {children}\n </div>\n </div>\n );\n }\n);\nGrid.displayName = \"Grid\";\n\n/** @experimental */\nexport interface StatProps extends HTMLAttributes<HTMLDivElement> {\n /** Muted label above the value. */\n label: string;\n /** The emphasized value (string or node). */\n value: ReactNode;\n}\n\n/** Labelled metric block for dashboard-style plugin widgets.\n * @experimental\n */\nexport const Stat = forwardRef<HTMLDivElement, StatProps>(\n ({ label, value, className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex flex-col gap-1\", className)} {...props}>\n <span className=\"text-sm text-muted-foreground\">{label}</span>\n <span className=\"text-2xl font-semibold text-foreground\">{value}</span>\n </div>\n )\n);\nStat.displayName = \"Stat\";\n","import { cva, type VariantProps } from \"class-variance-authority\";\nimport { forwardRef, type HTMLAttributes } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * Alert Component - Design System Specification\n *\n * Alerts display important messages that require user attention or awareness.\n * They are non-interactive callouts used for inline notifications and feedback.\n *\n * Design Specs:\n * - Padding: 16px (p-4)\n * - Border radius: `rounded-md`, one step tighter than Card's `rounded-lg`\n * for inline/flow content vs. larger container components\n * - Border: 1px solid matching variant color\n * - Shadow: sm (subtle elevation)\n * - Font: 14px (text-sm)\n * - Layout: Flex with gap-3 for icon/content spacing\n * - Colors: Light backgrounds with dark text for WCAG 2.2 AA compliance\n *\n * Variants (4 total):\n * - info (default): Blue - informational messages, neutral announcements\n * - success: Green - successful operations, confirmations\n * - warning: Amber - cautions, warnings that need attention\n * - destructive: Red - errors, critical issues, failures\n *\n * Structure:\n * <Alert variant=\"info\">\n * <InfoIcon className=\"h-4 w-4\" />\n * <div>\n * <AlertTitle>Optional Title</AlertTitle>\n * <AlertDescription>Alert message content</AlertDescription>\n * </div>\n * </Alert>\n *\n * Accessibility:\n * - Defaults to role=\"alert\" for assertive screen reader announcements\n * - Override with role=\"status\" for non-urgent updates (polite announcements)\n * - Override with role={undefined} to remove ARIA role if needed\n * - Color is not the only indicator - icons and text convey meaning\n * - Supports rich content (links, lists) within AlertDescription\n * - WCAG 2.2 AA compliant color contrast (4.5:1 minimum)\n *\n * Usage Examples:\n *\n * // Simple alert with icon and description (default role=\"alert\")\n * <Alert variant=\"success\">\n * <CheckCircle2 className=\"h-4 w-4\" />\n * <AlertDescription>User created successfully!</AlertDescription>\n * </Alert>\n *\n * // Alert with title and description\n * <Alert variant=\"warning\">\n * <AlertTriangle className=\"h-4 w-4\" />\n * <div>\n * <AlertTitle>Warning</AlertTitle>\n * <AlertDescription>This action cannot be undone.</AlertDescription>\n * </div>\n * </Alert>\n *\n * // Non-urgent informational update\n * <Alert variant=\"info\" role=\"status\">\n * <AlertCircle className=\"h-4 w-4\" />\n * <AlertDescription>New features are now available.</AlertDescription>\n * </Alert>\n *\n * Icons (from lucide-react):\n * - Info: <AlertCircle className=\"h-4 w-4\" />\n * - Success: <CheckCircle2 className=\"h-4 w-4\" />\n * - Warning: <AlertTriangle className=\"h-4 w-4\" />\n * - Destructive: <XCircle className=\"h-4 w-4\" />\n * @experimental\n */\nconst alertVariants = cva(\n \"relative flex items-start gap-3 rounded-md border border-border p-4 text-sm transition-colors duration-150\",\n {\n variants: {\n variant: {\n // text-primary is mode-correct (dark ink on light in light mode, light\n // ink on dark in dark mode); the previous dark text override rendered\n // dark slate on the dark tint at about 1:1.\n info: \"bg-primary/5 text-primary\",\n // dark:border-l-* re-asserts the strong base accent on the left after\n // the dark:border-*-900 all-sides rule, so the meaningful accent stays\n // visible in dark mode instead of collapsing to the faint -900 shade.\n success:\n \"border-success-200 bg-success-50 text-success-900 border-l-4 border-l-success dark:border-success-900 dark:border-l-success dark:bg-success-950 dark:text-success-100\",\n warning:\n \"border-warning-200 bg-warning-50 text-warning-900 border-l-4 border-l-warning dark:border-warning-900 dark:border-l-warning dark:bg-warning-950 dark:text-warning-100\",\n destructive:\n \"border-destructive-200 bg-destructive-50 text-destructive-900 border-l-4 border-l-destructive dark:border-destructive-900 dark:border-l-destructive dark:bg-destructive-950 dark:text-destructive-100\",\n },\n },\n defaultVariants: {\n variant: \"info\",\n },\n }\n);\n\n/** @experimental */\nexport type AlertProps = HTMLAttributes<HTMLDivElement> &\n VariantProps<typeof alertVariants>;\n\n/**\n * Alert - Root container for alert messages\n *\n * Defaults to role=\"alert\" for screen reader announcements. Override with\n * role=\"status\" for non-urgent updates or role={undefined} to remove.\n *\n * @example\n * <Alert variant=\"success\">\n * <CheckCircle2 className=\"h-4 w-4\" />\n * <AlertDescription>Operation completed successfully</AlertDescription>\n * </Alert>\n * @experimental\n */\nconst Alert = forwardRef<HTMLDivElement, AlertProps>(\n ({ className, variant = \"info\", role = \"alert\", ...props }, ref) => {\n return (\n <div\n ref={ref}\n role={role}\n data-slot={`alert.${variant}`}\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n );\n }\n);\nAlert.displayName = \"Alert\";\n\n/** @experimental */\nexport type AlertTitleProps = HTMLAttributes<HTMLHeadingElement>;\n\n/**\n * AlertTitle - Heading text for alert message\n *\n * Renders as <h5> for semantic HTML structure. Use for brief, scannable\n * alert headings that summarize the message (e.g., \"Success\", \"Warning\").\n *\n * @example\n * <AlertTitle>Payment Successful</AlertTitle>\n * @experimental\n */\nconst AlertTitle = forwardRef<HTMLHeadingElement, AlertTitleProps>(\n ({ className, ...props }, ref) => {\n return (\n <h5\n ref={ref}\n data-slot=\"alert-title\"\n className={cn(\n \"mb-1 text-sm font-semibold leading-tight tracking-tight\",\n className\n )}\n {...props}\n />\n );\n }\n);\nAlertTitle.displayName = \"AlertTitle\";\n\n/** @experimental */\nexport type AlertDescriptionProps = HTMLAttributes<HTMLDivElement>;\n\n/**\n * AlertDescription - Supporting detail text for alert message\n *\n * Renders as <div> to support rich content (links, lists, formatting).\n * Use for detailed explanations, instructions, or contextual information.\n *\n * @example\n * <AlertDescription>\n * Your changes have been saved. <a href=\"/view\">View details</a>\n * </AlertDescription>\n * @experimental\n */\nconst AlertDescription = forwardRef<HTMLDivElement, AlertDescriptionProps>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"alert-description\"\n className={cn(\"text-sm leading-relaxed\", className)}\n {...props}\n />\n );\n }\n);\nAlertDescription.displayName = \"AlertDescription\";\n\nexport { Alert, AlertTitle, AlertDescription, alertVariants };\n","import * as SeparatorPrimitive from \"@radix-ui/react-separator\";\nimport type * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** @experimental */\nfunction Separator({\n className,\n orientation = \"horizontal\",\n decorative = true,\n ...props\n}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {\n return (\n <SeparatorPrimitive.Root\n data-slot=\"separator\"\n decorative={decorative}\n orientation={orientation}\n className={cn(\n \"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Separator };\n","import * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * Skeleton Loading Component\n *\n * A flexible loading placeholder component that provides visual feedback while content is loading.\n * Uses a subtle pulse animation to indicate ongoing loading state.\n *\n * @design_specs\n * - Background: bg-accent (slate-100 in light mode, slate-800 in dark mode)\n * - Animation: animate-pulse with motion-reduce:animate-none (respects prefers-reduced-motion)\n * - Border-radius: `rounded-md` by default; override per placeholder shape\n * - Contrast: 3:1 minimum for WCAG 1.4.11 (Non-text Contrast) compliance\n *\n * @accessibility\n * - Uses aria-hidden=\"true\" to hide from screen readers (visual indicator only)\n * - Skeleton should be purely decorative - actual loading state must be conveyed via:\n * 1. aria-busy=\"true\" on the parent content container\n * 2. Visually hidden loading text for screen readers\n * - Animation automatically disabled when user prefers reduced motion\n * - Reference: https://adrianroselli.com/2020/11/more-accessible-skeletons.html\n *\n * @usage_patterns\n *\n * **Text Line Skeleton:**\n * ```tsx\n * <Skeleton className=\"h-4 w-[250px]\" />\n * ```\n *\n * **Avatar Skeleton:**\n * ```tsx\n * <Skeleton className=\"h-12 w-12 rounded-md\" />\n * ```\n *\n * **Card Skeleton:**\n * ```tsx\n * <div className=\"space-y-3\">\n * <Skeleton className=\"h-[125px] w-[250px] rounded-lg\" />\n * <div className=\"space-y-2\">\n * <Skeleton className=\"h-4 w-[250px]\" />\n * <Skeleton className=\"h-4 w-[200px]\" />\n * </div>\n * </div>\n * ```\n *\n * **Proper Accessible Loading Pattern:**\n * ```tsx\n * <div aria-busy={isLoading} aria-label=\"User profile\">\n * {isLoading ? (\n * <>\n * <span className=\"sr-only\">Loading user profile...</span>\n * <Skeleton className=\"h-12 w-12 rounded-md\" />\n * <Skeleton className=\"h-4 w-[200px]\" />\n * </>\n * ) : (\n * <UserProfile data={userData} />\n * )}\n * </div>\n * ```\n *\n * @important\n * - DO: Use aria-busy=\"true\" on the parent container while loading\n * - DO: Provide visually hidden loading text for screen readers\n * - DO: Control dimensions via className (h-* w-* utilities)\n * - DON'T: Use aria-live, role=\"alert\", or role=\"progressbar\" on skeleton\n * - DON'T: Use skeleton without aria-busy on parent container\n *\n * @wcag_compliance WCAG 2.2 Level AA\n * - 1.4.11 Non-text Contrast: ✅ 3:1 minimum contrast ratio\n * - 2.3.3 Animation from Interactions: ✅ Respects prefers-reduced-motion\n * - 4.1.3 Status Messages: ✅ When used with aria-busy on parent\n *\n * @see {@link https://ui.shadcn.com/docs/components/skeleton shadcn/ui Skeleton}\n * @see {@link https://adrianroselli.com/2020/11/more-accessible-skeletons.html More Accessible Skeletons}\n * @experimental\n */\nconst Skeleton = React.forwardRef<HTMLDivElement, SkeletonProps>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"skeleton\"\n aria-hidden=\"true\"\n className={cn(\n \"bg-primary/5 animate-pulse rounded-md motion-reduce:animate-none\",\n className\n )}\n {...props}\n />\n );\n }\n);\n\nSkeleton.displayName = \"Skeleton\";\n\n/** @experimental */\nexport type SkeletonProps = React.ComponentProps<\"div\">;\n\nexport { Skeleton };\n","\"use client\";\n\n/**\n * Progress Component\n *\n * A horizontal progress bar component with variant support for different states.\n *\n * ## Design Specifications\n *\n * - **Height**: 8px (h-2)\n * - **Border Radius**: `rounded-full` on the track, fixed rather than derived\n * from `--radius` so an 8px bar always reads as a capsule; the fill stays\n * square so it always meets the clipped track edge flush\n * - **Animation**: Width transition (300ms linear) for smooth progress updates\n * - **Variants**:\n * - `default`: Primary blue (bg-primary-500)\n * - `success`: Green (bg-success-500)\n * - `error`: Red (bg-destructive)\n *\n * ## Accessibility\n *\n * - Uses `role=\"progressbar\"` for screen readers\n * - Includes `aria-valuenow`, `aria-valuemin`, `aria-valuemax` attributes\n * - Includes `aria-label` for context (e.g., \"Upload progress: 45%\")\n *\n * ## Usage Examples\n *\n * ### Basic usage\n * ```tsx\n * <Progress value={45} />\n * ```\n *\n * ### Success state\n * ```tsx\n * <Progress value={100} variant=\"success\" />\n * ```\n *\n * ### Error state\n * ```tsx\n * <Progress value={30} variant=\"error\" />\n * ```\n *\n * ### With custom label\n * ```tsx\n * <Progress\n * value={progress}\n * aria-label={`Uploading ${filename}: ${progress}%`}\n * />\n * ```\n *\n * @see ui-revamp/media-library-design-spec.md - Progress component specification\n */\n\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * Progress variants using CVA\n *\n * Defines color variants for different progress states.\n *\n * @experimental\n */\n// Square corners: the capsule track clips the trailing edge already, so a radius\n// here would only round the leading edge, tapering low percentages into a sliver\n// narrower than the value they represent.\nexport const progressVariants = cva(\"h-full rounded-none transition-all\", {\n variants: {\n variant: {\n default: \"bg-primary-500\",\n success: \"bg-success-500\",\n error: \"bg-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n});\n\n/**\n * Progress component props\n * @experimental\n */\nexport type ProgressProps = {\n /**\n * Current progress value (0-100)\n *\n * @example\n * ```tsx\n * <Progress value={45} /> // 45% progress\n * ```\n */\n value: number;\n\n /**\n * Maximum value (default: 100)\n *\n * @example\n * ```tsx\n * <Progress value={30} max={50} /> // 60% progress (30/50)\n * ```\n */\n max?: number;\n\n /**\n * Visual variant for different states\n *\n * - `default`: Primary blue (bg-primary-500)\n * - `success`: Green (bg-success-500)\n * - `error`: Red (bg-destructive)\n *\n * @default \"default\"\n */\n variant?: VariantProps<typeof progressVariants>[\"variant\"];\n\n /**\n * Optional CSS class name for custom styling\n */\n className?: string;\n\n /**\n * Optional ARIA label for screen readers\n *\n * If not provided, defaults to \"Progress: X%\"\n *\n * @example\n * ```tsx\n * <Progress value={45} aria-label=\"Uploading image.jpg: 45%\" />\n * ```\n */\n \"aria-label\"?: string;\n} & React.HTMLAttributes<HTMLDivElement>;\n\n/**\n * Progress component\n *\n * Displays a horizontal progress bar with smooth animations and variant support.\n *\n * @param props - Progress component props\n * @returns Progress bar component\n *\n * @example\n * ```tsx\n * function FileUpload() {\n * const [progress, setProgress] = React.useState(0);\n *\n * return (\n * <div>\n * <p>Uploading file...</p>\n * <Progress value={progress} aria-label={`Upload progress: ${progress}%`} />\n * </div>\n * );\n * }\n * ```\n * @experimental\n */\nconst Progress = React.forwardRef<HTMLDivElement, ProgressProps>(\n (\n {\n value,\n max = 100,\n variant = \"default\",\n className,\n \"aria-label\": ariaLabel,\n ...props\n },\n ref\n ) => {\n // Clamp value between 0 and max\n const clampedValue = Math.min(Math.max(0, value), max);\n const percentage = (clampedValue / max) * 100;\n\n return (\n <div\n ref={ref}\n role=\"progressbar\"\n aria-valuenow={clampedValue}\n aria-valuemin={0}\n aria-valuemax={max}\n aria-label={ariaLabel || `Progress: ${Math.round(percentage)}%`}\n className={cn(\n \"relative h-2 w-full overflow-hidden rounded-full bg-accent\",\n className\n )}\n {...props}\n >\n <div\n className={cn(progressVariants({ variant }))}\n style={{\n width: `${percentage}%`,\n transition: \"width 300ms linear\",\n }}\n />\n </div>\n );\n }\n);\n\nProgress.displayName = \"Progress\";\n\nexport { Progress };\n","import * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport { Check, Minus } from \"lucide-react\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** @public */\nconst Checkbox = forwardRef<\n ElementRef<typeof CheckboxPrimitive.Root>,\n ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root> & {\n indeterminate?: boolean;\n }\n>(({ className, indeterminate, ...props }, ref) => (\n <CheckboxPrimitive.Root\n ref={ref}\n data-slot=\"checkbox\"\n className={cn(\n // Resting border uses border-control-border, NOT border-input. An\n // unchecked box has no label, value or focus ring to identify it -- the\n // border is the whole control -- so it is held to 1.4.11's 3:1, which\n // border-input deliberately no longer meets. The checked state switches\n // to border-primary below, keeping the two states distinct.\n \"peer relative h-4 w-4 shrink-0 rounded-sm border border-control-border ring-offset-background before:absolute before:left-1/2 before:top-1/2 before:h-6 before:w-6 before:-translate-x-1/2 before:-translate-y-1/2 before:content-[''] focus:border-primary! focus-visible:border-primary! focus:outline-none focus-visible:outline-none aria-invalid:border-destructive aria-invalid:focus:border-destructive! aria-invalid:focus-visible:border-destructive! disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground data-[state=indeterminate]:border-primary transition-all duration-200\",\n className\n )}\n {...props}\n >\n <CheckboxPrimitive.Indicator\n className={cn(\"flex items-center justify-center text-current\")}\n >\n {indeterminate ? (\n <Minus className=\"h-3 w-3\" />\n ) : (\n <Check className=\"h-3 w-3\" />\n )}\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n));\n\nCheckbox.displayName = \"Checkbox\";\n\nexport { Checkbox };\n","import * as RadioGroupPrimitive from \"@radix-ui/react-radio-group\";\nimport type { ElementRef, ComponentPropsWithoutRef } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * RadioGroup Component - Design System Specification\n *\n * Radio buttons allow users to select a single option from a set of mutually\n * exclusive options. They should be used when only one selection is allowed.\n *\n * Accessibility:\n * - Full keyboard navigation support (Arrow keys, Tab, Space)\n * - Proper ARIA attributes provided by Radix UI\n * - Focus indicators for keyboard users\n * - Disabled state support\n *\n * Design Specs:\n * - Size: 16px (h-4 w-4) - Fixed size matching Checkbox\n * - Border: 1px solid, expands to 5px when checked (visual indicator)\n * - Border radius: `rounded-full`. Round means \"pick one\" and square means\n * \"pick many\"; a square radio would announce the wrong behaviour, so the\n * shape is fixed and deliberately outside the `--radius` scale. Checkbox\n * keeps the derived radius for the same reason.\n * - Transition: 150ms (consistent with design system)\n * - Focus ring: 2px ring with 2px offset\n *\n * Implementation Notes:\n * - Uses Radix UI primitives for robust accessibility\n * - Visual \"checked\" state achieved via border border-border expansion (border-[5px])\n * - No inner indicator needed - border border-border expansion provides clear visual feedback\n * - Hover state changes border border-border color for better interactivity\n * @public\n */\nconst RadioGroup = forwardRef<\n ElementRef<typeof RadioGroupPrimitive.Root>,\n ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>\n>(({ className, ...props }, ref) => {\n return (\n <RadioGroupPrimitive.Root\n className={cn(\"grid gap-2\", className)}\n {...props}\n ref={ref}\n data-slot=\"radio-group\"\n />\n );\n});\n\nRadioGroup.displayName = \"RadioGroup\";\n\n/** @public */\nconst RadioGroupItem = forwardRef<\n ElementRef<typeof RadioGroupPrimitive.Item>,\n ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>\n>(({ className, ...props }, ref) => {\n return (\n <RadioGroupPrimitive.Item\n ref={ref}\n data-slot=\"radio-group-item\"\n className={cn(\n // Unchecked outline uses primary/40 (clearly visible) instead of primary/5\n // (~5% opacity, effectively invisible); hover strengthens above the resting state.\n // Resting border uses border-control-border, NOT border-input. An\n // unchecked radio is only its ring, with nothing else to identify it,\n // so it is held to 1.4.11's 3:1 -- which border-input deliberately no\n // longer meets. The checked state switches to border-primary below.\n // rounded-full is fixed rather than derived from --radius: the circle is\n // what tells the user only one option can be chosen. The thick checked\n // border leaves a background-coloured core, and because the border's\n // inner edge is curved too that core reads as a round dot.\n \"peer h-4 w-4 shrink-0 rounded-full border border-control-border bg-background cursor-pointer transition-all duration-150 focus:border-primary! focus-visible:border-primary! focus:outline-none focus-visible:outline-none aria-invalid:border-destructive aria-invalid:focus:border-destructive! aria-invalid:focus-visible:border-destructive! disabled:cursor-not-allowed disabled:opacity-50 hover:border-primary/70 data-[state=checked]:border-primary data-[state=checked]:border-[5px]\",\n className\n )}\n {...props}\n >\n {/* The indicator carries no marker of its own: the expanded border plus\n the circular background core already render the selected dot. */}\n <RadioGroupPrimitive.Indicator className=\"block size-full rounded-full\" />\n </RadioGroupPrimitive.Item>\n );\n});\n\nRadioGroupItem.displayName = \"RadioGroupItem\";\n\nexport { RadioGroup, RadioGroupItem };\n","\"use client\";\n\nimport {\n Root as SwitchRoot,\n Thumb as SwitchThumb,\n} from \"@radix-ui/react-switch\";\nimport type { ComponentProps } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * A pill track carrying a circular thumb is how a toggle is recognised, so both\n * parts use `rounded-full` and stay outside the `--radius` scale: at any theme\n * radius the switch must still read as a switch and not as a small checkbox.\n * @public\n */\nfunction Switch({ className, ...props }: ComponentProps<typeof SwitchRoot>) {\n return (\n <SwitchRoot\n data-slot=\"switch\"\n className={cn(\n \"peer inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-border transition-all outline-none focus-visible:border-primary aria-invalid:border-destructive aria-invalid:focus-visible:border-destructive! disabled:cursor-not-allowed disabled:opacity-50\",\n \"data-[state=checked]:bg-primary data-[state=checked]:border-primary!\",\n // An unchecked switch is a track and a thumb and nothing else -- no\n // label inside it, no value, no glyph -- so 1.4.11 applies to both the\n // track against the page and the thumb against the track. `bg-input`\n // cannot serve here: it is the FIELD border weight, deliberately below\n // the minimum, and at that value the pill and its thumb both vanish\n // into a light page. The control token is the same answer used for the\n // checkbox and radio boundary, for the same reason.\n // At full strength in both modes. A `/80` here read as a softening of\n // the dark track and was in fact a removal of the guarantee the token\n // carries: composited over the surfaces the switch renders on it\n // measures 3.02 on the page, 2.94 on a card, 2.85 on a popover or the\n // sidebar and 2.65 on muted, so three of the four fall under the 3:1\n // this token exists to hold. Opaque, the same four are 4.23, 4.01,\n // 3.79 and 3.40.\n \"data-[state=unchecked]:bg-control-border data-[state=unchecked]:border-control-border\",\n className\n )}\n {...props}\n >\n <SwitchThumb\n data-slot=\"switch-thumb\"\n className={cn(\n \"bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0\"\n )}\n />\n </SwitchRoot>\n );\n}\n\nexport { Switch };\n","import * as CollapsiblePrimitive from \"@radix-ui/react-collapsible\";\n\n/** @experimental */\nconst Collapsible = CollapsiblePrimitive.Root;\n\n/** @experimental */\nconst CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;\n\n/** @experimental */\nconst CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;\n\nexport { Collapsible, CollapsibleTrigger, CollapsibleContent };\n","\"use client\";\n\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\";\nimport { ChevronDown } from \"lucide-react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport type {\n AccordionItemProps,\n AccordionItemRef,\n AccordionTriggerProps,\n AccordionTriggerRef,\n AccordionContentProps,\n AccordionContentRef,\n} from \"../types/accordion\";\n\n/**\n * Accordion Component - Design System Specification\n *\n * A vertically stacked set of interactive headings that each reveal a section of content.\n * Built on Radix UI primitives with WAI-ARIA compliance.\n *\n * Design Specs:\n * - AccordionItem border: 1px bottom border border-border (border-b)\n * - AccordionTrigger padding: 16px vertical (py-4)\n * - AccordionTrigger font: font-medium (500 weight)\n * - AccordionContent padding: 16px bottom, 0 top (pb-4 pt-0)\n * - Icon size: 16×16px (h-4 w-4)\n * - Icon rotation: 180° when expanded\n * - Transition duration: 150ms (design system standard)\n *\n * Structure:\n * <Accordion type=\"single\" collapsible>\n * <AccordionItem value=\"item-1\">\n * <AccordionTrigger>Is it accessible?</AccordionTrigger>\n * <AccordionContent>\n * Yes. It adheres to the WAI-ARIA design pattern.\n * </AccordionContent>\n * </AccordionItem>\n * </Accordion>\n *\n * Accessibility:\n * - Full keyboard navigation (Arrow keys, Home, End, Space, Enter)\n * - ARIA attributes automatically applied by Radix UI\n * - aria-expanded indicates open/closed state\n * - aria-controls associates trigger with content\n * - aria-labelledby provides context to assistive technologies\n * - role=\"region\" on content panels\n * - Focus indicators visible (Tailwind default focus-visible)\n *\n * Features:\n * - Single mode: Only one item can be open at a time (type=\"single\")\n * - Multiple mode: Multiple items can be open (type=\"multiple\")\n * - Collapsible: Items can be collapsed when clicked again (collapsible prop)\n * - Disabled state support (disabled prop on items)\n * - Controlled/uncontrolled modes (value/defaultValue)\n * - Smooth height animations (data-state animations)\n *\n * Usage Examples:\n *\n * Basic accordion (single mode):\n * ```tsx\n * <Accordion type=\"single\" collapsible>\n * <AccordionItem value=\"item-1\">\n * <AccordionTrigger>Is it accessible?</AccordionTrigger>\n * <AccordionContent>\n * Yes. It adheres to the WAI-ARIA design pattern.\n * </AccordionContent>\n * </AccordionItem>\n * <AccordionItem value=\"item-2\">\n * <AccordionTrigger>Is it styled?</AccordionTrigger>\n * <AccordionContent>\n * Yes. It comes with default styles that match the design system.\n * </AccordionContent>\n * </AccordionItem>\n * </Accordion>\n * ```\n *\n * Multiple items open (multiple mode):\n * ```tsx\n * <Accordion type=\"multiple\">\n * <AccordionItem value=\"item-1\">\n * <AccordionTrigger>Section 1</AccordionTrigger>\n * <AccordionContent>Content 1</AccordionContent>\n * </AccordionItem>\n * <AccordionItem value=\"item-2\">\n * <AccordionTrigger>Section 2</AccordionTrigger>\n * <AccordionContent>Content 2</AccordionContent>\n * </AccordionItem>\n * </Accordion>\n * ```\n *\n * Controlled accordion:\n * ```tsx\n * const [value, setValue] = useState(\"item-1\");\n * <Accordion type=\"single\" value={value} onValueChange={setValue}>\n * <AccordionItem value=\"item-1\">\n * <AccordionTrigger>Item 1</AccordionTrigger>\n * <AccordionContent>Content 1</AccordionContent>\n * </AccordionItem>\n * <AccordionItem value=\"item-2\">\n * <AccordionTrigger>Item 2</AccordionTrigger>\n * <AccordionContent>Content 2</AccordionContent>\n * </AccordionItem>\n * </Accordion>\n * ```\n *\n * @see https://www.radix-ui.com/primitives/docs/components/accordion\n * @experimental\n */\nconst Accordion = AccordionPrimitive.Root;\n\n/**\n * AccordionItem - Container for trigger and content\n *\n * Design Specs:\n * - Border: 1px bottom border border-border (border-b) for visual separation\n * - Each item represents a collapsible section\n *\n * Accessibility:\n * - Each item requires a unique value prop for identification\n * - Disabled state can be set via disabled prop\n * @experimental\n */\nconst AccordionItem = forwardRef<AccordionItemRef, AccordionItemProps>(\n ({ className, ...props }, ref) => (\n <AccordionPrimitive.Item\n ref={ref}\n data-slot=\"accordion-item\"\n className={cn(\"border-b\", className)}\n {...props}\n />\n )\n);\nAccordionItem.displayName = \"AccordionItem\";\n\n/**\n * AccordionTrigger - Clickable header button that toggles content visibility\n *\n * Design Specs:\n * - Padding: 16px vertical (py-4) for adequate touch target\n * - Font: font-medium (500 weight) for emphasis\n * - Hover: underline text on hover for better feedback\n * - Icon: ChevronDown (16×16px) with 180° rotation when expanded\n * - Transition: 150ms (design system standard)\n * - Layout: flex with space-between for trigger text and icon\n *\n * Accessibility:\n * - Button element with proper ARIA attributes\n * - aria-expanded indicates open/closed state\n * - aria-controls associates trigger with content panel\n * - Keyboard: Space/Enter to toggle, Arrow keys to navigate\n * - Focus indicator visible via default focus-visible styles\n *\n * Note:\n * - The ChevronDown icon is included by default\n * - Icon rotates 180° when item is expanded ([data-state=open])\n * - Trigger includes AccordionPrimitive.Header wrapper for proper semantics\n * @experimental\n */\nconst AccordionTrigger = forwardRef<AccordionTriggerRef, AccordionTriggerProps>(\n ({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Header className=\"flex\" data-slot=\"accordion-header\">\n <AccordionPrimitive.Trigger\n ref={ref}\n data-slot=\"accordion-trigger\"\n className={cn(\n \"flex flex-1 items-center justify-between py-4 font-medium transition-all duration-150 hover:underline [&[data-state=open]>svg]:rotate-180\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronDown className=\"h-4 w-4 shrink-0 transition-transform duration-150 will-change-transform\" />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n )\n);\nAccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;\n\n/**\n * AccordionContent - Collapsible content panel\n *\n * Design Specs:\n * - Padding: 16px bottom, 0 top (pb-4 pt-0) for proper spacing\n * - Font: text-sm (14px) for body content\n * - Animation: Smooth height transition via data-state animations\n * - Overflow: hidden during animation for smooth reveal\n *\n * Accessibility:\n * - role=\"region\" for screen reader context\n * - aria-labelledby associates content with trigger\n * - Only visible when item is expanded (data-state=\"open\")\n * - Content is hidden but still in DOM when collapsed\n *\n * Animations:\n * - data-state=\"open\": animate-accordion-down (Tailwind built-in)\n * - data-state=\"closed\": animate-accordion-up (Tailwind built-in)\n * - Height transitions smoothly from 0 to auto\n * @experimental\n */\nconst AccordionContent = forwardRef<AccordionContentRef, AccordionContentProps>(\n ({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Content\n ref={ref}\n data-slot=\"accordion-content\"\n className=\"overflow-hidden text-sm transition-all will-change-[height] transform-[translateZ(0)] data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down\"\n {...props}\n >\n <div className={cn(\"pb-4 pt-0\", className)}>{children}</div>\n </AccordionPrimitive.Content>\n )\n);\n\nAccordionContent.displayName = AccordionPrimitive.Content.displayName;\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\nexport type {\n AccordionProps,\n AccordionItemProps,\n AccordionTriggerProps,\n AccordionContentProps,\n} from \"../types/accordion\";\n","\"use client\";\n\nimport {\n Root as AvatarRoot,\n Image as AvatarImagePrimitive,\n Fallback as AvatarFallbackPrimitive,\n} from \"@radix-ui/react-avatar\";\nimport { cva } from \"class-variance-authority\";\nimport { createContext, forwardRef, useContext } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport type {\n AvatarFallbackProps,\n AvatarImageProps,\n AvatarProps,\n} from \"../types/avatar\";\n\n/**\n * Avatar Component - Design System Specification\n *\n * Displays user avatars with image and fallback support. Built on Radix UI\n * primitives for robust image loading and fallback handling.\n *\n * **Component Structure**:\n * - `Avatar`: Root container with size variants\n * - `AvatarImage`: Image element with src/alt attributes\n * - `AvatarFallback`: Fallback content (typically initials) when image fails\n *\n * **Sizes**:\n * - sm: 32px (h-8 w-8) - For compact layouts, table rows, lists\n * - md: 40px (h-10 w-10) - Default size, general use\n * - lg: 48px (h-12 w-12) - For prominent displays, profile pages\n * - xl: 64px (h-16 w-16) - For large profile displays, user panels\n * - 2xl: 80px (h-20 w-20) - For profile headers, large avatars\n *\n * **Design Specs**:\n * - Border radius: `rounded-full`. A person's avatar is read as a circle, so it\n * sits outside the `--radius` scale and stays circular at any theme radius.\n * Non-identity content (media thumbnails) overrides back to a scale step.\n * - Background: bg-accent (slate-100 light, slate-800 dark)\n * - Text color: text-accent-foreground (slate-900 light, slate-100 dark)\n * - Fallback text scales with avatar size (text-xs to text-2xl)\n *\n * **Accessibility**:\n * - Always provide `alt` text on AvatarImage for screen readers\n * - Use meaningful fallback text (user initials, not decorative)\n * - Built on Radix UI with WAI-ARIA compliance\n * - Image loading handled gracefully with fallback\n *\n * @example\n * // With image\n * <Avatar size=\"md\">\n * <AvatarImage src=\"/user.jpg\" alt=\"John Doe\" />\n * <AvatarFallback>JD</AvatarFallback>\n * </Avatar>\n *\n * @example\n * // Fallback only (no image)\n * <Avatar size=\"lg\">\n * <AvatarFallback>AB</AvatarFallback>\n * </Avatar>\n *\n * @example\n * // Small size for lists\n * <Avatar size=\"sm\">\n * <AvatarImage src=\"/avatar.jpg\" alt=\"User\" />\n * <AvatarFallback>U</AvatarFallback>\n * </Avatar>\n *\n * @example\n * // Extra large for profile headers\n * <Avatar size=\"2xl\">\n * <AvatarImage src=\"/profile.jpg\" alt=\"User Name\" />\n * <AvatarFallback>UN</AvatarFallback>\n * </Avatar>\n *\n * @see {@link https://www.radix-ui.com/primitives/docs/components/avatar Radix UI Avatar}\n * @see {@link https://github.com/nextlyhq/nextly/blob/main/ui-revamp/04-design-system-specification.md Design System Specification}\n * @experimental\n */\nexport const avatarVariants = cva(\n \"relative inline-flex shrink-0 overflow-hidden rounded-full items-center justify-center bg-primary/5 text-muted-foreground\",\n {\n variants: {\n size: {\n sm: \"h-8 w-8\",\n md: \"h-10 w-10\",\n lg: \"h-12 w-12\",\n xl: \"h-16 w-16\",\n \"2xl\": \"h-20 w-20\",\n },\n },\n defaultVariants: {\n size: \"md\",\n },\n }\n);\n\n/**\n * Text size mapping for AvatarFallback based on Avatar size\n * Uses React Context to reliably pass size from Avatar to AvatarFallback\n */\nconst fallbackTextSizeMap = {\n sm: \"text-xs\", // 12px for 32px avatar\n md: \"text-sm\", // 14px for 40px avatar\n lg: \"text-base\", // 16px for 48px avatar\n xl: \"text-lg\", // 18px for 64px avatar\n \"2xl\": \"text-2xl\", // 24px for 80px avatar\n} as const;\n\n/**\n * Context to pass size from Avatar to AvatarFallback\n * This ensures text scaling works reliably regardless of className overrides\n */\nconst AvatarSizeContext = createContext<AvatarProps[\"size\"]>(\"md\");\n\n/**\n * Avatar root component\n *\n * Container element for avatar image and fallback. Provides consistent sizing\n * and styling across the application. Uses React Context to pass size to\n * AvatarFallback for reliable text scaling.\n * @experimental\n */\nconst Avatar = forwardRef<HTMLSpanElement, AvatarProps>(\n ({ className, size = \"md\", ...props }, ref) => {\n return (\n <AvatarSizeContext.Provider value={size}>\n <AvatarRoot\n ref={ref}\n data-slot=\"avatar\"\n className={cn(avatarVariants({ size }), className)}\n {...props}\n />\n </AvatarSizeContext.Provider>\n );\n }\n);\nAvatar.displayName = \"Avatar\";\n\n/**\n * AvatarImage component\n *\n * Displays the user's profile image. Falls back to AvatarFallback if image\n * fails to load or src is not provided.\n *\n * **Best Practices**:\n * - Always provide meaningful `alt` text (user's name, not \"avatar\" or \"profile picture\")\n * - Use optimized images (WebP, AVIF) for better performance\n * - Consider lazy loading for images below the fold\n *\n * @example\n * <AvatarImage src=\"/users/john-doe.jpg\" alt=\"John Doe\" />\n * @experimental\n */\nconst AvatarImage = forwardRef<HTMLImageElement, AvatarImageProps>(\n ({ className, ...props }, ref) => {\n return (\n <AvatarImagePrimitive\n ref={ref}\n data-slot=\"avatar-image\"\n className={cn(\"aspect-square size-full\", className)}\n {...props}\n />\n );\n }\n);\nAvatarImage.displayName = \"AvatarImage\";\n\n/**\n * AvatarFallback component\n *\n * Displays fallback content when image is not available or fails to load.\n * Typically shows user initials (1-2 characters). Text size automatically\n * scales based on the Avatar size using React Context.\n *\n * **Best Practices**:\n * - Use 1-2 uppercase characters (user initials: \"JD\", \"AB\")\n * - Keep text concise and meaningful\n * - Don't use decorative text (\"?\", \"NA\") - use initials or icon instead\n *\n * **Text Sizing** (scales with avatar size via Context):\n * - sm (32px): text-xs (12px)\n * - md (40px): text-sm (14px)\n * - lg (48px): text-base (16px)\n * - xl (64px): text-lg (18px)\n * - 2xl (80px): text-2xl (24px)\n *\n * @example\n * // User initials\n * <AvatarFallback>JD</AvatarFallback>\n *\n * @example\n * // Single character for compact layouts\n * <AvatarFallback>J</AvatarFallback>\n *\n * @example\n * // Custom delay before showing fallback\n * <AvatarFallback delayMs={300}>AB</AvatarFallback>\n * @experimental\n */\nconst AvatarFallback = forwardRef<HTMLSpanElement, AvatarFallbackProps>(\n ({ className, children, ...props }, ref) => {\n const size = useContext(AvatarSizeContext) || \"md\";\n const textSize = fallbackTextSizeMap[size];\n\n return (\n <AvatarFallbackPrimitive\n ref={ref}\n data-slot=\"avatar-fallback\"\n className={cn(\n \"bg-primary/5 text-muted-foreground flex size-full items-center justify-center rounded-full font-medium\",\n textSize,\n className\n )}\n {...props}\n >\n {children}\n </AvatarFallbackPrimitive>\n );\n }\n);\nAvatarFallback.displayName = \"AvatarFallback\";\n\nexport { Avatar, AvatarImage, AvatarFallback };\n","\"use client\";\n\nimport { Root, List, Trigger, Content } from \"@radix-ui/react-tabs\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { forwardRef, type ComponentPropsWithoutRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport type {\n TabsListProps as TabsListBaseProps,\n TabsListRef,\n TabsTriggerProps as TabsTriggerBaseProps,\n TabsTriggerRef,\n TabsContentProps,\n TabsContentRef,\n} from \"../types/tabs\";\n\n/**\n * Tabs Component - Design System Specification\n *\n * A set of layered sections of content—known as tab panels—that are displayed one at a time.\n * Built on Radix UI primitives with WAI-ARIA compliance.\n *\n * Design Specs:\n * - TabsList border-radius: square, independent of `--radius`\n * - TabsTrigger border-radius: square, independent of `--radius`; the active\n * state is a 2px bottom border that has to stay flush with the tab edges\n * - TabsList height: 40px (h-10)\n * - TabsTrigger padding: 12px 24px (px-3 py-1.5)\n * - Transition duration: 150ms (design system standard)\n * - Active state: bg-background with subtle shadow\n *\n * Structure:\n * <Tabs defaultValue=\"tab1\">\n * <TabsList>\n * <TabsTrigger value=\"tab1\">Tab 1</TabsTrigger>\n * <TabsTrigger value=\"tab2\">Tab 2</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"tab1\">Content 1</TabsContent>\n * <TabsContent value=\"tab2\">Content 2</TabsContent>\n * </Tabs>\n *\n * Accessibility:\n * - Full keyboard navigation (Arrow keys, Home, End, Tab)\n * - ARIA attributes automatically applied by Radix UI\n * - Focus indicators with 2px ring (WCAG 2.2 compliant)\n * - Disabled state support\n *\n * Features:\n * - Controlled/uncontrolled modes (value/defaultValue)\n * - Horizontal/vertical orientation support\n * - Automatic/manual activation modes\n * - Keyboard navigation built-in\n *\n * Usage Examples:\n *\n * Basic tabs:\n * ```tsx\n * <Tabs defaultValue=\"overview\">\n * <TabsList>\n * <TabsTrigger value=\"overview\">Overview</TabsTrigger>\n * <TabsTrigger value=\"details\">Details</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"overview\">Overview content</TabsContent>\n * <TabsContent value=\"details\">Details content</TabsContent>\n * </Tabs>\n * ```\n *\n * Controlled tabs:\n * ```tsx\n * const [activeTab, setActiveTab] = useState(\"tab1\");\n * <Tabs value={activeTab} onValueChange={setActiveTab}>\n * <TabsList>\n * <TabsTrigger value=\"tab1\">Tab 1</TabsTrigger>\n * <TabsTrigger value=\"tab2\">Tab 2</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"tab1\">Content 1</TabsContent>\n * <TabsContent value=\"tab2\">Content 2</TabsContent>\n * </Tabs>\n * ```\n *\n * Vertical tabs:\n * ```tsx\n * <Tabs defaultValue=\"tab1\" orientation=\"vertical\">\n * <TabsList>\n * <TabsTrigger value=\"tab1\">Tab 1</TabsTrigger>\n * <TabsTrigger value=\"tab2\">Tab 2</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"tab1\">Content 1</TabsContent>\n * <TabsContent value=\"tab2\">Content 2</TabsContent>\n * </Tabs>\n * ```\n *\n * @see https://www.radix-ui.com/primitives/docs/components/tabs\n * @public\n */\nconst Tabs = Root;\n\n/**\n * The list's own appearance, as variants rather than as classes each caller\n * repeats.\n *\n * `ghost` is the compact, surface-less list used where tabs sit inside another\n * panel and must not draw a bar of their own. It was spelled `h-8 bg-transparent\n * p-0` at one call site and `h-7 bg-transparent p-0` at another; naming it here\n * settles the height rather than leaving two answers in the tree.\n *\n * Only APPEARANCE is promoted. Layout a caller chooses -- `w-full`,\n * `justify-start`, margins -- stays on `className`, because a variant names a\n * decision this component owns and layout is the caller's.\n *\n * Horizontal SCROLLING is the exception, and it moved to the `scrollable` prop\n * for a reason rather than as tidying: a caller putting `overflow-x-auto` on the\n * list makes the list itself the scroll container, which breaks the rail\n * contract this file's other half depends on. See that prop.\n *\n * The arms are a named declaration rather than an object literal inside `cva`,\n * because `cva` does not expose its configuration on the function it returns —\n * so anything checking which arms exist would otherwise have to restate them,\n * and the two drift the moment an arm is added.\n */\nconst TABS_LIST_VARIANTS = {\n default: \"h-10\",\n ghost: \"h-8 bg-transparent\",\n} as const;\n\nconst tabsListVariants = cva(\n // Square corners: underline tabs, so the list never draws a rounded surface.\n // `gap-1` and `p-0` are invariant across the variants, so they belong here —\n // repeating them in each arm gives any future adjustment two sites to change\n // and one to forget.\n //\n // The rail the triggers sit on, and it is load-bearing rather than\n // decoration. Each trigger draws a 2px border on its trailing edge and pulls\n // itself half a step onto this one: with no rail here, that pull put a 2px\n // line onto whatever followed the strip in the document, and above a rounded\n // panel that is the corner curve — a straight bar crossing an 8px arc. The\n // rail also gives an inactive tab somewhere to be inactive, which is what\n // makes the active one read as selected rather than as the only tab.\n //\n // Which edge is the trailing one depends on orientation, so the rail follows\n // it. Radix stamps `data-orientation` on the list and on every trigger, so\n // both halves read the same source and cannot disagree about the axis. A\n // fixed bottom rail draws a horizontal line beneath a vertical list.\n \"inline-flex items-center justify-center gap-1 rounded-none border-b border-border p-0 text-muted-foreground data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch data-[orientation=vertical]:border-b-0 data-[orientation=vertical]:border-r\",\n {\n variants: { variant: TABS_LIST_VARIANTS },\n defaultVariants: { variant: \"default\" },\n }\n);\n\n/**\n * TabsList - Container for tab triggers\n *\n * Design Specs:\n * - Height: 40px (h-10)\n * - Border-radius: none (for underline style)\n * - Background: transparent\n * - Layout: inline-flex (horizontal by default, use orientation=\"vertical\" on Tabs root for vertical)\n * @public\n */\nconst TabsList = forwardRef<\n TabsListRef,\n TabsListBaseProps &\n VariantProps<typeof tabsListVariants> & {\n /**\n * Let a strip too wide for its container scroll sideways.\n *\n * The scroll container is a WRAPPER, never the list, and that is why this\n * prop exists rather than callers reaching for `overflow-x-auto`\n * themselves. Two things go wrong when the list is the scroller, and the\n * second is why the obvious remedy is also wrong:\n *\n * - Per the CSS overflow rules, `visible` computes to `auto` when the\n * other axis is neither `visible` nor `clip`, so `overflow-x` alone\n * always makes the element a VERTICAL scroll container too.\n * - `TabsTrigger` carries `-mb-0.5` so its 2px underline lands ON this\n * list's rail rather than below it. That pull-up puts content past the\n * content-box edge, which the new scroll container reports as vertical\n * overflow — so `overflow-y-hidden` would clip the 2px the underline is\n * made of, silencing a scrollbar by deleting the indicator.\n *\n * With the wrapper scrolling instead, the list keeps its rail and\n * `w-max min-w-full` makes that rail span the full scroll width rather\n * than stopping where the triggers do.\n */\n scrollable?: boolean;\n }\n>(({ className, variant, scrollable = false, ...props }, ref) => {\n const list = (\n <List\n ref={ref}\n data-slot=\"tabs-list\"\n className={cn(\n tabsListVariants({ variant }),\n scrollable && \"w-max min-w-full\",\n className\n )}\n {...props}\n />\n );\n\n if (!scrollable) return list;\n\n return (\n <div data-slot=\"tabs-list-scroller\" className=\"w-full overflow-x-auto\">\n {list}\n </div>\n );\n});\nTabsList.displayName = List.displayName;\n\n/**\n * The trigger's own appearance. `size` carries the type scale only: everything\n * that draws the tab -- the square corners, the 2px underline, the active and\n * hover colours, the focus ring -- is in the base and is not a caller's to\n * choose, which is the property `tabs-contract.test.ts` watches for.\n *\n * Arms declared separately for the same reason as the list's.\n */\nconst TABS_TRIGGER_SIZES = {\n default: \"text-sm\",\n sm: \"text-xs\",\n} as const;\n\nconst tabsTriggerVariants = cva(\n // Square corners: the active state is a 2px border on the trailing edge that\n // has to run the full length of the trigger and stay flush with its ends.\n //\n // The active colour is NOT important-marked. Nothing inside this component\n // competes for it — the inactive arm is mutually exclusive with the active\n // one — so the only thing an `!` could win against is a caller's class, which\n // is precisely what a theme supplies. Marking it made the one line under\n // every selected tab the one line a theme could not restyle, and the failure\n // read as \"the theme did not apply here\" rather than as an opt-out.\n //\n // The trailing edge is the bottom when the strip is horizontal and the right\n // when it is vertical, so the indicator, the half-step pull onto the rail and\n // the active colour all switch axis together off the same `data-orientation`\n // the list reads. Switching only some of them puts the selection affordance\n // on one axis and the line it sits on the other.\n \"inline-flex items-center justify-center whitespace-nowrap rounded-none bg-transparent px-4 py-2 font-medium cursor-pointer transition-all duration-200 border-b-2 relative -mb-0.5 data-[state=active]:border-b-primary data-[state=active]:text-primary data-[state=inactive]:border-transparent data-[state=inactive]:text-muted-foreground hover:text-primary hover:border-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed data-[orientation=vertical]:border-b-0 data-[orientation=vertical]:mb-0 data-[orientation=vertical]:border-r-2 data-[orientation=vertical]:-mr-0.5 data-[orientation=vertical]:data-[state=active]:border-r-primary\",\n {\n variants: { size: TABS_TRIGGER_SIZES },\n defaultVariants: { size: \"default\" },\n }\n);\n\n/**\n * TabsTrigger - Clickable tab button\n *\n * Design Specs:\n * - Border-radius: none (Gmail-style underline tabs)\n * - Padding: 6px 16px (px-4 py-2)\n * - Font: text-sm (14px), font-medium (500)\n * - Transition: 150ms (design system standard)\n * - Active state: the accent colour on the text and on the 2px trailing border\n * - Hover: the same accent, so the target reads before it is chosen\n * - Gmail-inspired clean underline style\n *\n * Accessibility:\n * - Keyboard navigation: Arrow keys, Home, End\n * - Focus ring: 2px with offset (WCAG 2.2 compliant)\n * - Disabled state: pointer-events-none, opacity-50\n * - Data attributes: [data-state=\"active|inactive\"], [data-disabled]\n * @public\n */\nconst TabsTrigger = forwardRef<\n TabsTriggerRef,\n TabsTriggerBaseProps & VariantProps<typeof tabsTriggerVariants>\n>(({ className, size, ...props }, ref) => (\n <Trigger\n ref={ref}\n data-slot=\"tabs-trigger\"\n className={cn(tabsTriggerVariants({ size }), className)}\n {...props}\n />\n));\nTabsTrigger.displayName = Trigger.displayName;\n\n/**\n * TabsContent - Content panel for each tab\n *\n * Design Specs:\n * - Margin top: 8px (mt-2) to separate from TabsList\n * - Focus ring: 2px with offset (for keyboard navigation)\n *\n * Accessibility:\n * - Focus indicator when navigating with Tab key\n * - Data attributes: [data-state=\"active|inactive\"], [data-orientation]\n * - Only active content is visible, inactive content is hidden\n * @public\n */\nconst TabsContent = forwardRef<TabsContentRef, TabsContentProps>(\n ({ className, ...props }, ref) => (\n <Content\n ref={ref}\n data-slot=\"tabs-content\"\n className={cn(\n \"mt-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n className\n )}\n {...props}\n />\n )\n);\nTabsContent.displayName = Content.displayName;\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent };\nexport { tabsListVariants, tabsTriggerVariants };\nexport { TABS_LIST_VARIANTS, TABS_TRIGGER_SIZES };\nexport type { TabsProps, TabsContentProps } from \"../types/tabs\";\n\n/**\n * The public prop types, DERIVED from the components rather than restated.\n *\n * `../types/tabs` describes the Radix props alone, so an alias taken from there\n * rejects `variant` and `size` — and a consumer typing a wrapper around\n * `TabsList` would be told the prop it can see in the signature does not exist.\n * Reading the component's own props keeps the two from drifting: a variant\n * added later reaches every consumer without a second edit.\n */\n/**\n * The list's props, including its `variant`.\n * @public\n */\nexport type TabsListProps = ComponentPropsWithoutRef<typeof TabsList>;\n\n/**\n * The trigger's props, including its `size`.\n * @public\n */\nexport type TabsTriggerProps = ComponentPropsWithoutRef<typeof TabsTrigger>;\n","import * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\n\n/** @experimental */\nconst Popover = PopoverPrimitive.Root;\n\n/** @experimental */\nconst PopoverTrigger = PopoverPrimitive.Trigger;\n\n/** @experimental */\nconst PopoverAnchor = PopoverPrimitive.Anchor;\n\n/** @experimental */\nconst PopoverContent = React.forwardRef<\n React.ElementRef<typeof PopoverPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>\n>(({ className, align = \"center\", sideOffset = 4, ...props }, ref) => {\n const portalContainer = usePortalContainer();\n\n return (\n <PopoverPrimitive.Portal container={portalContainer}>\n <PopoverPrimitive.Content\n ref={ref}\n align={align}\n sideOffset={sideOffset}\n data-slot=\"popover-content\"\n className={cn(\n \"z-[100] w-72 rounded-lg border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out 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 origin-[--radix-popover-content-transform-origin]\",\n className\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n );\n});\nPopoverContent.displayName = PopoverPrimitive.Content.displayName;\n\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };\n","import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { X } from \"lucide-react\";\nimport type {\n ElementRef,\n ComponentPropsWithoutRef,\n HTMLAttributes,\n} from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\n\n/**\n * Dialog (Modal) Component\n *\n * A composable dialog component built on Radix UI primitives for creating modal windows.\n * Supports keyboard navigation, focus trapping, and WCAG 2.2 AA accessibility.\n *\n * @example\n * ```tsx\n * <Dialog open={open} onOpenChange={setOpen}>\n * <DialogTrigger asChild>\n * <Button>Open Dialog</Button>\n * </DialogTrigger>\n * <DialogContent size=\"md\">\n * <DialogHeader>\n * <DialogTitle>Edit Profile</DialogTitle>\n * <DialogDescription>\n * Make changes to your profile here. Click save when you're done.\n * </DialogDescription>\n * </DialogHeader>\n * <div className=\"space-y-4\">\n * Your content here\n * </div>\n * <DialogFooter>\n * <Button variant=\"outline\" onClick={() => setOpen(false)}>Cancel</Button>\n * <Button type=\"submit\">Save Changes</Button>\n * </DialogFooter>\n * </DialogContent>\n * </Dialog>\n * ```\n *\n * @design-spec\n * - Border-radius: `rounded-lg`, the container step of the `--radius` scale\n * - Max-width: 512px (default), responsive sizes available\n * - Backdrop: the `--nx-overlay` scrim with blur effect\n * - Padding: 24px (p-6)\n * - Shadow: xl for prominence (elevation level 4)\n * - Transition: 150ms per design system\n * - Z-index: Overlay at z-50, Content at z-51 (ensures content above overlay)\n *\n * @accessibility\n * - Focus is trapped inside dialog when open\n * - Pressing Escape closes the dialog\n * - Focus returns to trigger element on close\n * - Includes ARIA labels and descriptions\n * - Screen reader announcements via role=\"dialog\"\n * - Close button has sr-only text for screen readers\n * @public\n */\n\nconst Dialog = DialogPrimitive.Root;\n\n/** @experimental */\nconst DialogTrigger = DialogPrimitive.Trigger;\n\n/** @experimental */\nconst DialogPortal = DialogPrimitive.Portal;\n\n/** @experimental */\nconst DialogClose = DialogPrimitive.Close;\n\n/** @experimental */\nexport type DialogOverlayProps = ComponentPropsWithoutRef<\n typeof DialogPrimitive.Overlay\n>;\n\n/**\n * DialogOverlay - The backdrop overlay behind the dialog content.\n * Renders the `--nx-overlay` scrim with a blur effect. The opacity is the\n * token's, not a literal: it differs by mode and a host can retheme it.\n * @experimental\n */\nconst DialogOverlay = forwardRef<\n ElementRef<typeof DialogPrimitive.Overlay>,\n DialogOverlayProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n data-slot=\"dialog-overlay\"\n className={cn(\n // A modal scrim, from the `--nx-overlay` token rather than a surface\n // token. A black wash is the point — painting it from `background` would\n // make it a white veil in light mode — but the alpha still has to differ\n // per mode, because what it composites over is white in one and mid-tone\n // in the other.\n \"fixed inset-0 z-50 bg-overlay backdrop-blur-sm transition-opacity duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className\n )}\n {...props}\n />\n));\nDialogOverlay.displayName = DialogPrimitive.Overlay.displayName;\n\n/**\n * Dialog content size variants using CVA.\n *\n * @variant sm - Small dialog (384px / max-w-sm) - confirmations, alerts\n * @variant md - Medium dialog (512px / max-w-lg) - default, standard forms\n * @variant lg - Large dialog (672px / max-w-2xl) - complex forms, data tables\n * @variant xl - Extra large dialog (896px / max-w-4xl) - content editors, media galleries\n * @variant full - Full width with margin (responsive) - fullscreen on mobile\n * @experimental\n */\nconst dialogContentVariants = cva(\"\", {\n variants: {\n size: {\n sm: \"max-w-sm\",\n md: \"max-w-lg\",\n lg: \"max-w-2xl\",\n xl: \"max-w-4xl\",\n full: \"max-w-[calc(100vw-2rem)] sm:max-w-[calc(100vw-4rem)]\",\n },\n },\n defaultVariants: {\n size: \"md\",\n },\n});\n\n/** @public */\nexport type DialogContentProps = ComponentPropsWithoutRef<\n typeof DialogPrimitive.Content\n> &\n VariantProps<typeof dialogContentVariants>;\n\n/**\n * DialogContent - The main dialog content container.\n *\n * @param size - Size variant (sm, md, lg, xl, full). Default: md (512px)\n *\n * @example\n * ```tsx\n * <DialogContent size=\"lg\">\n * Your content here\n * </DialogContent>\n * ```\n * @public\n */\nconst DialogContent = forwardRef<\n ElementRef<typeof DialogPrimitive.Content>,\n DialogContentProps\n>(({ className, children, size, ...props }, ref) => {\n const portalContainer = usePortalContainer();\n\n return (\n <DialogPortal container={portalContainer}>\n <DialogOverlay />\n <DialogPrimitive.Content\n ref={ref}\n data-slot=\"dialog-content\"\n className={cn(\n \"fixed left-[50%] top-[50%] z-[51] grid w-full translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background p-6 shadow-xl rounded-lg duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out 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%]\",\n dialogContentVariants({ size }),\n className\n )}\n {...props}\n >\n {children}\n <DialogPrimitive.Close\n data-slot=\"dialog-close\"\n className=\"absolute right-4 top-4 rounded-md p-1 text-muted-foreground cursor-pointer transition-colors duration-150 hover-unified focus:outline-none focus:ring-2 focus:ring-ring disabled:pointer-events-none disabled:cursor-not-allowed\"\n >\n <X className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n </DialogPrimitive.Content>\n </DialogPortal>\n );\n});\nDialogContent.displayName = DialogPrimitive.Content.displayName;\n\n/** @public */\nexport type DialogHeaderProps = HTMLAttributes<HTMLDivElement>;\n\n/**\n * DialogHeader - Container for dialog title and description.\n * Provides consistent spacing and alignment (centered on mobile, left-aligned on desktop).\n * @public\n */\nconst DialogHeader = forwardRef<HTMLDivElement, DialogHeaderProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n \"flex flex-col space-y-1.5 text-center sm:text-left\",\n className\n )}\n {...props}\n />\n )\n);\nDialogHeader.displayName = \"DialogHeader\";\n\n/** @public */\nexport type DialogFooterProps = HTMLAttributes<HTMLDivElement>;\n\n/**\n * DialogFooter - Container for dialog action buttons.\n * Provides consistent spacing and alignment (vertical on mobile, horizontal on desktop).\n *\n * @example\n * ```tsx\n * <DialogFooter>\n * <Button variant=\"outline\" onClick={onCancel}>Cancel</Button>\n * <Button type=\"submit\">Save Changes</Button>\n * </DialogFooter>\n * ```\n * @public\n */\nconst DialogFooter = forwardRef<HTMLDivElement, DialogFooterProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\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 )\n);\nDialogFooter.displayName = \"DialogFooter\";\n\n/** @public */\nexport type DialogTitleProps = ComponentPropsWithoutRef<\n typeof DialogPrimitive.Title\n>;\n\n/**\n * DialogTitle - The title of the dialog.\n * Uses text-lg (18px) with semibold weight per design system.\n *\n * @accessibility Required for screen readers. Always include a DialogTitle.\n * @public\n */\nconst DialogTitle = forwardRef<\n ElementRef<typeof DialogPrimitive.Title>,\n DialogTitleProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\n \"text-lg font-semibold leading-none tracking-tight text-foreground\",\n className\n )}\n {...props}\n />\n));\nDialogTitle.displayName = DialogPrimitive.Title.displayName;\n\n/** @public */\nexport type DialogDescriptionProps = ComponentPropsWithoutRef<\n typeof DialogPrimitive.Description\n>;\n\n/**\n * DialogDescription - The description text of the dialog.\n * Uses text-sm (14px) with muted color per design system.\n *\n * @accessibility Provides additional context for screen readers.\n * If not needed visually, you can use sr-only class.\n * @public\n */\nconst DialogDescription = forwardRef<\n ElementRef<typeof DialogPrimitive.Description>,\n DialogDescriptionProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nDialogDescription.displayName = DialogPrimitive.Description.displayName;\n\nexport {\n Dialog,\n DialogPortal,\n DialogOverlay,\n DialogClose,\n DialogTrigger,\n DialogContent,\n DialogHeader,\n DialogFooter,\n DialogTitle,\n DialogDescription,\n dialogContentVariants,\n};\n","/**\n * AlertDialog Component\n *\n * A modal dialog for important confirmations that require user acknowledgment.\n * Built on Radix UI primitives, designed for destructive actions like deletions.\n *\n * @example\n * ```tsx\n * <AlertDialog open={open} onOpenChange={setOpen}>\n * <AlertDialogTrigger asChild>\n * <Button variant=\"destructive\">Delete</Button>\n * </AlertDialogTrigger>\n * <AlertDialogContent>\n * <AlertDialogHeader>\n * <AlertDialogTitle>Are you sure?</AlertDialogTitle>\n * <AlertDialogDescription>\n * This action cannot be undone.\n * </AlertDialogDescription>\n * </AlertDialogHeader>\n * <AlertDialogFooter>\n * <AlertDialogCancel>Cancel</AlertDialogCancel>\n * <AlertDialogAction onClick={handleDelete}>Delete</AlertDialogAction>\n * </AlertDialogFooter>\n * </AlertDialogContent>\n * </AlertDialog>\n * ```\n *\n * @design-spec\n * - Border-radius: `rounded-lg`, the container step of the `--radius` scale\n * - Max-width: 512px (default)\n * - Backdrop: the `--nx-overlay` scrim with blur effect\n * - Padding: 24px (p-6)\n * - Shadow: xl for prominence\n *\n * @accessibility\n * - Focus is trapped inside dialog when open\n * - Pressing Escape closes the dialog\n * - Focus returns to trigger element on close\n * - Screen reader announcements via role=\"alertdialog\"\n */\n\nimport * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\nimport {\n forwardRef,\n type ElementRef,\n type ComponentPropsWithoutRef,\n type HTMLAttributes,\n} from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\n\nimport { buttonVariants } from \"./button\";\n\n/** @experimental */\nconst AlertDialog = AlertDialogPrimitive.Root;\n\n/** @experimental */\nconst AlertDialogTrigger = AlertDialogPrimitive.Trigger;\n\n/** @experimental */\nconst AlertDialogPortal = AlertDialogPrimitive.Portal;\n\n/** @experimental */\nexport type AlertDialogOverlayProps = ComponentPropsWithoutRef<\n typeof AlertDialogPrimitive.Overlay\n>;\n\n/**\n * AlertDialogOverlay - The backdrop overlay behind the dialog content.\n * @experimental\n */\nconst AlertDialogOverlay = forwardRef<\n ElementRef<typeof AlertDialogPrimitive.Overlay>,\n AlertDialogOverlayProps\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Overlay\n ref={ref}\n className={cn(\n // A modal scrim, from the `--nx-overlay` token rather than a surface\n // token. A black wash is the point — painting it from `background` would\n // make it a white veil in light mode — but the alpha still has to differ\n // per mode, because what it composites over is white in one and mid-tone\n // in the other.\n \"fixed inset-0 z-50 bg-overlay backdrop-blur-sm transition-opacity duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className\n )}\n {...props}\n />\n));\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;\n\n/** @experimental */\nexport type AlertDialogContentProps = ComponentPropsWithoutRef<\n typeof AlertDialogPrimitive.Content\n>;\n\n/**\n * AlertDialogContent - The main dialog content container.\n * @experimental\n */\nconst AlertDialogContent = forwardRef<\n ElementRef<typeof AlertDialogPrimitive.Content>,\n AlertDialogContentProps\n>(({ className, ...props }, ref) => {\n const portalContainer = usePortalContainer();\n\n return (\n <AlertDialogPortal container={portalContainer}>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Content\n ref={ref}\n className={cn(\n \"fixed left-[50%] top-[50%] z-[51] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background p-6 shadow-xl rounded-lg duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out 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%]\",\n className\n )}\n {...props}\n />\n </AlertDialogPortal>\n );\n});\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;\n\n/** @experimental */\nexport type AlertDialogHeaderProps = HTMLAttributes<HTMLDivElement>;\n\n/**\n * AlertDialogHeader - Container for dialog title and description.\n * @experimental\n */\nconst AlertDialogHeader = forwardRef<HTMLDivElement, AlertDialogHeaderProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className\n )}\n {...props}\n />\n )\n);\nAlertDialogHeader.displayName = \"AlertDialogHeader\";\n\n/** @experimental */\nexport type AlertDialogFooterProps = HTMLAttributes<HTMLDivElement>;\n\n/**\n * AlertDialogFooter - Container for dialog action buttons.\n * @experimental\n */\nconst AlertDialogFooter = forwardRef<HTMLDivElement, AlertDialogFooterProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\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 )\n);\nAlertDialogFooter.displayName = \"AlertDialogFooter\";\n\n/** @experimental */\nexport type AlertDialogTitleProps = ComponentPropsWithoutRef<\n typeof AlertDialogPrimitive.Title\n>;\n\n/**\n * AlertDialogTitle - The title of the alert dialog.\n * @experimental\n */\nconst AlertDialogTitle = forwardRef<\n ElementRef<typeof AlertDialogPrimitive.Title>,\n AlertDialogTitleProps\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Title\n ref={ref}\n className={cn(\n \"text-lg font-semibold leading-none tracking-tight text-foreground\",\n className\n )}\n {...props}\n />\n));\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;\n\n/** @experimental */\nexport type AlertDialogDescriptionProps = ComponentPropsWithoutRef<\n typeof AlertDialogPrimitive.Description\n>;\n\n/**\n * AlertDialogDescription - The description text of the alert dialog.\n * @experimental\n */\nconst AlertDialogDescription = forwardRef<\n ElementRef<typeof AlertDialogPrimitive.Description>,\n AlertDialogDescriptionProps\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nAlertDialogDescription.displayName =\n AlertDialogPrimitive.Description.displayName;\n\n/** @experimental */\nexport type AlertDialogActionProps = ComponentPropsWithoutRef<\n typeof AlertDialogPrimitive.Action\n>;\n\n/**\n * AlertDialogAction - The primary action button (e.g., \"Delete\", \"Confirm\").\n * Styled as destructive by default.\n * @experimental\n */\nconst AlertDialogAction = forwardRef<\n ElementRef<typeof AlertDialogPrimitive.Action>,\n AlertDialogActionProps\n>(({ className, children, ...props }, ref) => (\n <AlertDialogPrimitive.Action\n ref={ref}\n className={cn(buttonVariants({ variant: \"destructive\" }), className)}\n {...props}\n >\n {children}\n </AlertDialogPrimitive.Action>\n));\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;\n\n/** @experimental */\nexport type AlertDialogCancelProps = ComponentPropsWithoutRef<\n typeof AlertDialogPrimitive.Cancel\n>;\n\n/**\n * AlertDialogCancel - The cancel button.\n * Styled as outline variant.\n * @experimental\n */\nconst AlertDialogCancel = forwardRef<\n ElementRef<typeof AlertDialogPrimitive.Cancel>,\n AlertDialogCancelProps\n>(({ className, children, ...props }, ref) => (\n <AlertDialogPrimitive.Cancel\n ref={ref}\n className={cn(\n buttonVariants({ variant: \"outline\" }),\n \"mt-2 sm:mt-0\",\n className\n )}\n {...props}\n >\n {children}\n </AlertDialogPrimitive.Cancel>\n));\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;\n\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n};\n","/**\n * DropdownMenu Component\n *\n * A composable dropdown menu component built on Radix UI primitives.\n * Provides context menus, action menus, and navigation menus with full keyboard support.\n *\n * **Design Specifications**:\n * - Border-radius: `rounded-lg` for the menu surface, `rounded-sm` for items\n * - Padding: 4px (p-1) - compact spacing for menu items\n * - Shadow: shadow-md - floating element elevation\n * - Z-index: z-50 - above most content, below modals\n * - Min-width: 8rem (128px) - prevents cramped menus\n * - Item padding: 8px horizontal, 6px vertical (px-2 py-1.5)\n * - Font-size: 14px (text-sm)\n * - Transition: Tailwind animate utilities (fade, zoom, slide)\n *\n * **Accessibility**:\n * - Full keyboard navigation (Arrow keys, Enter, Escape, Tab)\n * - ARIA roles and attributes (menu, menuitem, menuitemcheckbox, menuitemradio)\n * - Focus management (focus trap, auto-focus first item)\n * - Screen reader support (labels, descriptions, indicators)\n * - WCAG 2.2 Level AA compliant\n *\n * **Features**:\n * - Portal rendering via PortalProvider for proper z-index stacking\n * - Checkbox and Radio item variants\n * - Sub-menu support (nested menus)\n * - Keyboard shortcuts display\n * - Customizable positioning (side, align, sideOffset)\n * - Disabled state support\n * - Inset support (for items with icons)\n *\n * @example\n * ```tsx\n * // Basic usage\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild>\n * <Button variant=\"outline\">Open Menu</Button>\n * </DropdownMenuTrigger>\n * <DropdownMenuContent>\n * <DropdownMenuItem>Profile</DropdownMenuItem>\n * <DropdownMenuItem>Settings</DropdownMenuItem>\n * <DropdownMenuSeparator />\n * <DropdownMenuItem>Logout</DropdownMenuItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n * ```\n *\n * @example\n * ```tsx\n * // With icons and shortcuts\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild>\n * <Button variant=\"ghost\" size=\"icon\">\n * <MoreHorizontal className=\"h-4 w-4\" />\n * </Button>\n * </DropdownMenuTrigger>\n * <DropdownMenuContent align=\"end\">\n * <DropdownMenuLabel>Actions</DropdownMenuLabel>\n * <DropdownMenuItem>\n * <Edit className=\"h-4 w-4\" />\n * Edit\n * <DropdownMenuShortcut>⌘E</DropdownMenuShortcut>\n * </DropdownMenuItem>\n * <DropdownMenuItem>\n * <Trash2 className=\"h-4 w-4\" />\n * Delete\n * <DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>\n * </DropdownMenuItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n * ```\n *\n * @example\n * ```tsx\n * // With checkbox items\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild>\n * <Button variant=\"outline\">View Options</Button>\n * </DropdownMenuTrigger>\n * <DropdownMenuContent>\n * <DropdownMenuLabel>Display</DropdownMenuLabel>\n * <DropdownMenuSeparator />\n * <DropdownMenuCheckboxItem checked={showPanel} onCheckedChange={setShowPanel}>\n * Show Panel\n * </DropdownMenuCheckboxItem>\n * <DropdownMenuCheckboxItem checked={showToolbar} onCheckedChange={setShowToolbar}>\n * Show Toolbar\n * </DropdownMenuCheckboxItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n * ```\n *\n * @see https://www.radix-ui.com/docs/primitives/components/dropdown-menu - Radix UI DropdownMenu\n */\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { Check, ChevronRight, Circle } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\n\n/** @public */\nconst DropdownMenu = DropdownMenuPrimitive.Root;\n\n/** @public */\nconst DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\n\n/** @experimental */\nconst DropdownMenuGroup = DropdownMenuPrimitive.Group;\n\n/** @experimental */\nconst DropdownMenuPortal = DropdownMenuPrimitive.Portal;\n\n/** @experimental */\nconst DropdownMenuSub = DropdownMenuPrimitive.Sub;\n\n/** @experimental */\nconst DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\n/**\n * Shared treatment for every interactive menu item.\n *\n * Radix sets `data-highlighted` for pointer hover *and* keyboard navigation, so\n * driving the highlight off that one state keeps mouse and keyboard in sync.\n * `bg-muted` is a real surface token: it reads clearly against the popover\n * without the full-contrast flip a solid `bg-primary` produces.\n */\nconst menuItemBase =\n \"cursor-pointer transition-colors data-[highlighted]:bg-muted data-[highlighted]:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\";\n\n/** @experimental */\nconst DropdownMenuSubTrigger = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {\n inset?: boolean;\n }\n>(({ className, inset, children, ...props }, ref) => (\n <DropdownMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n \"flex select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-muted data-[state=open]:text-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n menuItemBase,\n inset && \"pl-8\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto\" />\n </DropdownMenuPrimitive.SubTrigger>\n));\nDropdownMenuSubTrigger.displayName =\n DropdownMenuPrimitive.SubTrigger.displayName;\n\n/** @experimental */\nconst DropdownMenuSubContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.SubContent\n ref={ref}\n className={cn(\n \"z-50 min-w-[8rem] overflow-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out 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 origin-[--radix-dropdown-menu-content-transform-origin]\",\n className\n )}\n {...props}\n />\n));\nDropdownMenuSubContent.displayName =\n DropdownMenuPrimitive.SubContent.displayName;\n\n/** @public */\nconst DropdownMenuContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => {\n const portalContainer = usePortalContainer();\n\n return (\n <DropdownMenuPrimitive.Portal container={portalContainer}>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out 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 origin-[--radix-dropdown-menu-content-transform-origin]\",\n className\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n );\n});\nDropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;\n\n/** @public */\nconst DropdownMenuItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n menuItemBase,\n inset && \"pl-8\",\n className\n )}\n {...props}\n />\n));\nDropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;\n\n/** @public */\nconst DropdownMenuCheckboxItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n ref={ref}\n className={cn(\n \"relative flex select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none\",\n menuItemBase,\n className\n )}\n checked={checked}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Check className=\"h-4 w-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n));\nDropdownMenuCheckboxItem.displayName =\n DropdownMenuPrimitive.CheckboxItem.displayName;\n\n/** @experimental */\nconst DropdownMenuRadioItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"relative flex select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none\",\n menuItemBase,\n className\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Circle className=\"h-2 w-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n));\nDropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;\n\n/** @experimental */\nconst DropdownMenuLabel = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\n \"px-2 py-1.5 text-sm font-semibold\",\n inset && \"pl-8\",\n className\n )}\n {...props}\n />\n));\nDropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;\n\n/** @public */\nconst DropdownMenuSeparator = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-primary/5\", className)}\n {...props}\n />\n));\nDropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;\n\n/** @experimental */\nconst DropdownMenuShortcut = React.forwardRef<\n HTMLSpanElement,\n React.HTMLAttributes<HTMLSpanElement>\n>(({ className, ...props }, ref) => {\n return (\n <span\n ref={ref}\n className={cn(\"ml-auto text-xs tracking-widest opacity-60\", className)}\n {...props}\n />\n );\n});\nDropdownMenuShortcut.displayName = \"DropdownMenuShortcut\";\n\nexport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuGroup,\n DropdownMenuPortal,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuRadioGroup,\n};\n","import * as SelectPrimitive from \"@radix-ui/react-select\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { Check, ChevronDown, ChevronUp } from \"lucide-react\";\nimport type { ComponentProps } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\n\n/**\n * Select Component - Design System Specification\n *\n * Dropdown selection component for choosing from a list of options. Built on\n * Radix UI for robust accessibility and portal rendering.\n *\n * Accessibility:\n * - Full keyboard navigation (Arrow keys, Enter, Escape, Type-ahead)\n * - Proper ARIA attributes provided by Radix UI\n * - Screen reader announcements for selected value\n * - Focus management and keyboard shortcuts\n * - Disabled state support\n *\n * Design Specs:\n * - Height: sm=36px, default=40px, lg=44px (matches Input component)\n * - Padding: Horizontal 12px, vertical varies by size\n * - Border radius: `rounded-md` on the trigger, `rounded-lg` on the panel\n * - Border: 1px solid, changes on focus/error\n * - Transition: 150ms (consistent with design system)\n * - Font size: sm/default=14px (text-sm), lg=16px (text-base)\n *\n * Size Variants:\n * - sm: Height 36px - Compact forms and filters, matching a small Button\n * - default: Height 40px (h-10) - Standard forms\n * - lg: Height 44px (h-11) - Prominent selects\n *\n * Features:\n * - Portal rendering via PortalProvider (avoids overflow issues)\n * - CheckIcon indicator for selected items\n * - Keyboard type-ahead search\n * - Grouping support with labels\n * - Placeholder text support\n * - Error state via aria-invalid\n * @public\n */\nfunction Select({ ...props }: ComponentProps<typeof SelectPrimitive.Root>) {\n return <SelectPrimitive.Root data-slot=\"select\" {...props} />;\n}\n\n/** @experimental */\nfunction SelectGroup({\n ...props\n}: ComponentProps<typeof SelectPrimitive.Group>) {\n return <SelectPrimitive.Group data-slot=\"select-group\" {...props} />;\n}\n\n/** @public */\nfunction SelectValue({\n ...props\n}: ComponentProps<typeof SelectPrimitive.Value>) {\n return <SelectPrimitive.Value data-slot=\"select-value\" {...props} />;\n}\n\n/** @experimental */\nconst selectTriggerVariants = cva(\n // hover:border-primary (full strength) keeps the hover boundary more visible\n // than the resting border-input, not a fainter alpha of it.\n \"flex w-full items-center justify-between gap-2 rounded-md border border-input bg-background px-3 text-sm text-foreground cursor-pointer transition-all duration-150 focus:border-primary! focus-visible:border-primary! focus:outline-none hover:border-primary disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-primary/5 data-[placeholder]:text-muted-foreground aria-[invalid=true]:border-destructive aria-[invalid=true]:focus:border-destructive! [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4\",\n {\n variants: {\n size: {\n // `-md`, matching Button and Input: one height for one size name. A\n // select sitting beside a small button in a filter row is the case that\n // makes a 4px difference visible.\n sm: \"h-[var(--nx-control-height-md)] text-sm\",\n default: \"h-[var(--nx-control-height)] text-sm\",\n lg: \"h-[var(--nx-control-height-lg)] text-base\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n }\n);\n\n/** @public */\nexport interface SelectTriggerProps\n extends ComponentProps<typeof SelectPrimitive.Trigger>,\n VariantProps<typeof selectTriggerVariants> {}\n\n/** @public */\nconst SelectTrigger = forwardRef<\n React.ElementRef<typeof SelectPrimitive.Trigger>,\n SelectTriggerProps\n>(({ className, size, children, ...props }, ref) => {\n return (\n <SelectPrimitive.Trigger\n ref={ref}\n data-slot=\"select-trigger\"\n className={cn(selectTriggerVariants({ size, className }))}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <ChevronDown className=\"size-4 opacity-50\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n );\n});\n\nSelectTrigger.displayName = \"SelectTrigger\";\n\n/** @public */\nfunction SelectContent({\n className,\n children,\n position = \"popper\",\n ...props\n}: ComponentProps<typeof SelectPrimitive.Content>) {\n const portalContainer = usePortalContainer();\n\n return (\n <SelectPrimitive.Portal container={portalContainer}>\n <SelectPrimitive.Content\n data-slot=\"select-content\"\n className={cn(\n \"bg-popover text-popover-foreground border border-border shadow-none rounded-lg z-9999 max-h-(--radix-select-content-available-height) min-w-32 overflow-hidden data-[state=open]:animate-zoom-in-95 data-[state=closed]:animate-zoom-out-95 data-[side=bottom]:animate-slide-in-from-top-2 data-[side=left]:animate-slide-in-from-right-2 data-[side=right]:animate-slide-in-from-left-2 data-[side=top]:animate-slide-in-from-bottom-2\",\n position === \"popper\" &&\n \"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1\",\n className\n )}\n position={position}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n \"p-1\",\n position === \"popper\" &&\n \"h-(--radix-select-trigger-height) w-full min-w-(--radix-select-trigger-width) scroll-my-1\"\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n );\n}\n\n/** @experimental */\nfunction SelectLabel({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.Label>) {\n return (\n <SelectPrimitive.Label\n data-slot=\"select-label\"\n className={cn(\"text-muted-foreground px-2 py-1.5 text-xs\", className)}\n {...props}\n />\n );\n}\n\n/** @public */\nfunction SelectItem({\n className,\n children,\n ...props\n}: ComponentProps<typeof SelectPrimitive.Item>) {\n return (\n <SelectPrimitive.Item\n data-slot=\"select-item\"\n className={cn(\n \"relative flex w-full cursor-pointer items-center gap-2 rounded-sm py-2 pr-8 pl-2 text-sm text-foreground outline-none select-none transition-colors hover-unified focus:bg-primary/5 focus:text-primary data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4\",\n className\n )}\n {...props}\n >\n <span className=\"absolute right-2 flex size-3.5 items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <Check className=\"size-4\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n );\n}\n\n/** @experimental */\nfunction SelectSeparator({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.Separator>) {\n return (\n <SelectPrimitive.Separator\n data-slot=\"select-separator\"\n className={cn(\"bg-border pointer-events-none -mx-1 my-1 h-px\", className)}\n {...props}\n />\n );\n}\n\n/** @experimental */\nfunction SelectScrollUpButton({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {\n return (\n <SelectPrimitive.ScrollUpButton\n data-slot=\"select-scroll-up-button\"\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n {...props}\n >\n <ChevronUp className=\"size-4\" />\n </SelectPrimitive.ScrollUpButton>\n );\n}\n\n/** @experimental */\nfunction SelectScrollDownButton({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {\n return (\n <SelectPrimitive.ScrollDownButton\n data-slot=\"select-scroll-down-button\"\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n {...props}\n >\n <ChevronDown className=\"size-4\" />\n </SelectPrimitive.ScrollDownButton>\n );\n}\n\nexport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectScrollDownButton,\n SelectScrollUpButton,\n SelectSeparator,\n SelectTrigger,\n selectTriggerVariants,\n SelectValue,\n};\n","\"use client\";\n\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\nimport type { SheetProps } from \"../types/sheet\";\n\n/**\n * Whether the enclosing sheet is modal, published to its own parts.\n *\n * Radix takes `modal` at the root and uses it to decide focus trapping and\n * whether the rest of the page is withdrawn from the accessibility tree. The\n * scrim is that same decision expressed visually, and it is rendered a level\n * down in `SheetContent`. Passing the root's answer down — rather than giving\n * the content a second prop of its own — keeps one answer to one question: a\n * caller cannot ask for a non-modal sheet and still get a scrim over the page\n * it deliberately left interactive.\n *\n * Declared above the component doc blocks on purpose. The bundler attaches a\n * doc comment to the declaration that follows it, so anything inserted between\n * a tagged comment and its declaration silently steals the tag.\n */\nconst SheetModalContext = React.createContext(true);\n\n// Note: the close icon is not rendered by default here. Consumers should import and render their preferred icon with `SheetClose`.\n\n/**\n * Sheet Component\n *\n * A dialog variant that slides in from the edges of the screen. Used for mobile\n * navigation drawers, side panels, and contextual overlays.\n *\n * Built on Radix UI Dialog with slide-in animations and overlay backdrop.\n *\n * ## Design Specifications\n *\n * - **Width**: 320px (sm), 400px (default), 512px (lg), 672px (xl), 100% (full)\n * - **Animation**: Slide-in from side (150ms duration)\n * - **Backdrop**: the `--nx-overlay` scrim, with backdrop blur\n * - **z-index**: 50 (both overlay and content - content renders on top via DOM order)\n * - **Border-radius**: 0 (full-screen edges)\n *\n * ## Accessibility\n *\n * - **Focus Trapping**: Focus is trapped within the sheet when open\n * - **Escape Key**: Closes sheet on Escape key press\n * - **Overlay Click**: Closes sheet when clicking outside\n * - **ARIA**: Proper dialog role and ARIA attributes\n * - **Keyboard Navigation**: Tab/Shift+Tab to navigate, Enter to activate\n *\n * ## Usage Examples\n *\n * ### Basic Mobile Navigation Drawer\n *\n * ```tsx\n * import { Sheet, SheetContent, SheetTrigger } from '@nextlyhq/ui';\n * import { Menu } from 'lucide-react';\n *\n * function MobileNav() {\n * return (\n * <Sheet>\n * <SheetTrigger asChild>\n * <button className=\"h-11 w-11 md:hidden\">\n * <Menu />\n * </button>\n * </SheetTrigger>\n * <SheetContent side=\"left\" className=\"w-72\">\n * <nav>\n * <a href=\"/dashboard\">Dashboard</a>\n * <a href=\"/users\">Users</a>\n * </nav>\n * </SheetContent>\n * </Sheet>\n * );\n * }\n * ```\n *\n * @see https://www.radix-ui.com/primitives/docs/components/dialog\n * @public\n */\nconst Sheet = ({ modal = true, children, ...props }: SheetProps) => (\n <SheetModalContext.Provider value={modal}>\n <DialogPrimitive.Root modal={modal} {...props}>\n {children}\n </DialogPrimitive.Root>\n </SheetModalContext.Provider>\n);\nSheet.displayName = \"Sheet\";\n\n/** @experimental */\nconst SheetTrigger = DialogPrimitive.Trigger;\n\n/** @experimental */\nconst SheetClose = DialogPrimitive.Close;\n\n/** @experimental */\nconst SheetPortal = DialogPrimitive.Portal;\n\n/**\n * SheetOverlay\n *\n * Semi-transparent backdrop that appears behind the sheet.\n *\n * - **Background**: the `--nx-overlay` scrim + backdrop blur\n * - **Animation**: Fade in/out (150ms)\n * - **z-index**: 50\n * @experimental\n */\nconst SheetOverlay = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n className={cn(\n // A modal scrim, from the `--nx-overlay` token rather than a surface\n // token. A black wash is the point — painting it from `background` would\n // make it a white veil in light mode — but the alpha still has to differ\n // per mode, because what it composites over is white in one and mid-tone\n // in the other.\n \"fixed inset-0 z-50 bg-overlay backdrop-blur-sm\",\n \"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className\n )}\n {...props}\n ref={ref}\n />\n));\nSheetOverlay.displayName = DialogPrimitive.Overlay.displayName;\n\n/**\n * Sheet Content Variants\n *\n * Defines slide-in animations for each side and size options.\n * @experimental\n */\nconst sheetVariants = cva(\n \"fixed z-50 gap-4 bg-background p-6 shadow-lg will-change-transform transition ease-in-out data-[state=closed]:duration-150 data-[state=open]:duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out\",\n {\n variants: {\n side: {\n top: \"inset-x-0 top-0 border-b border-border data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top\",\n bottom:\n \"inset-x-0 bottom-0 border-t border-border data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom\",\n left: \"inset-y-0 left-0 h-full w-3/4 border-r border-border data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm\",\n right:\n \"inset-y-0 right-0 h-full w-3/4 border-l border-border data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm\",\n },\n },\n defaultVariants: {\n side: \"right\",\n },\n }\n);\n\n/** @public */\nexport interface SheetContentProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>,\n VariantProps<typeof sheetVariants> {}\n\n/**\n * SheetContent\n *\n * Main content container for the sheet.\n *\n * - **Position**: Fixed to screen edge (side prop)\n * - **Width**: Responsive (w-3/4 on mobile, max-w-sm on sm+)\n * - **Padding**: 24px (p-6)\n * - **Border**: On appropriate edge based on side\n * - **Close Button**: Positioned in top-right corner (16px from edges)\n *\n * @param side - Which edge to slide in from: \"left\", \"right\", \"top\", \"bottom\"\n * @public\n */\nconst SheetContent = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Content>,\n SheetContentProps\n>(({ side = \"right\", className, children, ...props }, ref) => {\n const portalContainer = usePortalContainer();\n // Taken from the root rather than from a prop here: the scrim and Radix's\n // inerting are the same decision, and two places to state it would let a\n // sheet scrim a page it had left interactive.\n const modal = React.useContext(SheetModalContext);\n\n return (\n <SheetPortal container={portalContainer}>\n {modal ? <SheetOverlay /> : null}\n <DialogPrimitive.Content\n ref={ref}\n data-slot=\"sheet-content\"\n className={cn(sheetVariants({ side }), className)}\n {...props}\n >\n {children}\n </DialogPrimitive.Content>\n </SheetPortal>\n );\n});\nSheetContent.displayName = DialogPrimitive.Content.displayName;\n\n/**\n * SheetHeader\n *\n * Header section for sheet title and description.\n *\n * - **Layout**: Flex column with 6px gap\n * - **Text Alignment**: Left (default) or center\n * @public\n */\nconst SheetHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className\n )}\n {...props}\n />\n);\nSheetHeader.displayName = \"SheetHeader\";\n\n/**\n * SheetFooter\n *\n * Footer section for sheet actions (buttons, etc.).\n *\n * - **Layout**: Flex row on desktop, column on mobile\n * - **Alignment**: Right-aligned on desktop, stretched on mobile\n * @experimental\n */\nconst SheetFooter = ({\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);\nSheetFooter.displayName = \"SheetFooter\";\n\n/**\n * SheetTitle\n *\n * Title heading for the sheet (h2).\n *\n * - **Font**: text-lg font-semibold\n * - **Color**: text-foreground\n * - **Required**: For accessibility (screen readers)\n * @public\n */\nconst SheetTitle = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\"text-lg font-semibold text-foreground\", className)}\n {...props}\n />\n));\nSheetTitle.displayName = DialogPrimitive.Title.displayName;\n\n/**\n * SheetDescription\n *\n * Description text for the sheet.\n *\n * - **Font**: text-sm\n * - **Color**: text-muted-foreground\n * - **Purpose**: Provide context for screen readers\n * @public\n */\nconst SheetDescription = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nSheetDescription.displayName = DialogPrimitive.Description.displayName;\n\nexport {\n Sheet,\n SheetPortal,\n SheetOverlay,\n SheetTrigger,\n SheetClose,\n SheetContent,\n SheetHeader,\n SheetFooter,\n SheetTitle,\n SheetDescription,\n sheetVariants,\n};\n","\"use client\";\n\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport {\n Command as CommandPrimitive,\n defaultFilter,\n useCommandState as useCommandStatePrimitive,\n} from \"cmdk\";\nimport { Search } from \"lucide-react\";\nimport type {\n ElementRef,\n ComponentPropsWithoutRef,\n HTMLAttributes,\n} from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\n\n/**\n * Command Component\n *\n * A command palette component built on cmdk for fast, keyboard-driven navigation and actions.\n * Supports fuzzy search, keyboard navigation, and WCAG 2.2 AA accessibility.\n *\n * @example\n * ```tsx\n * <Command>\n * <CommandInput placeholder=\"Type a command or search...\" />\n * <CommandList>\n * <CommandEmpty>No results found.</CommandEmpty>\n * <CommandGroup heading=\"Navigation\">\n * <CommandItem>\n * <Home className=\"mr-2 h-4 w-4\" />\n * Dashboard\n * </CommandItem>\n * </CommandGroup>\n * </CommandList>\n * </Command>\n * ```\n *\n * @design-spec\n * - Input height: 48px (h-12) - larger for prominence\n * - Item height: 36px (h-9) desktop, 44px (h-11) mobile for touch\n * - Border radius: `rounded-lg` for the panel, `rounded-sm` for items\n * - Max list height: 400px (max-h-[400px])\n * - Transition: 150ms per design system\n *\n * @accessibility\n * - Full keyboard navigation (Arrow keys, Enter, Escape, Home, End)\n * - ARIA attributes (role=\"combobox\", role=\"listbox\", role=\"option\")\n * - Screen reader announcements for results\n * - Focus management and visual focus indicators\n * - WCAG 2.2 AA compliant (verified contrast ratios)\n * @experimental\n */\n\nexport type CommandProps = ComponentPropsWithoutRef<typeof CommandPrimitive>;\n\n/**\n * Command - Root container for the command palette.\n * Handles filtering, keyboard navigation, and accessibility.\n * @experimental\n */\nconst Command = forwardRef<ElementRef<typeof CommandPrimitive>, CommandProps>(\n ({ className, ...props }, ref) => (\n <CommandPrimitive\n ref={ref}\n className={cn(\n \"flex h-full w-full flex-col overflow-hidden rounded-lg bg-background text-foreground\",\n className\n )}\n {...props}\n />\n )\n);\nCommand.displayName = \"Command\";\n\n/** @experimental */\nexport interface CommandDialogProps extends DialogPrimitive.DialogProps {\n /**\n * Passed to the command root this dialog renders internally.\n *\n * A seam rather than a list of forwarded props, because the settings a caller needs from the\n * root are the ones this component happens not to have thought of: `label`, which supplies the\n * search input's accessible name (cmdk renders an EMPTY hidden label without it, and an empty\n * `aria-labelledby` reference is worse than none — it stops the placeholder naming the field);\n * `filter` and `shouldFilter`, which decide match order; and `vimBindings`, which claims Ctrl+K\n * and Ctrl+N inside the list.\n *\n * `children` is excluded because this component owns the dialog's contents.\n */\n commandProps?: Omit<ComponentPropsWithoutRef<typeof Command>, \"children\">;\n /**\n * Passed to the dialog content this component renders internally.\n *\n * The seam that matters here is `onCloseAutoFocus`: this dialog has no trigger, so Radix has\n * nothing to hand focus back to, and it fires this at the point focus is actually being\n * returned — after the exit animation, which a timer set at close time cannot know the length\n * of. `className` is excluded because this component owns the dialog's own layout.\n */\n contentProps?: Omit<\n ComponentPropsWithoutRef<typeof DialogPrimitive.Content>,\n \"children\" | \"className\"\n >;\n}\n\n/**\n * CommandDialogOverlay - Custom overlay for CommandDialog with proper z-index.\n * Uses z-[99] to stay below CommandDialog content (z-[100]) but above regular dialogs.\n */\nconst CommandDialogOverlay = forwardRef<\n ElementRef<typeof DialogPrimitive.Overlay>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\n // A modal scrim, from the `--nx-overlay` token rather than a surface\n // token. A black wash is the point — painting it from `background` would\n // make it a white veil in light mode — but the alpha still has to differ\n // per mode, because what it composites over is white in one and mid-tone\n // in the other.\n \"fixed inset-0 z-[99] bg-overlay backdrop-blur-sm\",\n \"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n \"transition-opacity duration-200\",\n className\n )}\n {...props}\n />\n));\nCommandDialogOverlay.displayName = \"CommandDialogOverlay\";\n\n/**\n * CommandDialog - Command palette in a modal dialog.\n * Use this variant for Cmd+K keyboard shortcut pattern.\n *\n * @example\n * ```tsx\n * const [open, setOpen] = useState(false)\n *\n * useEffect(() => {\n * const down = (e: KeyboardEvent) => {\n * if (e.key === \"k\" && (e.metaKey || e.ctrlKey)) {\n * e.preventDefault()\n * setOpen((open) => !open)\n * }\n * }\n * document.addEventListener(\"keydown\", down)\n * return () => document.removeEventListener(\"keydown\", down)\n * }, [])\n *\n * return (\n * <CommandDialog open={open} onOpenChange={setOpen}>\n * <CommandInput placeholder=\"Type a command...\" />\n * <CommandList>...</CommandList>\n * </CommandDialog>\n * )\n * ```\n * @experimental\n */\nconst CommandDialog = ({\n children,\n commandProps,\n contentProps,\n ...props\n}: CommandDialogProps) => {\n const portalContainer = usePortalContainer();\n\n return (\n <DialogPrimitive.Root {...props}>\n <DialogPrimitive.Portal container={portalContainer}>\n <CommandDialogOverlay />\n <DialogPrimitive.Content\n {...contentProps}\n data-slot=\"command-content\"\n className={cn(\n // Position\n \"fixed left-[50%] top-[50%] z-[100] translate-x-[-50%] translate-y-[-50%]\",\n // Size - responsive\n \"w-full max-w-lg\",\n \"max-h-[85vh]\", // Slightly shorter than design spec to ensure safe area\n // Mobile adjustments\n \"sm:max-w-lg\", // 512px on desktop\n \"max-w-full\", // Full width on mobile\n // Spacing\n \"m-4 sm:m-0\", // 16px margin on mobile, no margin on desktop\n // Visual\n \"overflow-hidden rounded-lg border border-border bg-background shadow-xl\",\n // Animation\n \"duration-200\",\n \"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n \"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n \"data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-top-[48%]\"\n )}\n >\n <Command\n {...commandProps}\n className={cn(\n \"[&_[cmdk-group-heading]]:px-3 [&_[cmdk-group-heading]]:py-2 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-wide [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:mb-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-3 [&_[cmdk-item]]:py-2 [&_[cmdk-item]_svg]:h-4 [&_[cmdk-item]_svg]:w-4\",\n // Merged rather than overridden: a caller passing `className` for its own reason\n // would otherwise silently drop every layout rule this dialog depends on.\n commandProps?.className\n )}\n >\n {children}\n </Command>\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n </DialogPrimitive.Root>\n );\n};\n\n/** @experimental */\nexport type CommandInputProps = ComponentPropsWithoutRef<\n typeof CommandPrimitive.Input\n>;\n\n/**\n * CommandInput - Search input field for filtering commands.\n * Includes search icon and styled per design system.\n * @experimental\n */\nconst CommandInput = forwardRef<\n ElementRef<typeof CommandPrimitive.Input>,\n CommandInputProps\n>(({ className, ...props }, ref) => (\n <div\n className=\"flex items-center border-b border-border px-4\"\n // cmdk-input-wrapper is the attribute the cmdk library targets\n // in its built-in stylesheet to scope wrapper-level styles.\n // Required by the library; not a typo.\n // eslint-disable-next-line react/no-unknown-property\n cmdk-input-wrapper=\"\"\n >\n <Search className=\"mr-3 h-5 w-5 shrink-0 text-muted-foreground\" />\n <CommandPrimitive.Input\n ref={ref}\n className={cn(\n // Size\n \"flex h-12 w-full\",\n // Visual\n \"bg-transparent text-base\",\n \"outline-none\",\n // Typography\n \"placeholder:text-muted-foreground\",\n // States\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n // Prevent iOS zoom on focus\n \"text-base md:text-sm\",\n className\n )}\n {...props}\n />\n </div>\n));\nCommandInput.displayName = \"CommandInput\";\n\n/** @experimental */\nexport type CommandListProps = ComponentPropsWithoutRef<\n typeof CommandPrimitive.List\n>;\n\n/**\n * CommandList - Scrollable container for command results.\n * Max height 400px per design spec to prevent tall dialogs.\n * @experimental\n */\nconst CommandList = forwardRef<\n ElementRef<typeof CommandPrimitive.List>,\n CommandListProps\n>(({ className, ...props }, ref) => (\n <CommandPrimitive.List\n ref={ref}\n className={cn(\n // Scroll\n \"max-h-[400px] overflow-y-auto overflow-x-hidden\",\n // Spacing\n \"p-2\",\n className\n )}\n {...props}\n />\n));\nCommandList.displayName = \"CommandList\";\n\n/** @experimental */\nexport type CommandEmptyProps = ComponentPropsWithoutRef<\n typeof CommandPrimitive.Empty\n>;\n\n/**\n * CommandEmpty - Empty state message when no results found.\n * Centered text with muted color per design spec.\n * @experimental\n */\nconst CommandEmpty = forwardRef<\n ElementRef<typeof CommandPrimitive.Empty>,\n CommandEmptyProps\n>((props, ref) => (\n <CommandPrimitive.Empty\n ref={ref}\n className=\"py-8 px-4 text-center text-sm text-muted-foreground\"\n {...props}\n />\n));\nCommandEmpty.displayName = \"CommandEmpty\";\n\n/** @experimental */\nexport type CommandGroupProps = ComponentPropsWithoutRef<\n typeof CommandPrimitive.Group\n>;\n\n/**\n * CommandGroup - Grouped section of commands with optional heading.\n * Heading styled as uppercase, small, semibold per design spec.\n * @experimental\n */\nconst CommandGroup = forwardRef<\n ElementRef<typeof CommandPrimitive.Group>,\n CommandGroupProps\n>(({ className, ...props }, ref) => (\n <CommandPrimitive.Group\n ref={ref}\n className={cn(\n // Spacing\n \"space-y-1 mb-2\",\n // Heading styling applied via parent Command className\n \"[&_[cmdk-group-heading]]:px-3 [&_[cmdk-group-heading]]:py-2 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-wide\",\n className\n )}\n {...props}\n />\n));\nCommandGroup.displayName = \"CommandGroup\";\n\n/** @experimental */\nexport type CommandSeparatorProps = ComponentPropsWithoutRef<\n typeof CommandPrimitive.Separator\n>;\n\n/**\n * CommandSeparator - Visual divider between command groups.\n * 1px line with border border-border color, 8px margin top/bottom.\n * @experimental\n */\nconst CommandSeparator = forwardRef<\n ElementRef<typeof CommandPrimitive.Separator>,\n CommandSeparatorProps\n>(({ className, ...props }, ref) => (\n <CommandPrimitive.Separator\n ref={ref}\n className={cn(\"h-px bg-border my-2\", className)}\n {...props}\n />\n));\nCommandSeparator.displayName = \"CommandSeparator\";\n\n/** @experimental */\nexport type CommandItemProps = ComponentPropsWithoutRef<\n typeof CommandPrimitive.Item\n>;\n\n/**\n * CommandItem - Individual selectable command item.\n * Height: 36px desktop, 44px mobile per design spec.\n * Includes hover, focus, and selected states.\n * @experimental\n */\nconst CommandItem = forwardRef<\n ElementRef<typeof CommandPrimitive.Item>,\n CommandItemProps\n>(({ className, ...props }, ref) => (\n <CommandPrimitive.Item\n ref={ref}\n className={cn(\n // Layout\n \"relative flex cursor-pointer select-none items-center gap-3\",\n // Size\n \"min-h-[44px] sm:min-h-[36px]\", // Flexible height with minimal touch targets\n // Spacing\n \"px-3 py-2.5\",\n // Visual\n \"rounded-sm text-base sm:text-sm outline-none\",\n // Transitions\n \"transition-all duration-200 ease-(--ease-premium)\",\n // Hover state - shared dashboard hover treatment\n \"hover-unified\",\n // Selected/focused state (keyboard navigation)\n \"aria-selected:bg-primary/5 aria-selected:text-primary\",\n \"data-[selected=true]:bg-primary/5 data-[selected=true]:text-primary\",\n // Disabled state\n \"data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50\",\n className\n )}\n {...props}\n />\n));\nCommandItem.displayName = \"CommandItem\";\n\n/** @experimental */\nexport type CommandShortcutProps = HTMLAttributes<HTMLSpanElement>;\n\n/**\n * CommandShortcut - Keyboard shortcut display (e.g., \"⌘K\", \"↵ Enter\").\n * Monospace font, subtle background, right-aligned per design spec.\n * @experimental\n */\nconst CommandShortcut = forwardRef<HTMLSpanElement, CommandShortcutProps>(\n ({ className, ...props }, ref) => {\n return (\n <span\n ref={ref}\n className={cn(\n // Position\n \"ml-auto\",\n // Typography\n \"text-xs font-mono\",\n // Visual\n \"text-muted-foreground bg-primary/5\",\n \"border border-border rounded-md\",\n // Spacing\n \"px-1.5 py-0.5\",\n className\n )}\n {...props}\n />\n );\n }\n);\nCommandShortcut.displayName = \"CommandShortcut\";\n\nexport {\n Command,\n CommandDialog,\n CommandInput,\n CommandList,\n CommandEmpty,\n CommandGroup,\n CommandItem,\n CommandSeparator,\n CommandShortcut,\n};\n\n/**\n * The command palette's default match scorer, re-exported.\n *\n * A caller that overrides `filter` — to keep an opaque item value out of the scoring, say — still\n * wants the ranking that comes for free, and reaching for `cmdk` directly is not open to every\n * package here.\n *\n * Bound to a declaration rather than re-exported with `export { x as y }`: the bundler keeps a doc\n * comment attached to a declaration and drops one attached to an export statement, so the release\n * tag would not reach the published types.\n *\n * @experimental\n */\nexport const commandDefaultFilter = defaultFilter;\n\n/**\n * The value of the item the palette has HIGHLIGHTED, from a component inside\n * it.\n *\n * The palette owns which item is highlighted, and it moves that highlight for\n * reasons a caller never sees: a pointer crossing an item, an arrow key, and a\n * filter that removes the item the highlight was on. Anything outside wanting\n * to follow it — a preview pane, a description strip, a status line — needs to\n * read that rather than keep a copy.\n *\n * Reading beats mirroring here for a specific reason rather than on principle.\n * The palette's controlled `value` sets which item is MARKED, and does not move\n * the internal cursor that `aria-activedescendant` and the scroll follow. So a\n * caller that writes the value to steer the highlight desynchronises the two:\n * the item drawn as current and the option announced as current stop agreeing,\n * and after a filter the announcement can name an element that has been\n * removed. A read leaves one owner and takes a derived view.\n *\n * NARROWED to the one field deliberately. The underlying library exposes its\n * whole store through a selector — the raw search text, its internal item and\n * group maps, the id it uses for `aria-activedescendant` — and publishing that\n * selector would make every one of those part of this kit's public API and its\n * generated declarations. A dependency upgrade could then reshape what callers\n * can reach without any export changing name, which is exactly what the\n * surface snapshot cannot see. This returns a string.\n *\n * Empty string means nothing is highlighted, which is the library's own\n * spelling and a different answer from \"an item whose value is unknown\".\n *\n * Must be called from inside the palette, since that is where the state lives.\n *\n * Bound to a declaration rather than re-exported with `export { x as y }`: the\n * bundler keeps a doc comment attached to a declaration and drops one attached\n * to an export statement, so the release tag would not reach the published\n * types.\n *\n * @experimental\n */\nexport const useCommandHighlight = (): string =>\n useCommandStatePrimitive(state => state.value);\n","import { cva, type VariantProps } from \"class-variance-authority\";\nimport { Loader2, type LucideProps } from \"lucide-react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * Spinner Component - Design System Specification\n *\n * Loading indicator for short wait times (300ms - 1s). Uses the Loader2 icon from\n * lucide-react with a smooth rotation animation.\n *\n * **Usage Guidelines** (from UX Strategy):\n * - ✅ Use for buttons and small components (loading states)\n * - ✅ Use for short waits (300ms - 1s)\n * - ❌ Don't use for page content (use Skeleton instead)\n * - ❌ Don't use for waits > 3s (use Progress bar instead)\n *\n * **Sizes**:\n * - sm: 16px (h-4 w-4) - For small buttons, inline text\n * - md: 20px (h-5 w-5) - Default size, for regular buttons\n * - lg: 24px (h-6 w-6) - For large buttons, prominent loading states\n *\n * **Accessibility**:\n * - Uses `role=\"status\"` for screen reader announcements\n * - Uses `aria-label=\"Loading\"` for accessible name\n * - Respects `prefers-reduced-motion` (animation stops automatically via Tailwind)\n * - Non-focusable (not interactive)\n *\n * **Animation**:\n * - Uses Tailwind's `animate-spin` utility (1s linear infinite)\n * - Automatically respects user's motion preferences (WCAG 2.3.3)\n *\n * @example\n * // Button loading state\n * <Button disabled>\n * <Spinner size=\"sm\" className=\"mr-2\" />\n * Saving...\n * </Button>\n *\n * @example\n * // Standalone loading indicator\n * <div className=\"flex items-center justify-center p-8\">\n * <Spinner size=\"lg\" />\n * </div>\n *\n * @example\n * // Custom color\n * <Spinner className=\"text-primary\" />\n * @experimental\n */\nconst spinnerVariants = cva(\"animate-spin motion-reduce:animate-none\", {\n variants: {\n size: {\n sm: \"h-4 w-4\",\n md: \"h-5 w-5\",\n lg: \"h-6 w-6\",\n },\n },\n defaultVariants: {\n size: \"md\",\n },\n});\n\n/**\n * Spinner component props\n *\n * Extends LucideProps to support all standard SVG attributes (data-*, id, etc.)\n * while providing size variants and accessibility features.\n * @experimental\n */\nexport type SpinnerProps = Omit<LucideProps, \"size\"> &\n VariantProps<typeof spinnerVariants> & {\n /**\n * Accessible label for screen readers\n * @default \"Loading\"\n */\n \"aria-label\"?: string;\n };\n\n/**\n * Spinner component for loading states\n * @experimental\n */\nconst Spinner = forwardRef<SVGSVGElement, SpinnerProps>(\n (\n { size = \"md\", className, \"aria-label\": ariaLabel = \"Loading\", ...props },\n ref\n ) => {\n return (\n <Loader2\n ref={ref}\n role=\"status\"\n aria-label={ariaLabel}\n className={cn(spinnerVariants({ size }), className)}\n {...props}\n />\n );\n }\n);\n\nSpinner.displayName = \"Spinner\";\n\nexport { Spinner, spinnerVariants };\n","\"use client\";\n\nimport {\n CheckCircle2,\n AlertCircle,\n AlertTriangle,\n XCircle,\n Loader2,\n} from \"lucide-react\";\nimport { toast, Toaster as Sonner, type ToasterProps } from \"sonner\";\n\n// Re-export toast function for convenient usage\nexport { toast };\n\n/**\n * Toaster Component - Toast Notification System\n *\n * A wrapper around Sonner (opinionated toast component for React) with\n * custom icons. Provides a consistent notification system across the application.\n *\n * Features:\n * - Theme support via `theme` prop (light/dark/system)\n * - Custom icons from lucide-react matching design system\n * - 6 toast types: default, success, info, warning, error, loading (promise-based)\n * - Action button support (Undo, Retry, etc.)\n * - Configurable positioning (default: bottom-right)\n * - Automatic stacking and dismissal\n * - WCAG 2.2 AA compliant colors via CSS variables\n *\n * Setup:\n * 1. Add <Toaster /> to your root layout (once per app)\n * 2. Import toast from '@nextlyhq/ui' to trigger notifications\n *\n * Usage Examples:\n *\n * // Default toast\n * import { toast } from '@nextlyhq/ui';\n * toast(\"Event has been created\");\n *\n * // Success toast\n * toast.success(\"User created successfully!\");\n *\n * // Error toast\n * toast.error(\"Failed to save changes. Please try again.\");\n *\n * // Warning toast\n * toast.warning(\"This action cannot be undone.\");\n *\n * // Info toast\n * toast.info(\"Be at the area 10 minutes before the event time\");\n *\n * // Toast with action button\n * toast(\"Event deleted\", {\n * description: \"You can undo this action\",\n * action: {\n * label: \"Undo\",\n * onClick: () => console.log(\"Undo clicked\"),\n * },\n * });\n *\n * // Promise-based toast (loading → success/error)\n * toast.promise(\n * fetchData(),\n * {\n * loading: \"Loading...\",\n * success: (data) => `${data.name} has been created`,\n * error: \"Failed to load data\",\n * }\n * );\n *\n * Positioning Options:\n * <Toaster position=\"top-right\" />\n * <Toaster position=\"top-center\" />\n * <Toaster position=\"bottom-left\" />\n * <Toaster position=\"bottom-center\" />\n * <Toaster position=\"bottom-right\" /> (default)\n *\n * Customization:\n * All styling uses CSS variables from the design system:\n * - --normal-bg: Background color (uses --nx-popover with fallback)\n * - --normal-text: Text color (uses --nx-popover-foreground with fallback)\n * - --normal-border: Border color (uses --nx-border with fallback)\n * - --border-radius: Border radius (uses --radius with fallback)\n *\n * Security:\n * ⚠️ IMPORTANT: Toast content is not automatically sanitized. When displaying\n * user-generated content or data from external sources, ensure you sanitize\n * the content to prevent XSS attacks. Use plain text strings when possible,\n * or sanitize HTML/JSX content before passing to toast functions.\n *\n * Safe: toast.success(`User ${username} created`) // Template literals with plain text\n * Unsafe: toast.success(<div dangerouslySetInnerHTML={{__html: userInput}} />) // XSS risk\n * Safe: toast.success(<div>{sanitizeHtml(userInput)}</div>) // Sanitized content\n *\n * Accessibility:\n * - Screen reader announcements for all toast types\n * - Keyboard dismissible (Escape key)\n * - Focus management for action buttons\n * - ARIA labels automatically applied\n * - WCAG 2.2 AA color contrast\n *\n * @see https://sonner.emilkowal.ski/ - Sonner documentation\n * @see https://ui.shadcn.com/docs/components/sonner - shadcn/ui integration guide\n * @experimental\n */\nexport function Toaster({ theme = \"system\", ...props }: ToasterProps) {\n return (\n <Sonner\n theme={theme}\n className=\"toaster group bg-transparent! overflow-visible! z-[9999]!\"\n data-slot=\"toaster\"\n toastOptions={{\n classNames: {\n description: \"text-muted-foreground\",\n },\n }}\n icons={{\n success: <CheckCircle2 className=\"h-4 w-4\" />,\n info: <AlertCircle className=\"h-4 w-4\" />,\n warning: <AlertTriangle className=\"h-4 w-4\" />,\n error: <XCircle className=\"h-4 w-4\" />,\n loading: <Loader2 className=\"h-4 w-4 animate-spin\" />,\n }}\n style={\n {\n \"--normal-bg\": \"var(--nx-popover)\",\n \"--normal-text\": \"var(--nx-popover-foreground)\",\n \"--normal-border\": \"var(--nx-border)\",\n \"--border-radius\": \"0px\",\n } as React.CSSProperties\n }\n {...props}\n />\n );\n}\n","import * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** @experimental */\nconst Table = React.forwardRef<\n HTMLTableElement,\n React.HTMLAttributes<HTMLTableElement>\n>(({ className, ...props }, ref) => (\n <div className=\"relative w-full overflow-auto\">\n <table\n ref={ref}\n className={cn(\"w-full caption-bottom text-sm\", className)}\n {...props}\n />\n </div>\n));\nTable.displayName = \"Table\";\n\n/** @experimental */\nconst TableHeader = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <thead\n ref={ref}\n className={cn(\"[&_tr]:border-b border-border\", className)}\n {...props}\n />\n));\nTableHeader.displayName = \"TableHeader\";\n\n/** @experimental */\nconst TableBody = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tbody\n ref={ref}\n className={cn(\"[&_tr:last-child]:border-0\", className)}\n {...props}\n />\n));\nTableBody.displayName = \"TableBody\";\n\n/** @experimental */\nconst TableFooter = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tfoot\n ref={ref}\n className={cn(\n \"border-t border-border font-medium [&>tr]:last:border-b-0\",\n className\n )}\n {...props}\n />\n));\nTableFooter.displayName = \"TableFooter\";\n\n/** @experimental */\nconst TableRow = React.forwardRef<\n HTMLTableRowElement,\n React.HTMLAttributes<HTMLTableRowElement>\n>(({ className, ...props }, ref) => (\n <tr\n ref={ref}\n className={cn(\n \"border-b border-border transition-colors data-[state=selected]:bg-primary/5\",\n className\n )}\n {...props}\n />\n));\nTableRow.displayName = \"TableRow\";\n\n/** @experimental */\nconst TableHead = React.forwardRef<\n HTMLTableCellElement,\n React.ThHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <th\n ref={ref}\n className={cn(\n \"h-11 px-4 text-left align-middle font-semibold text-xs text-foreground uppercase tracking-wider [&:has([role=checkbox])]:pr-0\",\n className\n )}\n {...props}\n />\n));\nTableHead.displayName = \"TableHead\";\n\n/** @experimental */\nconst TableCell = React.forwardRef<\n HTMLTableCellElement,\n React.TdHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <td\n ref={ref}\n className={cn(\n \"px-4 py-3 align-middle [&:has([role=checkbox])]:pr-0\",\n className\n )}\n {...props}\n />\n));\nTableCell.displayName = \"TableCell\";\n\n/** @experimental */\nconst TableCaption = React.forwardRef<\n HTMLTableCaptionElement,\n React.HTMLAttributes<HTMLTableCaptionElement>\n>(({ className, ...props }, ref) => (\n <caption\n ref={ref}\n className={cn(\"mt-4 text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nTableCaption.displayName = \"TableCaption\";\n\nexport {\n Table,\n TableHeader,\n TableBody,\n TableFooter,\n TableHead,\n TableRow,\n TableCell,\n TableCaption,\n};\n","import { Search, Loader2, X } from \"lucide-react\";\n\n/**\n * Props for TableSearch component\n * @experimental\n */\nexport interface TableSearchProps {\n /** Current search value */\n value: string;\n /** Callback when search value changes */\n onChange: (value: string) => void;\n /** Callback when clear button is clicked */\n onClear: () => void;\n /** Placeholder text for search input */\n placeholder?: string;\n /** Whether data is currently loading */\n isLoading?: boolean;\n /** Ref to the input element */\n inputRef?: React.RefObject<HTMLInputElement | null>;\n}\n\n/**\n * Search input component for tables\n *\n * Features:\n * - Search icon\n * - Clear button (when value is present)\n * - Loading spinner (when isLoading is true)\n * - Accessible with aria-busy attribute\n *\n * @example\n * ```tsx\n * <TableSearch\n * value={searchInput}\n * onChange={handleSearchChange}\n * onClear={handleClearSearch}\n * placeholder=\"Search users...\"\n * isLoading={loading}\n * />\n * ```\n * @experimental\n */\nexport function TableSearch({\n value,\n onChange,\n onClear,\n placeholder = \"Filter records...\",\n isLoading = false,\n inputRef,\n}: TableSearchProps) {\n return (\n <div className=\"relative w-full max-w-lg\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground\" />\n {/* The edge uses border-input, the identifying-boundary token, rather\n than the decorative border-border: an empty field has nothing else to\n identify it. Matches Input, Textarea, Checkbox and RadioGroup.\n border-input no longer meets 1.4.11's 3:1 minimum in light mode; see\n contrast/accepted.ts. The distinction it draws is still the right one\n to follow, but it is a statement of role, not of ratio. */}\n <input\n ref={inputRef}\n type=\"text\"\n placeholder={placeholder}\n value={value}\n onChange={e => onChange(e.target.value)}\n aria-busy={isLoading}\n className=\"h-10 w-full rounded-md border border-input bg-background pl-10 pr-10 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 transition-all\"\n />\n {(value || isLoading) && (\n <div className=\"absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-2\">\n {isLoading && (\n <Loader2 className=\"w-3.5 h-3.5 text-primary animate-spin\" />\n )}\n {value && (\n <button\n type=\"button\"\n onClick={onClear}\n className=\"text-muted-foreground hover:text-foreground transition-colors p-0.5 rounded-md hover:bg-primary/5\"\n aria-label=\"Clear search\"\n >\n <X className=\"w-3.5 h-3.5\" />\n </button>\n )}\n </div>\n )}\n </div>\n );\n}\n","import { AlertCircle, Loader2, FileQuestion } from \"lucide-react\";\n\n/**\n * Props for TableError component\n * @experimental\n */\nexport interface TableErrorProps {\n /** Error message to display */\n message?: string;\n}\n\n/**\n * Error state component for tables\n * @experimental\n */\nexport function TableError({\n message = \"An error occurred. Please try again.\",\n}: TableErrorProps) {\n return (\n <div className=\"flex items-center gap-2\">\n <AlertCircle className=\"w-4 h-4 shrink-0\" />\n <span>{message}</span>\n </div>\n );\n}\n\n/**\n * Loading state component for tables\n * @experimental\n */\nexport function TableLoading() {\n return (\n <div className=\"flex flex-col items-center justify-center gap-4 p-12 text-muted-foreground\">\n <Loader2 className=\"w-8 h-8 animate-spin text-primary/80\" />\n <span className=\"text-sm font-medium\">Loading data...</span>\n </div>\n );\n}\n\n/**\n * Props for TableEmpty component\n * @experimental\n */\nexport interface TableEmptyProps {\n /** Custom message to display when no data */\n message?: string;\n}\n\n/**\n * Empty state component for tables\n * @experimental\n */\nexport function TableEmpty({ message = \"No records found\" }: TableEmptyProps) {\n return (\n <div className=\"flex flex-col items-center justify-center gap-4 p-16 text-center text-muted-foreground\">\n <div className=\"flex h-12 w-12 items-center justify-center rounded-md bg-primary/5\">\n <FileQuestion className=\"h-6 w-6\" />\n </div>\n <span className=\"text-sm font-medium\">{message}</span>\n </div>\n );\n}\n","/**\n * TableSkeleton Component\n *\n * Generic loading skeleton for data tables.\n * Renders header, body, and footer skeleton bars inside a card.\n * Unified with EntryTable skeleton pattern for consistency across all tables.\n */\n\nimport type * as React from \"react\";\n\nimport { Skeleton } from \"./skeleton\";\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"./table\";\n\n/** Shared animated gray bar — Unified with design system Skeleton */\nconst GrayBar = ({ className }: { className?: string }) => (\n <Skeleton className={className} />\n);\n\n/** @experimental */\nexport interface TableSkeletonProps {\n columns?: number;\n rowCount?: number;\n hideWrapper?: boolean;\n hideFooter?: boolean;\n}\n\n/** @experimental */\nexport const TableSkeleton: React.FC<TableSkeletonProps> = ({\n columns = 5,\n rowCount = 8,\n hideWrapper = false,\n hideFooter = false,\n}) => {\n const content = (\n <>\n {/* Square corners: this fills the bordered table wrapper edge to edge. */}\n <div className=\"border-0 rounded-none shadow-none\">\n <Table>\n {/* Header Skeleton */}\n <TableHeader>\n <TableRow>\n {Array.from({ length: columns }).map((_, colIdx) => (\n <TableHead key={`skeleton-header-${colIdx}`} className=\"py-3\">\n {colIdx === 0 ? (\n <GrayBar className=\"h-4 w-4\" />\n ) : colIdx === columns - 1 ? (\n <div className=\"flex justify-center\">\n <Skeleton className=\"h-4 w-4 rounded-sm\" />\n </div>\n ) : colIdx === 1 ? (\n <GrayBar className=\"h-4 w-[70%] max-w-[180px]\" />\n ) : (\n <GrayBar className=\"h-4 w-[60%] max-w-[120px]\" />\n )}\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n\n {/* Body Skeleton */}\n <TableBody>\n {Array.from({ length: rowCount }).map((_, rowIdx) => (\n <TableRow key={rowIdx} className=\"border-b border-border\">\n {Array.from({ length: columns }).map((_, colIdx) => (\n <TableCell key={colIdx} className=\"py-3\">\n {colIdx === 0 ? (\n <GrayBar className=\"h-4 w-4\" />\n ) : colIdx === columns - 1 ? (\n <div className=\"flex justify-center\">\n <Skeleton className=\"h-8 w-8 rounded-md\" />\n </div>\n ) : colIdx === 1 ? (\n <div className=\"flex items-center gap-3\">\n <Skeleton className=\"w-9 rounded-md shrink-0\" />\n <div className=\"space-y-1.5 flex-1\">\n <Skeleton className=\"h-4 w-[120px]\" />\n <Skeleton className=\"h-3 w-[80px]\" />\n </div>\n </div>\n ) : (\n <GrayBar className=\"h-4 w-[60%] max-w-[120px]\" />\n )}\n </TableCell>\n ))}\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n\n {/* Footer Skeleton */}\n {!hideFooter && (\n <div className=\"table-footer border-t border-border\">\n {/* Axis utilities rather than the `p-4` shorthand: Tailwind emits `.px-2`\n and `.py-4` AFTER `.p-4`, so at equal specificity the shorthand loses\n both axes and contributes nothing. The footer is deliberately tighter\n horizontally than vertically. */}\n <div className=\"flex items-center justify-between px-2 py-4\">\n <div className=\"flex items-center gap-2 text-sm\">\n <GrayBar className=\"h-4 w-[120px]\" />\n </div>\n <div className=\"flex items-center gap-6\">\n <div className=\"flex items-center gap-2\">\n <GrayBar className=\"h-4 w-20\" />\n <GrayBar className=\"h-8 w-[70px]\" />\n </div>\n <div className=\"flex items-center gap-1\">\n <GrayBar className=\"h-8 w-8\" />\n <GrayBar className=\"h-8 w-8\" />\n <GrayBar className=\"h-8 w-8\" />\n <GrayBar className=\"h-8 w-8\" />\n <GrayBar className=\"h-8 w-8\" />\n </div>\n <GrayBar className=\"h-4 w-[120px]\" />\n </div>\n </div>\n </div>\n )}\n </>\n );\n\n if (hideWrapper) {\n return content;\n }\n\n return (\n <div className=\"table-wrapper rounded-md border border-border bg-card overflow-hidden\">\n {content}\n </div>\n );\n};\n\nTableSkeleton.displayName = \"TableSkeleton\";\n","\"use client\";\n\nimport { Pipette } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport type { Rgba } from \"../lib/color\";\nimport {\n hsvToRgb,\n hueAt,\n hueSliderValue,\n parseHex,\n pointOnSurface,\n rgbToHsv,\n saturationValueAt,\n surfacePointFor,\n toHex,\n} from \"../lib/color\";\nimport { useIsomorphicLayoutEffect } from \"../lib/isomorphic-layout-effect\";\nimport { cn } from \"../lib/utils\";\n\nimport { Button } from \"./button\";\nimport { Input } from \"./input\";\n\n/**\n * One preset a host offers.\n *\n * `color` is what the swatch is PAINTED with. `value` is what `onSwatchSelect`\n * hands back, unread by this component — a host storing design tokens puts its\n * own token reference there and receives it unchanged, so choosing a swatch\n * never resolves a token into the colour it currently happens to be. Without\n * that, re-theming stops moving the values that pointed at it.\n *\n * @experimental\n */\nexport interface ColorSwatch<TValue = string> {\n id: string;\n label: string;\n color: string;\n value?: TValue;\n}\n\n/**\n * Props for ColorPicker.\n * @experimental\n */\nexport interface ColorPickerProps<TValue = string> {\n /** The colour shown on the surface, as hex. */\n color: string;\n /** A colour was chosen by editing — surface, hue, alpha or the hex field. */\n onColorChange: (color: string) => void;\n /** Presets. Painted from `color`, returned by `value`. */\n swatches?: ColorSwatch<TValue>[];\n /**\n * A preset was chosen. Separate from `onColorChange` because only the host\n * can say what a swatch MEANS: the two are different events, and collapsing\n * them is what loses a token reference.\n */\n onSwatchSelect?: (swatch: ColorSwatch<TValue>) => void;\n /**\n * Recently used colours. Owned by the host, never by this component — the\n * admin scopes them per user, and a component writing `localStorage` at\n * render is unusable on a server and untestable without a DOM.\n */\n recentColors?: string[];\n /** Alpha channel. Off by default: most call sites want an opaque colour. */\n showAlpha?: boolean;\n className?: string;\n}\n\n/** The picker's own working state, kept in HSV so a drag does not lose hue. */\ninterface Hsva {\n h: number;\n s: number;\n v: number;\n a: number;\n}\n\nfunction toHsva(hex: string): Hsva {\n const parsed = parseHex(hex);\n if (!parsed) return { h: 0, s: 0, v: 0, a: 1 };\n const { r, g, b, alpha } = parsed;\n return { ...rgbToHsv({ r, g, b }), a: alpha };\n}\n\nfunction toHexString(hsva: Hsva, withAlpha: boolean): string {\n return toHex(hsvToRgb(hsva), withAlpha ? hsva.a : 1);\n}\n\n/** The last step of the hue strip. Kept beside the input it sizes. */\nconst HUE_MAX = 359;\n\n/**\n * A parsed colour as picker state, keeping the hue the surface already sits on\n * when the new colour has none of its own.\n *\n * Grey and black carry no hue, so `rgbToHsv` reports its documented fallback of\n * 0. Storing that discards where the user was: typing black while editing a\n * blue and then raising saturation returns RED. While saturation is 0 the\n * retained hue is invisible, so keeping it costs nothing and is the only thing\n * that makes the surface recoverable.\n */\nfunction hsvaFrom(color: Rgba, alpha: number, currentHue: number): Hsva {\n const hsv = rgbToHsv(color);\n return { ...hsv, h: hsv.s === 0 ? currentHue : hsv.h, a: alpha };\n}\n\n/**\n * A range input drawn by this component rather than by the browser.\n *\n * `appearance-none` removes the platform track, so every slider carrying it\n * owes a background of its own — one that does not is not a subtle styling\n * miss, it is an invisible control.\n */\nconst SLIDER = \"h-3 w-full cursor-pointer appearance-none rounded-full\";\n\n/**\n * The grey chequerboard that makes transparency legible.\n *\n * Fixed greys, deliberately, where the rest of this package uses theme tokens:\n * this is the standard rendering of \"nothing here\", and a chequerboard that\n * changed colour with the theme would read as part of the colour being edited.\n *\n * design-lint-ok: fixed greys are the point here; see above.\n */\nconst CHECKERBOARD = \"repeating-conic-gradient(#c8c8c8 0% 25%, #ffffff 0% 50%)\";\n\n/** Whether this browser can sample a colour from the screen. */\nfunction eyeDropperSupported(): boolean {\n // Chromium only. Feature-detected rather than assumed: constructing it where\n // it does not exist throws, and a picker that throws on click is worse than\n // one without the button.\n return typeof window !== \"undefined\" && \"EyeDropper\" in window;\n}\n\ninterface EyeDropperLike {\n open: () => Promise<{ sRGBHex: string }>;\n}\n\n/**\n * Whether an event target is a node in ANY document.\n *\n * `instanceof Node` cannot answer this: it is bound to one JavaScript realm, so\n * a target from an iframe or a pop-out fails it while being a perfectly good\n * node. Probing for the property the DOM guarantees is realm-independent, and\n * `Partial<Node>` is the honest shape to probe through — the value is not known\n * to be a node until this returns.\n */\nfunction isNode(value: EventTarget | null): value is Node {\n return (\n value !== null && typeof (value as Partial<Node>).nodeType === \"number\"\n );\n}\n\n/**\n * A colour control: a saturation square, a hue strip, optional alpha, a hex\n * field, and any presets the host supplies.\n *\n * Deliberately knows nothing about design tokens. A swatch carries an opaque\n * `value` this component never reads and hands back untouched, so a host can\n * store a token reference and keep it. That is what lets one component serve\n * both a plain colour field and a token-aware surface without either learning\n * about the other.\n *\n * @experimental\n *\n * @example\n * ```tsx\n * <ColorPicker\n * color={color}\n * onColorChange={setColor}\n * swatches={tokens.map(t => ({ id: t.name, label: t.name, color: t.value, value: { $token: t.name } }))}\n * onSwatchSelect={s => store(s.value)}\n * />\n * ```\n */\nexport function ColorPicker<TValue = string>({\n color,\n onColorChange,\n swatches = [],\n onSwatchSelect,\n recentColors = [],\n showAlpha = false,\n className,\n}: ColorPickerProps<TValue>) {\n const fieldId = React.useId();\n /** The picker's own subtree, for telling a press inside it from a dismissal. */\n const rootRef = React.useRef<HTMLDivElement>(null);\n /**\n * Whether a press that began INSIDE this picker is still in progress, so a\n * blur carrying no destination can be told from focus genuinely leaving.\n */\n const insidePress = React.useRef(false);\n /**\n * Whether a finish was DEFERRED rather than declined: a blur carrying no\n * destination arrived during an inside press, so the press's own action was\n * given the chance to supersede the draft instead.\n */\n const owedFinish = React.useRef(false);\n /** Undoes a touch press that is waiting to see whether it becomes a tap. */\n const pendingTap = React.useRef<(() => void) | null>(null);\n /**\n * The current way to finish a draft, for a deferred tap whose wait may span a\n * render. Refreshed where the listeners are registered, at layout timing, so\n * it is settled before any later native event can read it.\n */\n const latestCommit = React.useRef<() => void>(() => undefined);\n /**\n * The saturation area, whose BOX is what turns a pointer position into a\n * saturation and brightness pair — the mapping needs the rectangle, not the\n * element.\n */\n const surfaceRef = React.useRef<HTMLDivElement>(null);\n const [hsva, setHsva] = React.useState<Hsva>(() => toHsva(color));\n // What the hex field shows while it is being typed into. A half-typed value\n // is not a colour, and reformatting it on every keystroke moves the caret.\n const [draftHex, setDraftHex] = React.useState<string | null>(null);\n /*\n * The same draft, held where a SECOND finish in the same dispatch can see it.\n *\n * `setDraftHex(null)` is queued, not applied, so two paths that both finish —\n * an outside press moving focus, and the blur that press produces — can each\n * read a still-non-null draft and report the colour twice. React renders\n * between them only if something flushes, which is what makes a test\n * dispatching the events separately miss it entirely.\n */\n const draftRef = React.useRef<string | null>(null);\n\n // Re-seeded when the host supplies a colour this picker did not produce.\n // Comparing the RENDERED hex rather than the prop avoids a loop: the same\n // colour has several spellings, and `#FFF` arriving back as `#ffffff` would\n // otherwise reset the surface on every change.\n const rendered = toHexString(hsva, showAlpha);\n /*\n * At LAYOUT timing, matching the listener below. A passive effect leaves the\n * stale draft readable for a moment the native capture listener is already\n * refreshed for, so an outside press arriving in between publishes the old\n * text over the colour the host has just supplied.\n */\n useIsomorphicLayoutEffect(() => {\n const incoming = parseHex(color);\n if (\n incoming &&\n toHex(incoming, showAlpha ? incoming.alpha : 1) !== rendered\n ) {\n // Same hue retention as the other entry points: a host that pushes a grey\n // in must not silently move the surface's hue to red. Read from the\n // updater rather than from `hsva`, so the effect does not re-run on a\n // hue change it is not interested in.\n /*\n * The DRAFT goes with it. A colour arriving from the host — an undo, an\n * edit made elsewhere — replaces what is stored, so text typed against\n * the old value is stale: left in place, the next blur would publish it\n * back over the value that just arrived.\n */\n dropDraft();\n setHsva(prev => hsvaFrom(incoming, incoming.alpha, prev.h));\n }\n }, [color, rendered, showAlpha]);\n\n /*\n * A typed colour is reported when the author FINISHES it, never per\n * keystroke.\n *\n * `parseHex` accepts 3, 4, 6 and 8 digits, so a PREFIX of a valid colour is\n * itself a valid colour: typing `#123456` passes through `#123` and `#1234`\n * on the way. Reporting each of those made the last one stick whenever the\n * author paused or the surface went away — `#12345` left the host holding\n * `#11223344`, a colour nobody typed, silently replacing the stored one.\n *\n * So the field holds a draft and this is the only thing that publishes it:\n * Enter, and leaving the field. Dragging is untouched and still reports\n * continuously, which is what its coalescing exists for — a drag has no\n * finish to wait for, and typing does.\n *\n * DISMISSAL IS NOT A FINISH, deliberately. Escape means cancel, so a draft\n * dying with the surface is the conventional answer rather than a loss; and\n * clicking away moves focus out of the field first, so that path commits\n * through the blur below. Reporting from an unmount instead would arrive\n * after a host that coalesces a gesture on close has already decided what to\n * write, which is a value published into nothing.\n */\n /*\n * Forget the draft without reporting it, for everything that SUPERSEDES one:\n * a preset, a recent colour, a drag, or the host pushing a new colour in. The\n * ref and the state move together, and the ref moves synchronously, because a\n * blur that has already been queued will read it before React renders.\n */\n const dropDraft = (): void => {\n owedFinish.current = false;\n draftRef.current = null;\n setDraftHex(null);\n };\n\n const commitDraft = (): void => {\n owedFinish.current = false;\n const text = draftRef.current;\n // Taken BEFORE anything else, so a second caller in this same dispatch\n // finds nothing to report rather than the value this one is publishing.\n draftRef.current = null;\n // NOTHING TYPED, nothing to report. Reading the field's value instead would\n // publish the colour already on screen every time focus merely passed\n // through — a save for an edit nobody made, and a second one for an edit\n // already reported by Enter.\n if (text === null) return;\n setDraftHex(null);\n const parsed = parseHex(text);\n // An unfinishable draft is DISCARDED rather than reported. The field\n // returns to the colour that is actually stored, so what is shown and what\n // is saved agree — which they did not when a stale intermediate stood in\n // for the text on screen.\n if (!parsed) return;\n setHsva(prev => hsvaFrom(parsed, parsed.alpha, prev.h));\n onColorChange(toHex(parsed, showAlpha ? parsed.alpha : 1));\n };\n\n /*\n * A press OUTSIDE is a finish, and it is the one a blur cannot catch.\n *\n * Measured rather than assumed: a dismissable layer runs from the outside\n * `pointerdown` and unmounts this content there, so the focus change that\n * would have produced a blur never happens and a complete typed colour was\n * lost with no report at all. A test driving `blur` directly cannot see that\n * — the blur is the thing in question — so the case that proves it presses\n * outside for real.\n *\n * CAPTURE, because the ordering is the whole point: a capture listener on the\n * document runs before the dismiss layer's own, so the value is reported\n * while this is still mounted. Reporting from an unmount instead was tried\n * and removed — a host that coalesces a picker gesture on close has already\n * decided what to write by then.\n *\n * RE-REGISTERED every render, with no dependency list, and at LAYOUT timing.\n * A passive effect leaves the previous listener installed until its cleanup\n * runs, so a native press arriving after a render that changed `showAlpha` or\n * `onColorChange` would reach the closure from the render before it — an old\n * alpha, or a consumer that is no longer the current one.\n * The obvious alternative keeps the handler in a ref refreshed by an effect,\n * and that ref is not guaranteed fresh when a NATIVE listener fires: a\n * passive effect runs after the commit, and this listener is outside React's\n * event system, so an outside press arriving in between would call the\n * previous closure and discard the draft it was holding. Swapping one\n * listener per render costs nothing measurable and has no such window.\n *\n * Escape is untouched and still cancels: it dismisses without a pointer, so\n * nothing here runs and the draft dies with the surface, which is what a\n * cancel means.\n */\n useIsomorphicLayoutEffect(() => {\n const root = rootRef.current;\n if (root === null) return;\n latestCommit.current = commitDraft;\n const onPointerDown = (event: Event): void => {\n /*\n * Any new press ENDS whatever the last one was waiting for. A touch that\n * became a scroll produces no click, so its pending completion would\n * otherwise sit installed and be finished by the next unrelated click\n * anywhere — including a press on the hex field to move the caret, which\n * would publish text still being edited.\n */\n pendingTap.current?.();\n pendingTap.current = null;\n /*\n * A press INSIDE is not a dismissal — a swatch, a slider, the field\n * itself — and committing there would report a draft the press is about\n * to replace.\n *\n * Recognised through the COMPOSED PATH first, because a composed event\n * crossing a shadow boundary is retargeted to the host by the time it\n * reaches this document: `root` does not contain that host, so a press on\n * the hex field itself would read as outside and publish a half-typed\n * prefix — clicking to move the caret after `#123` would store `#112233`.\n *\n * The containment test behind it covers the ordinary case and is written\n * WITHOUT `instanceof`, which is realm-bound: in an iframe or a pop-out\n * the target belongs to that document's own JavaScript realm and is not\n * an instance of this one's `Node`. `contains` is a tree operation and\n * does not care which realm a node came from.\n */\n const path =\n typeof event.composedPath === \"function\" ? event.composedPath() : [];\n const inside =\n path.includes(root) ||\n (isNode(event.target) && root.contains(event.target));\n /*\n * RECORDED, because a blur cannot always tell where focus went. Some\n * engines do not focus a button on press, so the field's `focusout`\n * arrives with a null `relatedTarget` and reads as focus leaving the\n * picker entirely — finishing the draft before the swatch or eyedropper\n * click can supersede it, which is the double report this all exists to\n * avoid. Cleared when the press ends.\n */\n insidePress.current = true;\n // A press inside decides NOTHING about the draft. Whether it becomes a\n // replacement is not knowable here — the eyedropper's button is inside\n // and its sampling can be cancelled, leaving nothing to replace with —\n // so each path that actually replaces the value drops the draft as part\n // of doing so, and the blur below declines to report one while focus is\n // moving within this picker.\n if (inside) return;\n /*\n * A TOUCH press is not yet a tap. It may become a scroll or a long press,\n * and a dismissable layer waits for the resulting click before dismissing\n * for exactly that reason — so finishing here would publish a draft while\n * the picker stays open and the field is still being edited. The click\n * that follows a completed tap is what finishes it; a scroll produces\n * none, and the listener is discarded with the effect.\n */\n /*\n * Read off the event rather than narrowed by `instanceof PointerEvent`,\n * which is realm-bound for the same reason the node test above avoids it.\n * A listener registered for `pointerdown` receives a pointer event; the\n * property is absent only where the environment does not implement them,\n * and an absent type is not a touch.\n */\n const pointerType = (event as Partial<PointerEvent>).pointerType;\n if (pointerType === \"touch\") {\n const onClick = (): void => {\n owner.removeEventListener(\"click\", onClick, true);\n pendingTap.current = null;\n // The CURRENT commit, not this render's: a wait that spans a rerender\n // would otherwise report through the closure it was created in — an\n // old alpha, or a consumer no longer current. The ref is refreshed in\n // the same layout effect that registers these listeners, so it is\n // settled before any later native event.\n latestCommit.current();\n };\n owner.addEventListener(\"click\", onClick, true);\n pendingTap.current = () => {\n owner.removeEventListener(\"click\", onClick, true);\n };\n return;\n }\n commitDraft();\n };\n /*\n * The picker's OWN document, not the global one. Rendered into an iframe or\n * a pop-out window this component's presses happen in a different document\n * entirely, and a listener on the parent global would never see them —\n * which is the case where a dismiss layer unmounts the picker and the draft\n * goes with it.\n */\n const owner = root.ownerDocument;\n /*\n * A cancelled gesture ends the wait too, and is the signal the platform\n * gives when a press becomes a scroll rather than a tap.\n */\n const onPointerCancel = (): void => {\n insidePress.current = false;\n pendingTap.current?.();\n pendingTap.current = null;\n };\n // The press ENDING is what releases the blur above, whether or not it\n // became a click.\n const onPointerUp = (): void => {\n insidePress.current = false;\n };\n /*\n * The finish a null-destination blur DEFERRED rather than cancelled.\n *\n * On engines that do not focus a button when it is pressed, the field's\n * blur is skipped so the press's own action can supersede the draft. Where\n * that action replaces nothing — a swatch with no handler, a cancelled\n * sample — the draft would otherwise sit pending with focus already outside\n * the picker, and no further blur is coming to finish it.\n *\n * BUBBLE phase, so the action has already run: a swatch that did replace\n * the value has dropped the draft by now and there is nothing left to\n * report. Only a draft that survived its own press, with focus outside,\n * finishes here.\n */\n const onClickResolve = (): void => {\n // Only a finish that was actually deferred. Reading focus alone would\n // finish on any click that happens to land while focus is elsewhere,\n // including one this picker had no part in.\n if (!owedFinish.current) return;\n latestCommit.current();\n };\n owner.addEventListener(\"pointerdown\", onPointerDown, true);\n owner.addEventListener(\"pointercancel\", onPointerCancel, true);\n owner.addEventListener(\"pointerup\", onPointerUp, true);\n owner.addEventListener(\"click\", onClickResolve, false);\n return () => {\n owner.removeEventListener(\"pointerdown\", onPointerDown, true);\n owner.removeEventListener(\"pointercancel\", onPointerCancel, true);\n owner.removeEventListener(\"pointerup\", onPointerUp, true);\n owner.removeEventListener(\"click\", onClickResolve, false);\n };\n });\n\n /*\n * A pending tap outlives an ordinary RERENDER and dies with the component.\n *\n * The effect above re-runs on every render so its closures stay current, and\n * ending the wait in its cleanup killed a legitimate one: an outside target\n * that sets state from its own `pointerdown` rerenders this picker before the\n * click arrives, so the completion was removed and a finished colour never\n * reached the host. What ends a wait is a new press, a cancelled gesture, or\n * this component going away — never a render.\n */\n useIsomorphicLayoutEffect(\n () => () => {\n pendingTap.current?.();\n pendingTap.current = null;\n },\n []\n );\n\n const commit = (next: Hsva): void => {\n setHsva(next);\n dropDraft();\n onColorChange(toHexString(next, showAlpha));\n };\n\n const trackPointer = (event: React.PointerEvent<HTMLDivElement>): void => {\n const rect = surfaceRef.current?.getBoundingClientRect();\n if (!rect) return;\n const { s, v } = saturationValueAt(\n pointOnSurface(event.clientX, event.clientY, rect)\n );\n commit({ ...hsva, s, v });\n };\n\n // Routed through the surface mapping instead of clamping here, so the keys\n // and the pointer cannot disagree about where the edges are.\n const nudge = (ds: number, dv: number): void => {\n const { s, v } = saturationValueAt(\n surfacePointFor(hsva.s + ds, hsva.v + dv)\n );\n commit({ ...hsva, s, v });\n };\n\n const handleSurfaceKey = (event: React.KeyboardEvent<HTMLDivElement>) => {\n // Shift takes the coarse step, matching what the arrow keys do on the\n // sliders beside it.\n const step = event.shiftKey ? 0.1 : 0.01;\n const moves: Record<string, [number, number]> = {\n ArrowLeft: [-step, 0],\n ArrowRight: [step, 0],\n ArrowUp: [0, step],\n ArrowDown: [0, -step],\n };\n const move = moves[event.key];\n if (!move) return;\n // Arrow keys would otherwise scroll the page under the control.\n event.preventDefault();\n nudge(move[0], move[1]);\n };\n\n // Resolved after mount, never during render. Reading `window` while rendering\n // makes the server omit this button and the first client render add it, which\n // React 19 treats as a hydration failure and repairs by discarding the whole\n // picker subtree.\n const [canPickFromScreen, setCanPickFromScreen] = React.useState(false);\n React.useEffect(() => {\n setCanPickFromScreen(eyeDropperSupported());\n }, []);\n\n const handle = surfacePointFor(hsva.s, hsva.v);\n const hueOnly = toHex(hsvToRgb({ h: hsva.h, s: 1, v: 1 }));\n\n const pickFromScreen = async (): Promise<void> => {\n const ctor = (window as unknown as Record<string, unknown>).EyeDropper as\n | (new () => EyeDropperLike)\n | undefined;\n if (!ctor) return;\n /*\n * This press OWNS whatever finish its own blur deferred. Sampling either\n * replaces the draft or is cancelled, and both answers arrive later than\n * the click — so leaving the deferral to be settled on that click reports\n * the typed colour first and the sampled one after it, two edits for the\n * one the author made.\n *\n * Claimed synchronously, before the first await, because the click that\n * would otherwise settle it is already on its way.\n */\n const owed = owedFinish.current;\n owedFinish.current = false;\n let sampled: string;\n try {\n sampled = (await new ctor().open()).sRGBHex;\n } catch {\n /*\n * Dismissed, so nothing replaces the draft and the finish its own blur\n * deferred is now due: focus has already left the field, and no further\n * blur is coming to carry it.\n */\n if (owed) commitDraft();\n // The user dismissed the picker. Not an error, and nothing to report.\n // Scoped to `open()` alone: with the commit inside this block, a host\n // whose `onColorChange` throws — a failing save, a rejected validation —\n // was reported as a dismissal and swallowed, while the picker had\n // already moved. Every other edit path lets that reach the host, and so\n // does this one now.\n return;\n }\n const parsed = parseHex(sampled);\n // The screen's alpha is not meaningful, so the picker keeps its own.\n if (parsed) commit(hsvaFrom(parsed, hsva.a, hsva.h));\n };\n\n return (\n <div\n ref={rootRef}\n className={cn(\"w-64 space-y-3\", className)}\n /*\n * The finish that focus can express, watched at the PICKER rather than at\n * the field. `onBlur` is delivered from the bubbling `focusout`, so this\n * sees focus leaving any descendant.\n *\n * At the field alone it missed the keyboard route entirely: tab from the\n * field to a preset and then out without activating it, and the field's\n * own blur was declined — focus had moved to something inside — while\n * nothing watched the boundary the focus actually crossed. The pointer\n * listener cannot cover it either, since no pointer was involved.\n *\n * `relatedTarget` names where focus is going, and is null when it leaves\n * the document entirely, which is also a finish.\n */\n onBlur={event => {\n const next = event.relatedTarget;\n const root = rootRef.current;\n if (root !== null && isNode(next) && root.contains(next)) return;\n // A blur with NO destination during a press that began inside is that\n // press, not a departure: some engines do not focus a button when it is\n // pressed, and finishing here would beat the click that supersedes it.\n if (next === null && insidePress.current) {\n owedFinish.current = true;\n return;\n }\n commitDraft();\n }}\n >\n <div\n ref={surfaceRef}\n role=\"application\"\n tabIndex={0}\n // The values are in the name because `role=\"application\"` carries no\n // value semantics of its own, and without them a screen reader\n // announces a region that can be driven but never says where it is.\n aria-label={`Saturation and brightness: ${Math.round(hsva.s * 100)}% saturation, ${Math.round(hsva.v * 100)}% brightness. Arrow keys adjust.`}\n className=\"ring-offset-background focus-visible:ring-ring relative h-40 w-full cursor-crosshair touch-none rounded-md focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none\"\n style={{\n backgroundColor: hueOnly,\n // Value on TOP of saturation. CSS paints the first layer nearest the\n // viewer, so the reverse order lets the opaque white end of the\n // saturation ramp cover the black end of the value ramp: the\n // bottom-left corner displays white while selecting black.\n backgroundImage:\n \"linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, transparent)\",\n }}\n onKeyDown={handleSurfaceKey}\n onPointerDown={event => {\n event.currentTarget.setPointerCapture(event.pointerId);\n trackPointer(event);\n }}\n onPointerMove={event => {\n if (event.buttons === 1) trackPointer(event);\n }}\n >\n <span\n aria-hidden=\"true\"\n // A fixed white ring inside a black one, not theme tokens: this\n // handle sits on an arbitrary colour the user is choosing, not on a\n // themed surface, so it has to stay visible against both ends of the\n // square. `border-background` resolved to black in dark mode and\n // vanished against the square's own black lower edge.\n className=\"pointer-events-none absolute size-3 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow-sm ring-1 ring-black/60\"\n style={{ left: `${handle.x * 100}%`, top: `${handle.y * 100}%` }}\n />\n </div>\n\n <label className=\"sr-only\" htmlFor={`${fieldId}-hue`}>\n Hue\n </label>\n <input\n id={`${fieldId}-hue`}\n type=\"range\"\n min={0}\n max={HUE_MAX}\n step={1}\n value={hueSliderValue(hsva.h, HUE_MAX)}\n onChange={event =>\n commit({ ...hsva, h: hueAt(+event.target.value / (HUE_MAX + 1)) })\n }\n className={SLIDER}\n // design-lint-ok: the hue strip renders the colour wheel itself, so its\n // stops are the control's data rather than theming.\n style={{\n backgroundImage:\n \"linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00)\",\n }}\n />\n\n {showAlpha && (\n <>\n <label className=\"sr-only\" htmlFor={`${fieldId}-alpha`}>\n Opacity\n </label>\n <input\n id={`${fieldId}-alpha`}\n type=\"range\"\n min={0}\n max={100}\n step={1}\n value={Math.round(hsva.a * 100)}\n onChange={event =>\n commit({ ...hsva, a: +event.target.value / 100 })\n }\n className={SLIDER}\n style={{\n // The ramp runs to the colour being edited, over a chequerboard,\n // so the track shows what the slider actually controls. Without\n // any background this rendered as a blank 12px strip whose only\n // label was screen-reader-only.\n backgroundImage: `linear-gradient(to right, transparent, ${toHexString({ ...hsva, a: 1 }, false)}), ${CHECKERBOARD}`,\n backgroundSize: \"100% 100%, 8px 8px\",\n }}\n />\n </>\n )}\n\n <div className=\"flex items-center gap-2\">\n <label className=\"sr-only\" htmlFor={`${fieldId}-hex`}>\n Hex colour\n </label>\n <Input\n id={`${fieldId}-hex`}\n className=\"font-mono\"\n value={draftHex ?? rendered}\n /*\n * A keystroke moves the DRAFT and nothing else — not the surface, not\n * the host. Moving the surface here would also fight the re-seeding\n * effect above, which compares the rendered hex against the host's\n * prop and would pull a half-typed value straight back.\n */\n onChange={event => {\n draftRef.current = event.target.value;\n setDraftHex(event.target.value);\n }}\n onKeyDown={event => {\n if (event.key !== \"Enter\") return;\n /*\n * An Enter that ACCEPTS AN IME CANDIDATE is not a finish. Consuming\n * it blocks the acceptance and reports whatever was in the field\n * before the composition resolved. Both signals are read because\n * older engines report the composition only as `keyCode` 229, and\n * this repository's other IME guards check the pair for that\n * reason.\n */\n if (event.nativeEvent.isComposing || event.keyCode === 229) return;\n // Kept off the surrounding form, which may have a submit of its own:\n // finishing a colour is not submitting whatever contains it.\n event.preventDefault();\n commitDraft();\n }}\n />\n {canPickFromScreen && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n aria-label=\"Pick a colour from the screen\"\n onClick={() => void pickFromScreen()}\n >\n <Pipette className=\"size-4\" />\n </Button>\n )}\n </div>\n\n {swatches.length > 0 && (\n <div>\n <p className=\"text-muted-foreground mb-1 text-xs\">Presets</p>\n <div className=\"flex flex-wrap gap-1\">\n {swatches.map(swatch => (\n <button\n key={swatch.id}\n type=\"button\"\n title={swatch.label}\n aria-label={swatch.label}\n className=\"size-6 rounded border shadow-sm\"\n style={{ backgroundColor: swatch.color }}\n onClick={() => {\n /*\n * The swatch REPLACES what was being typed, so the draft goes\n * with it — but only where the host can actually perform the\n * replacement. `onSwatchSelect` is optional and the type\n * permits swatches without it, and dropping a draft for a\n * callback that does nothing loses the typed colour and puts\n * nothing in its place.\n *\n * The other replacement paths drop it inside `commit`; this\n * one reports through the host and has to say so itself.\n */\n if (onSwatchSelect === undefined) return;\n dropDraft();\n onSwatchSelect(swatch);\n }}\n />\n ))}\n </div>\n </div>\n )}\n\n {recentColors.length > 0 && (\n <div>\n <p className=\"text-muted-foreground mb-1 text-xs\">Recent</p>\n <div className=\"flex flex-wrap gap-1\">\n {recentColors.map(recent => (\n <button\n key={recent}\n type=\"button\"\n title={recent}\n aria-label={recent}\n className=\"size-6 rounded border shadow-sm\"\n style={{ backgroundColor: recent }}\n onClick={() => {\n const parsed = parseHex(recent);\n if (parsed) commit(hsvaFrom(parsed, parsed.alpha, hsva.h));\n }}\n />\n ))}\n </div>\n </div>\n )}\n </div>\n );\n}\n","/**\n * Conversions between the colour models an editing surface needs.\n *\n * ## Why each model is here\n *\n * - **sRGB** is what a screen displays and what `#rrggbb` encodes. Everything ends here.\n * - **HSV** is what a colour picker is: a square of saturation against value, beside a hue\n * strip. No other model puts those three controls in the shape people expect.\n * - **OKLCH** is what this product's own theme is written in — every token in `theme.css` is an\n * `oklch()` value. A picker that cannot read it cannot edit the theme.\n *\n * ## Why the maths is here rather than in a library\n *\n * These are fixed, published transforms: the sRGB transfer function and the OKLab matrices are\n * specified in CSS Color 4 and do not change. The package ships no runtime colour dependency, and\n * this module keeps it that way. `culori` remains a DEV dependency used as a test oracle — the\n * conversions here are cross-checked against it rather than trusted on their own.\n *\n * ## The part that is genuinely hard\n *\n * OKLCH describes more colours than a screen can show. Converting one that falls outside sRGB has\n * no correct answer, only choices, and the naive choice — clamp each channel independently — is\n * the wrong one: it shifts hue, because clipping red without clipping green changes the ratio\n * between them. {@link oklchToRgb} reduces chroma instead, holding lightness and hue, which is the\n * approach CSS Color 4 describes for gamut mapping.\n *\n * @module lib/color/convert\n */\n\n/**\n * An sRGB colour with channels in [0, 1]. Alpha is carried separately.\n *\n * @experimental\n */\nexport interface Rgb {\n r: number;\n g: number;\n b: number;\n}\n\n/**\n * Hue in [0, 360), saturation and value in [0, 1].\n *\n * @experimental\n */\nexport interface Hsv {\n h: number;\n s: number;\n v: number;\n}\n\n/**\n * Perceptual lightness in [0, 1], chroma from 0, hue in [0, 360).\n *\n * @experimental\n */\nexport interface Oklch {\n l: number;\n c: number;\n h: number;\n}\n\nconst clamp01 = (n: number): number => (n < 0 ? 0 : n > 1 ? 1 : n);\n\n/**\n * A chroma no displayable sRGB colour exceeds.\n *\n * The most saturated sRGB primaries sit near 0.37 in OKLCH; this leaves headroom above that and\n * gives the gamut search a fixed bracket, so its error is absolute rather than proportional to\n * whatever the caller asked for.\n */\nconst MAX_SRGB_CHROMA = 0.5;\n\n/**\n * Wrap a hue into [0, 360), so -30 and 330 are the same angle.\n *\n * @experimental\n */\nexport function normalizeHue(hue: number): number {\n if (!Number.isFinite(hue)) return 0;\n const wrapped = hue % 360;\n return wrapped < 0 ? wrapped + 360 : wrapped;\n}\n\n/**\n * HSV to sRGB.\n * Saturation and value are clamped rather than rejected: a picker drags them, and a drag that\n * overshoots by a rounding error should saturate rather than throw.\n *\n * @experimental\n */\nexport function hsvToRgb({ h, s, v }: Hsv): Rgb {\n const hue = normalizeHue(h);\n const sat = clamp01(s);\n const val = clamp01(v);\n\n const sector = hue / 60;\n const chroma = val * sat;\n // The second-largest component, which falls as the hue moves away from a primary.\n const x = chroma * (1 - Math.abs((sector % 2) - 1));\n const base = val - chroma;\n\n let rgb: [number, number, number];\n if (sector < 1) rgb = [chroma, x, 0];\n else if (sector < 2) rgb = [x, chroma, 0];\n else if (sector < 3) rgb = [0, chroma, x];\n else if (sector < 4) rgb = [0, x, chroma];\n else if (sector < 5) rgb = [x, 0, chroma];\n else rgb = [chroma, 0, x];\n\n return { r: rgb[0] + base, g: rgb[1] + base, b: rgb[2] + base };\n}\n\n/**\n * sRGB to HSV.\n * Hue is UNDEFINED for a grey and value is undefined for black, and this returns 0 for both. A\n * picker must not take that 0 as the user's hue: it is the absence of one. Holding hue across a\n * drag to zero saturation is the caller's job, which is why a picker keeps HSV as its state\n * rather than deriving it from the colour each render.\n *\n * @experimental\n */\nexport function rgbToHsv({ r, g, b }: Rgb): Hsv {\n const red = clamp01(r);\n const green = clamp01(g);\n const blue = clamp01(b);\n\n const max = Math.max(red, green, blue);\n const min = Math.min(red, green, blue);\n const chroma = max - min;\n\n let hue = 0;\n if (chroma !== 0) {\n if (max === red) hue = ((green - blue) / chroma) % 6;\n else if (max === green) hue = (blue - red) / chroma + 2;\n else hue = (red - green) / chroma + 4;\n hue *= 60;\n }\n\n return {\n h: normalizeHue(hue),\n s: max === 0 ? 0 : chroma / max,\n v: max,\n };\n}\n\n/** The sRGB transfer function, gamma-encoded to linear light. */\nfunction toLinear(channel: number): number {\n return channel <= 0.04045\n ? channel / 12.92\n : Math.pow((channel + 0.055) / 1.055, 2.4);\n}\n\n/** The inverse transfer function, linear light back to gamma-encoded. */\nfunction toGamma(channel: number): number {\n return channel <= 0.0031308\n ? channel * 12.92\n : 1.055 * Math.pow(channel, 1 / 2.4) - 0.055;\n}\n\n/**\n * Linear sRGB to OKLab.\n *\n * The two matrices and the cube root between them are the definition of OKLab, given in CSS\n * Color 4. They are transcribed rather than derived.\n */\nfunction linearRgbToOklab(\n r: number,\n g: number,\n b: number\n): [number, number, number] {\n const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;\n const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;\n const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;\n\n const l_ = Math.cbrt(l);\n const m_ = Math.cbrt(m);\n const s_ = Math.cbrt(s);\n\n return [\n 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_,\n 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_,\n 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_,\n ];\n}\n\n/** OKLab back to linear sRGB, the inverse of {@link linearRgbToOklab}. */\nfunction oklabToLinearRgb(\n L: number,\n a: number,\n b: number\n): [number, number, number] {\n const l_ = L + 0.3963377774 * a + 0.2158037573 * b;\n const m_ = L - 0.1055613458 * a - 0.0638541728 * b;\n const s_ = L - 0.0894841775 * a - 1.291485548 * b;\n\n const l = l_ * l_ * l_;\n const m = m_ * m_ * m_;\n const s = s_ * s_ * s_;\n\n return [\n 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,\n -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,\n -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s,\n ];\n}\n\n/**\n * sRGB to OKLCH.\n *\n * @experimental\n */\nexport function rgbToOklch({ r, g, b }: Rgb): Oklch {\n const [L, A, B] = linearRgbToOklab(\n toLinear(clamp01(r)),\n toLinear(clamp01(g)),\n toLinear(clamp01(b))\n );\n const chroma = Math.sqrt(A * A + B * B);\n // Below this the hue angle is numerical noise rather than a colour, so it is reported as 0\n // instead of whatever direction the rounding happened to point.\n const hue =\n chroma < 1e-6 ? 0 : normalizeHue((Math.atan2(B, A) * 180) / Math.PI);\n return { l: L, c: chroma, h: hue };\n}\n\n/** Whether every channel of a linear triple lies within the displayable range. */\nfunction inGamut([r, g, b]: [number, number, number]): boolean {\n // No tolerance at all: the point must be GENUINELY inside the gamut.\n //\n // Any fixed tolerance is eventually comparable to the channel values themselves, because those\n // shrink without bound as lightness falls — 1e-6 broke the hue at l=0.01, and 1e-12 still broke\n // it at l=0.0001. A tolerance exists to absorb the cube roots' error for a colour sitting\n // exactly ON the boundary, and the cost of not absorbing it is that such a colour comes back\n // with its chroma reduced by less than one part in a million, which nothing can display. The\n // cost of absorbing it is a channel that must then be clamped, and clamping is precisely what\n // moves the hue this function promises to keep.\n const epsilon = 0;\n return (\n r >= -epsilon &&\n r <= 1 + epsilon &&\n g >= -epsilon &&\n g <= 1 + epsilon &&\n b >= -epsilon &&\n b <= 1 + epsilon\n );\n}\n\n/**\n * OKLCH to sRGB, reducing chroma until the colour fits on screen.\n * OKLCH can name colours a display cannot show. Clamping the channels independently is the\n * obvious response and the wrong one: clipping red without clipping green changes the ratio\n * between them, so the colour that appears is a DIFFERENT HUE from the one asked for. Lightness\n * and hue are what a person chose; chroma is the part they will not miss, so chroma is what is\n * given up.\n * The search is a bisection on chroma, which converges to well under a perceptible step in the\n * fixed number of rounds below — no loop that might not terminate.\n *\n * **The gamut is not always monotonic along this ray, and that is a deliberate trade.** At some\n * lightness and hue pairs the boundary is crossed more than once: at `l = 0.2, h = 264.1` the ray\n * is inside up to c ≈ 0.1192, outside until c ≈ 0.1368, briefly inside again to c ≈ 0.1386. A\n * bisection therefore finds the FIRST boundary rather than the outermost reachable chroma.\n *\n * That is the intended behaviour rather than a limitation. Those islands span roughly a tenth of\n * a degree of hue, so preferring the outermost value would make chroma jump by about 0.021\n * between h = 264.05 and h = 264.10 — a visible step while dragging a hue slider, over a change\n * no one can aim at. Taking the first boundary gives 0.1160, 0.1175, 0.1192, 0.1255, 0.1383\n * across the same sweep: continuous, and one step less saturated at worst. It is also what the\n * CSS Color 4 gamut-mapping algorithm does.\n *\n * @experimental\n */\nexport function oklchToRgb({ l, c, h }: Oklch): Rgb {\n const lightness = clamp01(l);\n const hueRadians = (normalizeHue(h) * Math.PI) / 180;\n\n const at = (chroma: number): [number, number, number] =>\n oklabToLinearRgb(\n lightness,\n chroma * Math.cos(hueRadians),\n chroma * Math.sin(hueRadians)\n );\n\n const requested = Math.max(0, c);\n let fitting = at(requested);\n\n if (!inGamut(fitting)) {\n let low = 0;\n // Bracketed against an ABSOLUTE ceiling rather than the requested chroma. Halving an\n // unbounded input a fixed number of times converges on a fraction OF THAT INPUT, so a\n // sufficiently large chroma leaves the interval far above the gamut and the search returns\n // zero — discarding the hue entirely and answering grey for a colour that has one. No sRGB\n // colour exceeds a chroma of roughly 0.37, so this ceiling cannot exclude a reachable one.\n let high = Math.min(requested, MAX_SRGB_CHROMA);\n // Halvings of a fixed interval, so the remaining error is absolute: 0.5 / 2^20 is far below\n // anything a screen or an eye resolves.\n for (let i = 0; i < 20; i++) {\n const mid = (low + high) / 2;\n if (inGamut(at(mid))) low = mid;\n else high = mid;\n }\n fitting = at(low);\n }\n\n return {\n r: clamp01(toGamma(fitting[0])),\n g: clamp01(toGamma(fitting[1])),\n b: clamp01(toGamma(fitting[2])),\n };\n}\n","/**\n * Hex is the notation people type, so it is the picker's front door.\n *\n * It lives beside the conversions rather than in the component that reads it, for the same reason\n * they do: parsing `#3b82f6` is arithmetic on a string, a server rendering a token swatch needs it\n * as much as an editing surface does, and pulling it into client code would put it behind the\n * `\"use client\"` boundary for no benefit.\n *\n * @module lib/color/hex\n */\n\nimport type { Rgb } from \"./convert\";\n\n/**\n * An sRGB colour with its alpha, which is what a hex string can carry and {@link Rgb} cannot.\n *\n * `alpha` is in [0, 1] like the channels, rather than 0-255, so it composes with the conversions\n * without a second unit in play.\n *\n * @experimental\n */\nexport interface Rgba extends Rgb {\n alpha: number;\n}\n\n/** `#rgb`, `#rgba`, `#rrggbb` or `#rrggbbaa`, with the hash optional and case ignored. */\nconst HEX = /^#?(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;\n\nconst clamp01 = (n: number): number => (n < 0 ? 0 : n > 1 ? 1 : n);\n\n/** A channel byte as a two-digit lowercase pair. */\nfunction pair(channel: number): string {\n // A non-finite channel becomes 0 rather than passing through. `clamp01(NaN)` is NaN, because\n // both of its comparisons are false, and formatting that yields the three characters \"NaN\" —\n // producing `#NaN0000`, which is exactly the string this module documents itself as never\n // returning.\n const value = Number.isFinite(channel) ? clamp01(channel) : 0;\n return Math.round(value * 255)\n .toString(16)\n .padStart(2, \"0\");\n}\n\n/**\n * Read a hex colour, or `null` if the input is not one.\n *\n * Returns `null` rather than throwing or substituting black: this reads what someone is part-way\n * through typing, where \"not a colour yet\" is the ordinary case and neither an exception nor a\n * silent black is a useful answer. A caller decides whether to hold the last good value, show a\n * message, or wait.\n *\n * Both short forms are accepted because both are what people paste. `#abc` expands by REPEATING\n * each digit rather than padding with zero — `#abc` is `#aabbcc`, not `#a0b0c0` — which is what CSS\n * does and the only expansion under which `#fff` is white.\n *\n * @experimental\n */\nexport function parseHex(input: string): Rgba | null {\n const text = input.trim();\n if (!HEX.test(text)) return null;\n\n const digits = text.replace(\"#\", \"\");\n const short = digits.length < 6;\n const size = short ? 1 : 2;\n const channel = (index: number): number => {\n const slice = digits.slice(index * size, index * size + size);\n return parseInt(short ? slice + slice : slice, 16) / 255;\n };\n\n const hasAlpha = digits.length === 4 || digits.length === 8;\n return {\n r: channel(0),\n g: channel(1),\n b: channel(2),\n alpha: hasAlpha ? channel(3) : 1,\n };\n}\n\n/**\n * Write a colour as `#rrggbb`, or `#rrggbbaa` when it is not fully opaque.\n *\n * The alpha pair is omitted at 1 rather than always written, because `#3b82f6ff` is the same colour\n * and the shorter form is what someone expects to see in a field they typed `#3b82f6` into.\n *\n * Channels outside [0, 1] are clamped, so the result is always a valid six- or eight-digit hex\n * string whatever a caller passes. Not for floating-point drift, which rounds to the right byte on\n * its own: it is for a value that is wrong by a lot — a channel still in 0-255, or a computation\n * that overshot — where the alternative is emitting `#17f00-80`, a string nothing downstream can\n * parse and no error explains.\n *\n * @experimental\n */\nexport function toHex(color: Rgb, alpha = 1): string {\n // A non-finite alpha falls back to 1, not to 0 as a channel does. Both are \"nothing was\n // specified\", and for alpha that is this parameter's own default — where treating it as 0 would\n // turn a colour invisible on a stray NaN, silently and with no way to tell from the output.\n const opacity = Number.isFinite(alpha) ? clamp01(alpha) : 1;\n const opaque = `#${pair(color.r)}${pair(color.g)}${pair(color.b)}`;\n return opacity === 1 ? opaque : `${opaque}${pair(opacity)}`;\n}\n","/**\n * The mapping between a pointer on a picker surface and a colour.\n *\n * Kept apart from the component for two reasons. It is arithmetic on numbers,\n * so it belongs on the server-safe side with the rest of `@nextlyhq/ui/color`;\n * and a saturation square is the one part of a picker that cannot be checked by\n * rendering it — jsdom reports every element as zero-sized, so a component test\n * measures nothing and passes. Measured here instead, against known corners.\n *\n * @module lib/color/picker-geometry\n */\n\n/** A position on a surface, each axis in [0, 1] from the top-left. */\nexport interface SurfacePoint {\n x: number;\n y: number;\n}\n\nconst clamp01 = (n: number): number => (n < 0 ? 0 : n > 1 ? 1 : n);\n\n/**\n * A pointer position as a fraction of a surface.\n *\n * Clamped, because a drag that begins inside the surface continues to report\n * while the pointer leaves it — which is the interaction people actually use to\n * reach full saturation, and without clamping it produces values outside the\n * colour space rather than the corner they are aiming at.\n *\n * A zero-sized surface answers the top-left rather than dividing by zero. That\n * happens in a test environment and on the first frame before layout.\n *\n * @experimental\n */\nexport function pointOnSurface(\n clientX: number,\n clientY: number,\n rect: { left: number; top: number; width: number; height: number }\n): SurfacePoint {\n return {\n x: rect.width === 0 ? 0 : clamp01((clientX - rect.left) / rect.width),\n y: rect.height === 0 ? 0 : clamp01((clientY - rect.top) / rect.height),\n };\n}\n\n/**\n * The saturation and value a point on the square stands for.\n *\n * Value runs UPWARD while a surface's y runs downward, so the vertical axis is\n * inverted here. Getting that wrong produces a picker that looks correct and\n * selects the colour vertically mirrored from the one under the cursor.\n *\n * @experimental\n */\nexport function saturationValueAt(point: SurfacePoint): {\n s: number;\n v: number;\n} {\n return { s: clamp01(point.x), v: 1 - clamp01(point.y) };\n}\n\n/**\n * Where the handle sits for a given saturation and value — the inverse of\n * {@link saturationValueAt}.\n *\n * Derived from that function's own inversion rather than written independently,\n * so the two cannot disagree about which way the axis runs.\n *\n * @experimental\n */\nexport function surfacePointFor(s: number, v: number): SurfacePoint {\n return { x: clamp01(s), y: 1 - clamp01(v) };\n}\n\n/**\n * The hue a horizontal position stands for, in [0, 360).\n *\n * The upper bound is exclusive: 360 and 0 are the same hue, and returning 360\n * lets a handle at the far end read back as a position outside the strip.\n *\n * @experimental\n */\nexport function hueAt(fraction: number): number {\n const hue = clamp01(fraction) * 360;\n return hue >= 360 ? 0 : hue;\n}\n\n/** Where the hue handle sits, as a fraction of the strip. @experimental */\nexport function huePosition(hue: number): number {\n const wrapped = ((hue % 360) + 360) % 360;\n return wrapped / 360;\n}\n\n/**\n * The integer step a hue occupies on a strip whose last step is `max`.\n *\n * Rounding is what makes this more than a multiplication. A hue just below 360\n * — `#ff0001` is about 359.76 — rounds UP to a step past the end of the strip,\n * and the obvious repair of wrapping it with a modulo sends it to 0: the far\n * LEFT, the opposite end from where that colour belongs. The handle then sits\n * on the wrong side and any keyboard adjustment starts from there. Held at the\n * last step instead, which is where it visually belongs.\n *\n * @experimental\n */\nexport function hueSliderValue(hue: number, max: number): number {\n const step = Math.round(huePosition(hue) * (max + 1));\n return step > max ? max : step;\n}\n","import * as React from \"react\";\n\n/**\n * A layout effect in the browser, a plain effect where there is no DOM.\n *\n * These components are client code, but a consumer may still PRERENDER them,\n * and React warns that `useLayoutEffect` does nothing on the server. Layout\n * timing is what the browser needs wherever an effect has to be settled before\n * anything else can observe it — a registration that must exist before the\n * first frame, or a native listener that must be the current one before the\n * next event reaches it. Neither effect runs during a server render, so\n * choosing between them by environment loses nothing and silences a warning\n * that reports no real problem.\n *\n * Published rather than kept beside its first caller, because a second one\n * arrived: two spellings of this choice would drift the first time either\n * learned something about a new environment.\n */\nexport const useIsomorphicLayoutEffect =\n typeof document === \"undefined\" ? React.useEffect : React.useLayoutEffect;\n","/**\n * ContextMenu Component\n *\n * A right-click menu built on Radix UI primitives. Same surface, items and keyboard model as\n * `DropdownMenu`; what differs is how it opens — a pointer's secondary button, a long press on\n * touch, or the platform's context-menu key — and that it opens AT the pointer rather than\n * anchored to a trigger element.\n *\n * **Why a separate component rather than a `DropdownMenu` with a different trigger**: the two\n * have different anchoring (a virtual point versus an element), different open semantics, and\n * different ARIA. Radix models them separately for that reason, and collapsing them would mean\n * reimplementing one of the two behaviours by hand.\n *\n * **Design specifications** (shared with `DropdownMenu`, so a right-click menu and a button menu\n * cannot drift apart):\n * - Border-radius: `rounded-lg` for the surface, `rounded-sm` for items\n * - Padding: 4px (p-1); item padding 8px horizontal, 6px vertical\n * - Shadow: `shadow-md`; z-index `z-50`; min-width 8rem\n * - Highlight: `bg-muted`, driven off `data-[highlighted]` so pointer and keyboard agree\n *\n * **Accessibility**:\n * - Opens on the context-menu event, so the keyboard route (Shift+F10, or the menu key) reaches\n * it — but only once the trigger can hold focus. Radix wires the event handlers onto whatever\n * `asChild` is given and does not make it focusable, so a plain `div` trigger is reachable by\n * pointer only. Use an already-focusable element, or give it `tabIndex` and a role, as the\n * example below does\n * - Full keyboard navigation (arrows, Enter, Escape, Home/End, typeahead)\n * - ARIA roles from Radix: `menu`, `menuitem`, `menuitemcheckbox`, `menuitemradio`\n * - Focus returns to the element that opened the menu on close\n *\n * **Portalling**: content renders into the container from `PortalProvider`, like every other\n * overlay in this kit. The scoped stylesheet only reaches inside `.nextly-ui`, and an overlay\n * portalled to `document.body` is outside it, so the provider is what keeps it styled.\n *\n * @example\n * ```tsx\n * <ContextMenu>\n * <ContextMenuTrigger asChild>\n * <div className=\"p-8\" tabIndex={0} role=\"group\" aria-label=\"Canvas\">\n * Right-click anywhere in here\n * </div>\n * </ContextMenuTrigger>\n * <ContextMenuContent>\n * <ContextMenuItem onSelect={duplicate}>Duplicate</ContextMenuItem>\n * <ContextMenuItem onSelect={remove}>Delete</ContextMenuItem>\n * <ContextMenuSeparator />\n * <ContextMenuCheckboxItem checked={locked} onCheckedChange={setLocked}>\n * Locked\n * </ContextMenuCheckboxItem>\n * </ContextMenuContent>\n * </ContextMenu>\n * ```\n *\n * @module\n */\n\n\"use client\";\n\nimport * as ContextMenuPrimitive from \"@radix-ui/react-context-menu\";\nimport { Check, ChevronRight, Circle } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\n\n/**\n * The item highlight, taken from the same reasoning as `DropdownMenu`: Radix sets\n * `data-highlighted` for both pointer hover and keyboard focus, so driving the highlight off\n * that one state keeps the two in sync, and `bg-muted` reads against the popover surface\n * without the full-contrast flip a solid `bg-primary` produces.\n */\nconst menuItemBase =\n \"cursor-pointer transition-colors data-[highlighted]:bg-muted data-[highlighted]:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\";\n\n/**\n * The popover surface, shared by the root menu and every submenu.\n *\n * Shared rather than repeated because the two drifted once already: the submenu was written with\n * `overflow-hidden` and no height bound, so a long one near the edge of the viewport clipped with\n * nothing to scroll. A submenu opens beside its parent item, further down the screen with less\n * room left than the menu that spawned it, so it needs the bound at least as much.\n *\n * The available-height variable is what supplies that bound: Radix measures the space the surface\n * actually has and publishes it, so the menu scrolls instead of overflowing the viewport.\n */\nconst menuSurface =\n \"z-50 max-h-[var(--radix-context-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 origin-[--radix-context-menu-content-transform-origin]\";\n\n/** @experimental */\nconst ContextMenu = ContextMenuPrimitive.Root;\n\n/** @experimental */\nconst ContextMenuTrigger = ContextMenuPrimitive.Trigger;\n\n/** @experimental */\nconst ContextMenuGroup = ContextMenuPrimitive.Group;\n\n/** @experimental */\nconst ContextMenuSub = ContextMenuPrimitive.Sub;\n\n/** @experimental */\nconst ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;\n\n/** @experimental */\nconst ContextMenuSubTrigger = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {\n inset?: boolean;\n }\n>(({ className, inset, children, ...props }, ref) => (\n <ContextMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n \"flex select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-muted [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n menuItemBase,\n inset && \"pl-8\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto\" />\n </ContextMenuPrimitive.SubTrigger>\n));\nContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;\n\n/** @experimental */\nconst ContextMenuSubContent = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => {\n const portalContainer = usePortalContainer();\n\n return (\n <ContextMenuPrimitive.Portal container={portalContainer}>\n <ContextMenuPrimitive.SubContent\n ref={ref}\n className={cn(menuSurface, className)}\n {...props}\n />\n </ContextMenuPrimitive.Portal>\n );\n});\nContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;\n\n/** @experimental */\nconst ContextMenuContent = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>\n>(({ className, ...props }, ref) => {\n const portalContainer = usePortalContainer();\n\n return (\n <ContextMenuPrimitive.Portal container={portalContainer}>\n <ContextMenuPrimitive.Content\n ref={ref}\n className={cn(menuSurface, className)}\n {...props}\n />\n </ContextMenuPrimitive.Portal>\n );\n});\nContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;\n\n/** @experimental */\nconst ContextMenuItem = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <ContextMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n menuItemBase,\n inset && \"pl-8\",\n className\n )}\n {...props}\n />\n));\nContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;\n\n/** @experimental */\nconst ContextMenuCheckboxItem = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <ContextMenuPrimitive.CheckboxItem\n ref={ref}\n className={cn(\n \"relative flex select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none\",\n menuItemBase,\n className\n )}\n checked={checked}\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));\nContextMenuCheckboxItem.displayName =\n ContextMenuPrimitive.CheckboxItem.displayName;\n\n/** @experimental */\nconst ContextMenuRadioItem = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <ContextMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"relative flex select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none\",\n menuItemBase,\n className\n )}\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));\nContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;\n\n/** @experimental */\nconst ContextMenuLabel = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <ContextMenuPrimitive.Label\n ref={ref}\n className={cn(\n \"px-2 py-1.5 text-sm font-semibold text-foreground\",\n inset && \"pl-8\",\n className\n )}\n {...props}\n />\n));\nContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;\n\n/** @experimental */\nconst ContextMenuSeparator = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <ContextMenuPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-border\", className)}\n {...props}\n />\n));\nContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;\n\n/**\n * A keyboard shortcut hint, right-aligned in the item.\n *\n * @experimental\n */\nconst ContextMenuShortcut = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => (\n <span\n className={cn(\n \"ml-auto text-xs tracking-widest text-muted-foreground\",\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 ContextMenuRadioGroup,\n ContextMenuRadioItem,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n};\n","/**\n * Resizable panel group\n *\n * Side-by-side or stacked regions whose sizes the user can drag, built on `react-resizable-panels`.\n * An editor shell is exactly this: a rail, a canvas and an inspector, each of which someone will\n * want wider than we chose for them.\n *\n * **Why a library rather than a drag handler**: the hard parts of a splitter are not the drag.\n * They are the keyboard model (the APG window-splitter pattern — arrows resize, Home and End go\n * to the extremes), collapse-and-restore, minimum sizes that survive a window resize, and nested\n * groups. `react-resizable-panels` implements all of them, and is the library the wider React\n * ecosystem settled on for this control.\n *\n * **Sizes are relative, not pixels.** A layout stored in pixels is wrong on the next monitor; one\n * stored proportionally survives a window resize. Persisting a shell layout is the caller's to\n * store wherever it already keeps preferences — this kit does not reach for browser storage on\n * their behalf.\n *\n * The two size props are not the same shape, which is easy to get wrong in both directions:\n * `defaultLayout` is a map of panel id to a **number** (a flex-grow weight, conventionally read as\n * a percentage by making them sum to 100), while per-panel bounds such as `minSize` take a CSS\n * **string** like `\"15%\"`. Handing `defaultLayout` strings is a type error, and a JavaScript\n * caller who does it stores a layout the library cannot restore.\n *\n * Persist from **`onLayoutChanged`**, not `onLayoutChange`: the first fires once the drag has\n * settled, the second fires continuously while the pointer moves. Writing on every frame of a\n * drag thrashes whatever is behind it, which for a remote preference store means a request per\n * frame.\n *\n * **Design specifications**:\n * - Handle: 1px visible line in `bg-border`, with a larger invisible hit area around it\n * - Grip: optional 3x4 handle in `bg-border`, `rounded-sm`, for discoverability\n * - Focus: `focus-visible` ring in the focus token, because a splitter is keyboard-operable\n *\n * **Accessibility**:\n * - The handle is a `separator` with `aria-valuenow`/`aria-valuemin`/`aria-valuemax`, supplied by\n * the library, so a screen reader announces the split as a percentage\n * - Its accessible NAME is required by the type, because the library supplies everything except\n * that: a focusable separator with a position and no name announces \"74\" and leaves a keyboard\n * user to guess what is at 74. Only the caller knows what the two panels hold\n * - Arrow keys resize, Home/End collapse and expand, Enter toggles a collapsible panel\n * - The hit area is larger than the visible line, so the target is reachable without precision\n * pointing (WCAG 2.5.8 Target Size)\n *\n * @example\n * ```tsx\n * <ResizablePanelGroup\n * orientation=\"horizontal\"\n * defaultLayout={{ layers: 20, canvas: 55, inspector: 25 }}\n * onLayoutChanged={saveLayout}\n * >\n * <ResizablePanel id=\"layers\" minSize=\"15%\" collapsible>\n * <LayersPanel />\n * </ResizablePanel>\n * <ResizableHandle withGrip aria-label=\"Layers and canvas\" />\n * <ResizablePanel id=\"canvas\">\n * <Canvas />\n * </ResizablePanel>\n * <ResizableHandle withGrip aria-label=\"Canvas and inspector\" />\n * <ResizablePanel id=\"inspector\" minSize=\"20%\">\n * <Inspector />\n * </ResizablePanel>\n * </ResizablePanelGroup>\n * ```\n *\n * @module\n */\n\n\"use client\";\n\nimport { GripVertical } from \"lucide-react\";\nimport type * as React from \"react\";\nimport * as ResizablePrimitive from \"react-resizable-panels\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * A splitter's accessible name, which the caller must supply one way or the\n * other.\n *\n * REQUIRED rather than documented, because the handle is focusable: a keyboard\n * user lands on it whether or not anyone remembered, and an unnamed separator\n * announces its position — \"74\" — with nothing saying what is at 74. The\n * caller is the only one who can name it, since only the caller knows what the\n * two panels hold, so the type is the only place the requirement can live.\n *\n * Either attribute satisfies it and neither may be paired with the other: two\n * names on one element is not a stronger label, it is an ambiguity resolved by\n * precedence rules nobody writing the call site is thinking about.\n */\ntype SplitterName =\n | { \"aria-label\": string; \"aria-labelledby\"?: never }\n | { \"aria-labelledby\": string; \"aria-label\"?: never };\n\n/**\n * A group of resizable panels, laid out horizontally or vertically.\n *\n * @experimental\n */\nconst ResizablePanelGroup = ({\n className,\n ...props\n}: React.ComponentProps<typeof ResizablePrimitive.Group>) => (\n <ResizablePrimitive.Group\n className={cn(\"h-full w-full\", className)}\n {...props}\n />\n);\n\n/**\n * One region of a panel group.\n *\n * @experimental\n */\nconst ResizablePanel = ResizablePrimitive.Panel;\n\n/**\n * The draggable divider between two panels.\n *\n * The visible line is 1px; the element around it is wider and transparent, so the pointer target\n * is comfortably larger than the line it appears to grab. `withGrip` adds a visible handle, which\n * is worth it on a divider people are meant to discover rather than one they already expect.\n *\n * @experimental\n */\nconst ResizableHandle = ({\n withGrip,\n className,\n children,\n ...props\n}: Omit<\n React.ComponentProps<typeof ResizablePrimitive.Separator>,\n \"aria-label\" | \"aria-labelledby\"\n> &\n SplitterName & {\n withGrip?: boolean;\n }) => (\n <ResizablePrimitive.Separator\n className={cn(\n // The drawn line is 1px; the element around it is wider and transparent, so the pointer\n // target is comfortably larger than what it appears to grab (WCAG 2.5.8).\n \"relative flex items-center justify-center bg-border\",\n // Keyed off `aria-orientation`, which is what the separator actually carries, and read as\n // the ARIA spec defines it: the attribute describes the SEPARATOR, not the group. A\n // horizontal group puts its panels side by side, so its separator is a vertical line.\n \"aria-[orientation=vertical]:w-px aria-[orientation=horizontal]:h-px\",\n \"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background\",\n // Reachable without precision pointing, without drawing a heavier divider: the hit area\n // grows across the line, so a vertical line widens and a horizontal one deepens.\n \"after:absolute after:inset-0\",\n \"aria-[orientation=vertical]:after:-inset-x-1 aria-[orientation=horizontal]:after:-inset-y-1\",\n className\n )}\n {...props}\n >\n {withGrip ? (\n <div className=\"z-10 flex h-4 w-3 items-center justify-center rounded-sm border border-border bg-border\">\n <GripVertical className=\"h-2.5 w-2.5 text-muted-foreground\" />\n </div>\n ) : null}\n {children}\n </ResizablePrimitive.Separator>\n);\n\nexport { ResizableHandle, ResizablePanel, ResizablePanelGroup };\n","/**\n * TreeView\n *\n * A keyboard-operable, virtualized tree. The layers panel of an editor is this control: a\n * hierarchy that can hold thousands of nodes, that someone navigates with arrow keys as much as\n * with a pointer, and that has to stay responsive while they do.\n *\n * **Why virtualized, and why that decides the markup.** A document of a few thousand blocks\n * renders a few thousand rows, and the cost is not the React work — it is layout and paint on\n * every expand, scroll and selection. Only the visible window is rendered here.\n *\n * That has a consequence the accessibility notes below depend on: with only a window in the DOM,\n * the nested `role=\"group\"` markup the tree pattern usually uses **cannot be built**, because an\n * item's children may not be rendered at all. The APG covers this exact case by allowing a FLAT\n * set of `treeitem`s that describe the hierarchy through `aria-level`, `aria-setsize` and\n * `aria-posinset` instead of through nesting. A screen reader reads depth and position from those\n * attributes, so they are not decoration — without them a virtualized tree announces itself as a\n * flat list of whatever happens to be on screen.\n *\n * **Why a headless virtualizer.** The markup above is the requirement, so anything that owns the\n * DOM is unusable. `@tanstack/react-virtual` computes offsets and renders nothing.\n *\n * **State is controllable, not controlled.** `expandedIds`/`selectedId` may be passed with their\n * `onChange` partners to drive the tree from a store — which an editor will do, since selection is\n * shared with the canvas and the inspector — or omitted entirely, in which case the tree keeps its\n * own. Requiring a store for a tree in a settings dialog would be a poor trade.\n *\n * **Design specifications**:\n * - Row height: fixed 28px (`--tree-row`), so the virtualizer needs no measurement pass\n * - Indent: 12px per level, applied as padding so the whole row stays a hit target\n * - Selection: `bg-muted`, matching the menu highlight rather than a full-contrast flip\n * - Focus: `focus-visible` ring in the focus token\n *\n * **Accessibility**:\n * - `role=\"tree\"` with flat `role=\"treeitem\"` children carrying `aria-level`, `aria-setsize`,\n * `aria-posinset`, and `aria-expanded` on anything with children\n * - Roving tabindex: exactly one row is in the tab order, so Tab enters and leaves the tree once\n * rather than walking every node\n * - Arrow keys move and expand, per the APG tree pattern: Right expands then descends, Left\n * collapses then ascends, Home/End jump to the ends, `*` expands every sibling\n * - Typeahead focuses the next row whose label starts with what was typed\n * - Moving focus scrolls the row into view, which virtualization would otherwise prevent: a row\n * outside the window has no element to focus\n *\n * @example\n * ```tsx\n * <TreeView\n * nodes={layers}\n * aria-label=\"Layers\"\n * selectedId={selected}\n * onSelectedChange={setSelected}\n * className=\"h-full\"\n * />\n * ```\n *\n * @module\n */\n\n\"use client\";\n\nimport { useVirtualizer } from \"@tanstack/react-virtual\";\nimport { ChevronRight } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * One node of the tree. Children are omitted or empty for a leaf.\n *\n * @experimental\n */\nexport interface TreeNode {\n /** Stable identity. What selection and expansion are keyed by. */\n id: string;\n /** What the row shows. A string also feeds typeahead; anything else needs `textValue`. */\n label: React.ReactNode;\n /**\n * The text typeahead matches on, when `label` is not a string.\n *\n * Without it a row rendered as markup cannot be typed to, and a keyboard user loses the fastest\n * way through a long tree.\n */\n textValue?: string;\n /** Children, if any. An empty array still marks the node as a parent. */\n children?: readonly TreeNode[];\n /** Shown before the label, after the twisty. */\n icon?: React.ReactNode;\n /** Skipped by every keyboard move and not selectable. */\n disabled?: boolean;\n}\n\n/** A node flattened into a row, carrying what the ARIA attributes need. */\ninterface TreeRow {\n node: TreeNode;\n /** Depth from the root, zero-based. `aria-level` is this plus one. */\n level: number;\n /** How many siblings share this position, for `aria-setsize`. */\n setSize: number;\n /** Position among those siblings, zero-based. `aria-posinset` is this plus one. */\n posInSet: number;\n /** The parent row's id, for the Left-arrow move. */\n parentId?: string;\n hasChildren: boolean;\n}\n\nconst ROW_HEIGHT = 28;\nconst INDENT_PER_LEVEL = 12;\n\n/** The text a row can be typed to, falling back to a string label. */\nfunction textOf(node: TreeNode): string {\n if (typeof node.textValue === \"string\") return node.textValue;\n return typeof node.label === \"string\" ? node.label : \"\";\n}\n\n/**\n * The visible rows, in the order they are shown.\n *\n * Only expanded branches are walked, so a collapsed subtree of ten thousand nodes costs nothing —\n * which is the other half of why this scales, and the half virtualization does not give you.\n */\nfunction flatten(\n nodes: readonly TreeNode[],\n expanded: ReadonlySet<string>\n): TreeRow[] {\n const rows: TreeRow[] = [];\n // An explicit stack rather than recursion, so depth costs heap instead of call frames. A\n // document that is one long expanded chain would otherwise overflow the JavaScript stack before\n // the virtualizer ever got to window it — this control failing on the one shape virtualization\n // does not already help with.\n const pending: {\n list: readonly TreeNode[];\n index: number;\n level: number;\n parentId?: string;\n }[] = [{ list: nodes, index: 0, level: 0 }];\n\n while (pending.length > 0) {\n const frame = pending[pending.length - 1];\n if (frame === undefined || frame.index >= frame.list.length) {\n pending.pop();\n continue;\n }\n const node = frame.list[frame.index];\n const posInSet = frame.index;\n frame.index += 1;\n if (node === undefined) continue;\n // Any declared children array marks a branch, empty or not. A folder that is empty, or\n // whose contents have not loaded, is still something to expand — and the exported contract\n // says so, so reading length here would quietly contradict it.\n const hasChildren = node.children !== undefined;\n rows.push({\n node,\n level: frame.level,\n setSize: frame.list.length,\n posInSet,\n parentId: frame.parentId,\n hasChildren,\n });\n if (hasChildren && expanded.has(node.id)) {\n pending.push({\n list: node.children ?? [],\n index: 0,\n level: frame.level + 1,\n parentId: node.id,\n });\n }\n }\n return rows;\n}\n\n/**\n * State the caller may own, or may leave to the component.\n *\n * Which of the two it is has to be decided once and kept: a prop that starts defined and later\n * goes undefined releases control, and the internal state behind it is still at its initial\n * value, so expansion or selection jumps back to the default. Mirroring the controlled value into\n * the internal one on every render would fix the jump and cost a render loop for an array prop\n * built inline, which is the normal way to pass one.\n *\n * So switching is unsupported, the way React treats a controlled input that loses its value.\n * Being explicit about that beats a mechanism that works until the render it does not.\n */\nfunction useControllable<T>(\n controlled: T | undefined,\n fallback: T\n): [T, React.Dispatch<React.SetStateAction<T>>] {\n const [uncontrolled, setUncontrolled] = React.useState(fallback);\n return [\n controlled === undefined ? uncontrolled : controlled,\n setUncontrolled,\n ];\n}\n\n/**\n * Which gesture a row's modifiers meant.\n *\n * Named by the same three words the rest of the system uses, so a caller maps\n * them onto its own selection rules without translating. Both Meta and Control\n * mean toggle: a Mac author presses Command and a Windows author presses\n * Control, and neither ever presses the other's.\n *\n * Shift outranks the toggle modifier — a shift+mod click is a slip rather than\n * a fourth gesture, and extending is the one whose result is visible and undone\n * by a plain click.\n *\n * @experimental\n */\nexport type TreeSelectionMode = \"replace\" | \"toggle\" | \"extend\";\n\n/**\n * Read the gesture from the event that carried it.\n *\n * @experimental\n */\nexport function treeSelectionMode(modifiers: {\n shiftKey: boolean;\n metaKey: boolean;\n ctrlKey: boolean;\n}): TreeSelectionMode {\n if (modifiers.shiftKey) return \"extend\";\n if (modifiers.metaKey || modifiers.ctrlKey) return \"toggle\";\n return \"replace\";\n}\n\n/**\n * Whether a row is in the selection at all.\n *\n * A helper rather than an expression inside the render, so the multi-select\n * branch is one call there instead of a condition — a small edit to a large\n * function is what pushes it across a complexity threshold.\n *\n * `selectedIds` when the caller owns a set, the single id otherwise, so a\n * caller that has not adopted the set keeps exactly the behaviour it had.\n *\n * @experimental\n */\nexport function isRowSelected(\n id: string,\n primary: string | null | undefined,\n selectedIds: readonly string[] | undefined\n): boolean {\n return selectedIds === undefined ? primary === id : selectedIds.includes(id);\n}\n\n/** @experimental */\nexport interface TreeViewProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, \"onSelect\"> {\n /** The roots of the tree. */\n nodes: readonly TreeNode[];\n /** Expanded node ids, if the caller owns them. */\n expandedIds?: readonly string[];\n /** Which ids start expanded when the caller does not own expansion. */\n defaultExpandedIds?: readonly string[];\n /** Called with the full next set whenever a branch opens or closes. */\n onExpandedChange?: (ids: string[]) => void;\n /**\n * The selected node id, if the caller owns it.\n *\n * With `selectedIds` also supplied this is the PRIMARY — the row a detail\n * panel answers for. Drawn at a heavier weight so a reader can tell which\n * member of a multi-row selection the rest of the screen describes.\n */\n selectedId?: string | null;\n /**\n * Every selected id, when the caller holds more than one.\n *\n * Additive: omit it and the tree behaves exactly as it did. Supplying it also\n * makes the tree announce itself as `aria-multiselectable`, which is why it\n * is a separate prop rather than inferred — a single-select tree claiming to\n * be multi-selectable is wrong in a way a screen-reader user acts on.\n */\n selectedIds?: readonly string[];\n /** Which id starts selected when the caller does not own selection. */\n defaultSelectedId?: string | null;\n /** Called when a row is chosen, by pointer or by Enter. */\n onSelectedChange?: (id: string, mode: TreeSelectionMode) => void;\n /**\n * Names the tree for a screen reader. One of this or `aria-labelledby` is required: a tree\n * announced only as \"tree\" tells a user nothing about which one they are in.\n */\n \"aria-label\"?: string;\n}\n\n/**\n * A virtualized tree.\n *\n * @experimental\n */\nconst TreeView = React.forwardRef<HTMLDivElement, TreeViewProps>(\n (\n {\n nodes,\n expandedIds,\n defaultExpandedIds,\n onExpandedChange,\n selectedId,\n selectedIds,\n defaultSelectedId,\n onSelectedChange,\n className,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n ...props\n },\n forwardedRef\n ) => {\n const scrollRef = React.useRef<HTMLDivElement | null>(null);\n // The forwarded ref goes to the SCROLL container, not to the element carrying the role. That\n // is the one a caller measures or calls `scrollTo` on; the inner element is a sized spacer\n // and scrolling it does nothing.\n const attachScroll = React.useCallback(\n (node: HTMLDivElement | null) => {\n scrollRef.current = node;\n if (typeof forwardedRef === \"function\") forwardedRef(node);\n else if (forwardedRef !== null && forwardedRef !== undefined) {\n forwardedRef.current = node;\n }\n },\n [forwardedRef]\n );\n const [expandedState, setExpandedState] = useControllable(\n expandedIds === undefined ? undefined : [...expandedIds],\n [...(defaultExpandedIds ?? [])]\n );\n const expanded = React.useMemo(\n () => new Set(expandedIds ?? expandedState),\n [expandedIds, expandedState]\n );\n const [selected, setSelected] = useControllable(\n selectedId === undefined ? undefined : selectedId,\n defaultSelectedId ?? null\n );\n\n const rows = React.useMemo(\n () => flatten(nodes, expanded),\n [nodes, expanded]\n );\n\n // Which row holds the tab stop. Kept as an id rather than an index so that expanding a branch\n // above it does not silently move the tab stop to a different node.\n const [activeId, setActiveId] = React.useState<string | null>(null);\n const activeIndex = Math.max(\n 0,\n rows.findIndex(row => row.node.id === (activeId ?? selected))\n );\n\n const virtualizer = useVirtualizer({\n count: rows.length,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => ROW_HEIGHT,\n overscan: 8,\n });\n\n const commitExpanded = (next: Set<string>): void => {\n const ids = [...next];\n if (expandedIds === undefined) setExpandedState(ids);\n onExpandedChange?.(ids);\n };\n\n const setExpansion = (id: string, open: boolean): void => {\n const next = new Set(expanded);\n if (open) next.add(id);\n else next.delete(id);\n commitExpanded(next);\n };\n\n const choose = (id: string, mode: TreeSelectionMode = \"replace\"): void => {\n // The uncontrolled fallback tracks the PRIMARY only. A caller wanting a\n // set owns it; inventing a default set here would give an uncontrolled\n // tree a selection its caller never sees.\n if (selectedId === undefined) setSelected(id);\n onSelectedChange?.(id, mode);\n };\n\n /**\n * Move the tab stop, and bring the row into view.\n *\n * The scroll is not a nicety: a row outside the rendered window has no element, so focusing it\n * would do nothing at all and the arrow key would appear dead.\n */\n const focusRow = (index: number): void => {\n const row = rows[index];\n if (row === undefined) return;\n setActiveId(row.node.id);\n virtualizer.scrollToIndex(index, { align: \"auto\" });\n // After the scroll the row may have only just been rendered, so the element is looked up on\n // the next frame rather than now.\n requestAnimationFrame(() => {\n const element = scrollRef.current?.querySelector<HTMLElement>(\n `[data-tree-index=\"${index}\"]`\n );\n element?.focus();\n });\n };\n\n /** The next row that is not disabled, in the given direction. */\n const step = (from: number, delta: number): number => {\n for (\n let index = from + delta;\n index >= 0 && index < rows.length;\n index += delta\n ) {\n if (rows[index]?.node.disabled !== true) return index;\n }\n return from;\n };\n\n const typeahead = React.useRef({ query: \"\", at: 0 });\n\n const onKeyDown = (event: React.KeyboardEvent<HTMLDivElement>): void => {\n const index = activeIndex;\n const row = rows[index];\n if (row === undefined) return;\n\n /*\n * Alt belongs to the HOST, so nothing here claims it.\n *\n * The tree pattern uses bare arrows to move, Shift to extend and Ctrl to\n * toggle; Alt appears nowhere in it, which leaves the chord free for\n * whatever embeds the tree. A host that binds one — `alt+ArrowUp` to\n * reorder, say — otherwise loses it exactly where the author is most\n * likely to press it, because the switch below reads `event.key` and\n * `ArrowUp` is `ArrowUp` whatever modifiers are down. The row then takes\n * focus, calls `preventDefault`, and the host's binding never fires.\n *\n * Returning WITHOUT `preventDefault` is the whole point: the event has to\n * go on bubbling for the host to see it.\n */\n if (event.altKey) return;\n\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n focusRow(step(index, 1));\n return;\n case \"ArrowUp\":\n event.preventDefault();\n focusRow(step(index, -1));\n return;\n case \"ArrowRight\":\n event.preventDefault();\n // Expand first, descend second. Pressing Right twice on a closed branch opens it and\n // then enters it, which is what the pattern asks for and what people expect.\n if (row.hasChildren && !expanded.has(row.node.id)) {\n setExpansion(row.node.id, true);\n } else if (row.hasChildren) {\n // Bounded to this row's own children. `step` searches the whole flattened tree, so an\n // expanded branch that is empty — or holds only disabled rows — would send focus to\n // whatever came next in the document instead of staying put.\n for (\n let child = index + 1;\n child < rows.length && (rows[child]?.level ?? 0) > row.level;\n child += 1\n ) {\n if (\n rows[child]?.parentId === row.node.id &&\n rows[child]?.node.disabled !== true\n ) {\n focusRow(child);\n break;\n }\n }\n }\n return;\n case \"ArrowLeft\":\n event.preventDefault();\n if (row.hasChildren && expanded.has(row.node.id)) {\n setExpansion(row.node.id, false);\n } else if (row.parentId !== undefined) {\n // Climb past a disabled ancestor. A disabled branch can still be expanded and hold\n // enabled children, and every other keyboard move refuses to land on one — so\n // stopping here would be the single way to focus a row the rest of the control skips.\n let ancestor: string | undefined = row.parentId;\n while (ancestor !== undefined) {\n const at: number = rows.findIndex(\n candidate => candidate.node.id === ancestor\n );\n if (at < 0) break;\n if (rows[at]?.node.disabled !== true) {\n focusRow(at);\n break;\n }\n ancestor = rows[at]?.parentId;\n }\n }\n return;\n case \"Home\":\n event.preventDefault();\n focusRow(rows[0]?.node.disabled === true ? step(0, 1) : 0);\n return;\n case \"End\": {\n event.preventDefault();\n const last = rows.length - 1;\n focusRow(rows[last]?.node.disabled === true ? step(last, -1) : last);\n return;\n }\n case \"Enter\":\n case \" \":\n event.preventDefault();\n /*\n * The same three gestures the pointer has, so multi-select is not a\n * mouse-only capability. WCAG 2.2 SC 2.1.1 asks that everything\n * reachable by pointer be reachable from a keyboard, and the APG's\n * multi-select tree pattern names Ctrl+Space for toggle and Shift for\n * extend — which is what these modifiers resolve to.\n */\n if (row.node.disabled !== true) {\n choose(row.node.id, treeSelectionMode(event));\n }\n return;\n case \"*\": {\n event.preventDefault();\n // Every sibling at this level, which is the pattern's shortcut for \"show me this whole\n // layer\" without walking it.\n const next = new Set(expanded);\n for (const sibling of rows) {\n if (sibling.parentId === row.parentId && sibling.hasChildren) {\n next.add(sibling.node.id);\n }\n }\n commitExpanded(next);\n return;\n }\n default:\n break;\n }\n\n // Typeahead. A single printable character extends the query rather than replacing it, so\n // typing \"he\" reaches \"header\" instead of stopping at every row beginning with \"e\".\n if (\n event.key.length !== 1 ||\n event.metaKey ||\n event.ctrlKey ||\n event.altKey\n ) {\n return;\n }\n event.preventDefault();\n const now = Date.now();\n const state = typeahead.current;\n state.query = now - state.at > 500 ? event.key : state.query + event.key;\n state.at = now;\n const query = state.query.toLowerCase();\n for (let offset = 1; offset <= rows.length; offset += 1) {\n const candidate = rows[(index + offset) % rows.length];\n if (candidate === undefined || candidate.node.disabled === true)\n continue;\n if (textOf(candidate.node).toLowerCase().startsWith(query)) {\n focusRow(rows.indexOf(candidate));\n return;\n }\n }\n };\n\n // The roving tab stop has to be on a row that EXISTS and that keyboard navigation would\n // accept. Neither is guaranteed by the active index: a selection outside the first window is\n // not rendered at scrollTop 0, so every rendered row would compare false and the tree would\n // have no tab stop at all — unreachable by Tab until something else scrolled it. And a\n // disabled row is skipped by pointer and by every arrow key, so landing on it by Tab\n // contradicts the rest of the control.\n const virtualItems = virtualizer.getVirtualItems();\n const usable = (index: number): boolean =>\n rows[index]?.node.disabled !== true;\n const tabStopIndex =\n virtualItems.some(item => item.index === activeIndex) &&\n usable(activeIndex)\n ? activeIndex\n : (virtualItems.find(item => usable(item.index))?.index ?? -1);\n\n return (\n <div\n ref={attachScroll}\n className={cn(\"overflow-auto\", className)}\n {...props}\n >\n <div\n role=\"tree\"\n // The naming attributes go on the element that carries the role, not on the scroll\n // container around it. Left outside, a caller who names the tree with\n // `aria-labelledby` gets a tree with no accessible name at all — the label sits on a\n // plain div and the role element is announced as an unlabelled tree.\n // Only when the caller actually holds a set — see `selectedIds`.\n aria-multiselectable={selectedIds === undefined ? undefined : true}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={ariaDescribedBy}\n onKeyDown={onKeyDown}\n style={{ height: virtualizer.getTotalSize(), position: \"relative\" }}\n >\n {virtualItems.map(item => {\n const row = rows[item.index];\n if (row === undefined) return null;\n const isSelected = isRowSelected(\n row.node.id,\n selected,\n selectedIds\n );\n // Which member the rest of the screen answers for. With no set\n // supplied every selected row is the primary, so nothing changes.\n const isPrimary = selected === row.node.id;\n return (\n <div\n key={row.node.id}\n data-tree-index={item.index}\n role=\"treeitem\"\n aria-level={row.level + 1}\n aria-setsize={row.setSize}\n aria-posinset={row.posInSet + 1}\n aria-selected={isSelected}\n aria-expanded={\n row.hasChildren ? expanded.has(row.node.id) : undefined\n }\n aria-disabled={row.node.disabled === true ? true : undefined}\n // Roving tabindex: one row in the tab order, so Tab crosses the tree once rather\n // than stopping at every node in it.\n tabIndex={item.index === tabStopIndex ? 0 : -1}\n onFocus={() => setActiveId(row.node.id)}\n onClick={event => {\n if (row.node.disabled === true) return;\n setActiveId(row.node.id);\n choose(row.node.id, treeSelectionMode(event));\n }}\n className={cn(\n \"absolute left-0 flex w-full select-none items-center gap-1 rounded-sm pr-2 text-sm outline-none\",\n \"focus-visible:ring-1 focus-visible:ring-ring\",\n row.node.disabled === true\n ? \"pointer-events-none opacity-50\"\n : \"cursor-pointer\",\n isSelected ? \"bg-muted text-foreground\" : \"hover:bg-muted/50\",\n // WEIGHT, not a second colour. Every row here is selected and\n // an action applies to all of them; what a reader needs is\n // which one the detail panel describes, and a second colour\n // would have to mean a second kind of selected.\n isSelected && isPrimary && \"font-medium\"\n )}\n style={{\n height: item.size,\n transform: `translateY(${item.start}px)`,\n paddingLeft: 4 + row.level * INDENT_PER_LEVEL,\n }}\n >\n <span\n // A separate hit target from the row: opening a branch and selecting it are\n // different intents, and collapsing a folder should not also select it.\n aria-hidden=\"true\"\n className=\"flex size-4 shrink-0 items-center justify-center\"\n onClick={event => {\n if (!row.hasChildren) return;\n event.stopPropagation();\n setExpansion(row.node.id, !expanded.has(row.node.id));\n }}\n >\n {row.hasChildren ? (\n <ChevronRight\n className={cn(\n \"size-3.5 text-muted-foreground transition-transform\",\n expanded.has(row.node.id) && \"rotate-90\"\n )}\n />\n ) : null}\n </span>\n {row.node.icon !== undefined ? (\n <span className=\"flex size-4 shrink-0 items-center justify-center text-muted-foreground\">\n {row.node.icon}\n </span>\n ) : null}\n <span className=\"truncate\">{row.node.label}</span>\n </div>\n );\n })}\n </div>\n </div>\n );\n }\n);\nTreeView.displayName = \"TreeView\";\n\nexport { TreeView };\n","/**\n * Slider\n *\n * A value chosen by dragging along a track, built on `@radix-ui/react-slider`. An inspector is\n * full of bounded numeric properties — opacity, blur radius, letter spacing, a colour's alpha —\n * and each one is a value where the useful question is \"more or less?\" rather than \"what number?\".\n *\n * **Why a library rather than a range input**: `<input type=\"range\">` is keyboard-accessible and\n * nearly unstyleable, and it cannot express two thumbs. The parts that are genuinely hard are the\n * ones a hand-rolled version gets wrong quietly — pointer capture that survives the cursor leaving\n * the element, step rounding that does not accumulate floating-point drift, right-to-left\n * direction, and the ARIA slider pattern for each thumb independently. Radix implements all of\n * them and is already this kit's primitive vendor, so it adds no new dependency shape.\n *\n * **A slider is for magnitude, not precision.** Anything a person needs to type exactly wants a\n * number input beside it; the slider is the coarse control and the input is the fine one. Pairing\n * them is the caller's composition, deliberately: this kit does not decide that every slider earns\n * a spinbox next to it.\n *\n * **Controlled and uncontrolled both work**, following Radix: pass `value` with `onValueChange` to\n * control it, or `defaultValue` to let it own its state. `value` is an ARRAY even for a single\n * thumb — that is what makes a range slider the same component rather than a second one, and it is\n * the most common thing to get wrong on first use.\n *\n * **Commit on `onValueCommit`, not `onValueChange`**, whenever the write is expensive. The first\n * fires once the drag settles; the second fires continuously while the pointer moves. Recompiling\n * a stylesheet or writing to a server on every frame of a drag is the same mistake\n * `ResizablePanelGroup` documents for layout persistence.\n *\n * **Design specifications**:\n * - Track: 1.5 units thick, `bg-secondary`, fully rounded\n * - Range: the filled portion, `bg-primary`\n * - Thumb: 4x4, `border-primary` on `bg-background`, so it reads against both track halves\n * - Focus: `focus-visible` ring on the thumb, which is the focusable element\n * - Disabled: 50% opacity and `pointer-events-none`, matching the kit's other inputs\n *\n * **Accessibility**:\n * - Each thumb is a `slider` with `aria-valuenow`/`aria-valuemin`/`aria-valuemax` from Radix\n * - Arrow keys step, PageUp/PageDown jump, Home/End go to the bounds\n * - A name is REQUIRED and not defaulted: an unlabelled slider announces only a number, and\n * this kit cannot invent a name that would be honest. The name lands on the THUMB, which is\n * what takes focus — `aria-label` on the root is inherited by nothing\n * - A RANGE needs `thumbs`, one entry per thumb: two thumbs sharing the root's name are\n * announced identically, so nothing says which end is held\n * - `aria-valuetext` and `aria-describedby` belong on `thumbs` too — like the name, they are\n * read from the thumb and inherited from nothing\n * - The root is padded so the target clears the 24px minimum (WCAG 2.5.8); the 16px thumb on a\n * 6px track does not on its own\n * - An empty name does not count as a name: `aria-label=\"\"` is reported the same as a missing one,\n * because the accessible name computes to nothing either way\n *\n * **An empty value array renders nothing.** A slider over no values is not a state this control\n * can represent: an empty `defaultValue` falls back to `min`, and an empty `value` — which a\n * controlled caller owns and this component must not overwrite — renders no control at all,\n * rather than a thumb that carries no value and cannot be moved.\n *\n * **Sizing**: a horizontal slider fills its container's width. A VERTICAL one carries a default\n * height instead of filling, because `height: 100%` inside an auto-height parent collapses to a\n * track with no length. Override it with an ordinary `className` — `h-64` for a longer control,\n * `h-full` for the fill-the-parent behaviour.\n *\n * @example\n * ```tsx\n * // Single value, controlled, committing only when the drag settles\n * <Slider\n * aria-label=\"Opacity\"\n * value={[opacity]}\n * min={0}\n * max={100}\n * step={1}\n * onValueChange={([next]) => setPreview(next)}\n * onValueCommit={([next]) => save(next)}\n * // The number alone does not say what it means; this is what gets spoken.\n * thumbs={[{ \"aria-valuetext\": `${opacity} percent` }]}\n * />\n * ```\n *\n * @example\n * ```tsx\n * // Two thumbs: the same component, because `value` was always an array.\n * // A range needs `thumbLabels` — the root's name is not inherited, and two\n * // thumbs sharing one name are announced identically.\n * <Slider\n * defaultValue={[25, 75]}\n * thumbs={[\n * { \"aria-label\": \"Minimum size\" },\n * { \"aria-label\": \"Maximum size\" },\n * ]}\n * />\n * ```\n *\n * @module components/slider\n */\n\"use client\";\n\nimport * as SliderPrimitive from \"@radix-ui/react-slider\";\nimport * as React from \"react\";\n\nimport { devWarnOnce } from \"../lib/dev-warn\";\nimport { cn } from \"../lib/utils\";\n\n/**\n * The assistive-technology attributes a single thumb can carry.\n *\n * @experimental\n */\nexport interface SliderThumbProps {\n /** The thumb's accessible name. */\n \"aria-label\"?: string;\n /** An element naming the thumb, when the name is already on screen. */\n \"aria-labelledby\"?: string;\n /**\n * What the value MEANS, when the number alone does not say it — \"40\n * percent\", \"Medium\". Announced in place of the raw number.\n */\n \"aria-valuetext\"?: string;\n /** An element carrying help text for this thumb. */\n \"aria-describedby\"?: string;\n}\n\n/**\n * The slider's props, mirroring the Radix root.\n *\n * @experimental\n */\nexport type SliderProps = Omit<\n React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>,\n // The wrapper always supplies a track and at least one thumb, and Radix's\n // Slot accepts exactly one composable child — so `asChild` here throws at\n // render. Excluded from the type rather than left to fail at runtime.\n \"asChild\"\n> & {\n /**\n * Assistive-technology attributes per thumb, in value order.\n *\n * The reason this exists at all: the focusable element with the `slider`\n * role is the THUMB, and none of these attributes are inherited from the\n * root. Anything a caller puts on the root is therefore announced by\n * nothing, and the thumbs are generated internally so they cannot be\n * reached any other way.\n *\n * Deliberately a curated set rather than the thumb's full prop type. This\n * is the surface assistive technology reads; opening it to arbitrary props\n * would let a caller replace the class names or the role the control\n * depends on, and every escape hatch in a design system eventually gets\n * used that way.\n *\n * Required for a RANGE: two thumbs sharing one name are announced\n * identically, so nothing says which end is held. A single thumb falls back\n * to the root's `aria-label`/`aria-labelledby`, so the one-thumb API stays\n * as documented.\n */\n thumbs?: readonly SliderThumbProps[];\n};\n\n/**\n * One thumb per value, derived from whichever of `value`/`defaultValue` is present.\n *\n * Radix renders only as many thumbs as it is given children, so a range slider whose caller\n * supplied two values but one thumb would silently drop the second — the value would still be in\n * state, and no thumb would be able to reach it.\n *\n * An EMPTY array floors to one rather than to zero. Zero thumbs is a track with nothing focusable\n * in it: no `slider` role, no keyboard target, and no pointer target either, because Radix routes\n * a track click to the nearest thumb. A control that cannot be operated at all is a worse outcome\n * than one showing a fallback, and the empty array is reported separately.\n */\nfunction thumbCount(\n value: readonly number[] | undefined,\n defaultValue: readonly number[] | undefined\n): number {\n return Math.max(1, value?.length ?? defaultValue?.length ?? 1);\n}\n\n/**\n * Whether a naming attribute actually carries a name.\n *\n * A present-but-empty `aria-label` is the case a presence check misses: the attribute is there, so\n * every `!== undefined` test says the thumb is named, while the accessible name computes to the\n * empty string and assistive technology announces a bare number. It arises from ordinary code —\n * `aria-label={field.label}` before the label loads, or a template over an absent value.\n *\n * The check is deliberately shallow for `aria-labelledby`: whether the referenced element exists\n * and holds text is a property of a document this component cannot see at render, so an id that\n * resolves to nothing still passes here. This catches the empty STRING, which is the case that is\n * both common and knowable.\n */\nfunction hasAccessibleName(value: string | undefined): boolean {\n return value !== undefined && value.trim() !== \"\";\n}\n\n/**\n * A bounded numeric value chosen by dragging.\n *\n * @experimental\n */\nconst Slider = React.forwardRef<\n React.ElementRef<typeof SliderPrimitive.Root>,\n SliderProps\n>(\n (\n {\n className,\n value,\n defaultValue,\n thumbs,\n orientation = \"horizontal\",\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n ...props\n },\n ref\n ) => {\n // Radix captures an uncontrolled value array ONCE, at mount. Recomputing\n // the count from a later `defaultValue` would drop a thumb while Radix\n // still stores its value — an endpoint the user can no longer reach and\n // nothing reports. Controlled sliders keep deriving from `value`, which is\n // the prop Radix itself follows.\n const initialUncontrolledCount = React.useRef(\n thumbCount(undefined, defaultValue)\n ).current;\n // Both sources are already at least one: an empty controlled value returns before this is\n // used, and `thumbCount` floors the uncontrolled side.\n const count = value?.length ?? initialUncontrolledCount;\n\n // An empty array asks for a slider over no values, which is not a state this control can\n // represent. The two cases differ in how far they can be repaired, so they are handled\n // separately rather than with one blanket rule.\n //\n // UNCONTROLLED is fully repairable: an empty `defaultValue` is forwarded as absent, and Radix\n // then applies its own `[min]` default. Substituting the vendor's default is exactly what an\n // omitted prop would have done, so nothing downstream can tell the difference.\n //\n // CONTROLLED is NOT repairable, so the control renders NOTHING. Substituting a value would\n // either flip to uncontrolled — handing Radix ownership of state the caller believes it holds\n // — or show a number the caller's state does not contain, which then never reconciles.\n // Emitting a thumb anyway is worse than either: Radix resolves a track click through\n // `getClosestValueIndex`, which returns -1 for an empty array and so writes nowhere. That\n // thumb carries no `aria-valuenow`, cannot be dragged and cannot be moved by a key — a\n // `slider` role that looks operable and is not, which is the one outcome worse than absence.\n const isEmptyDefault =\n defaultValue !== undefined && defaultValue.length === 0;\n const isEmptyControlled = value !== undefined && value.length === 0;\n devWarnOnce(\n !isEmptyDefault && !isEmptyControlled,\n \"Slider: `value`/`defaultValue` must hold one number per thumb, and an empty array \" +\n \"holds none — the control has nothing to slide. An empty `defaultValue` falls back to \" +\n \"`min`; an empty `value` renders nothing at all, because a controlled slider cannot be \" +\n \"given a value without taking state the caller owns. Render nothing until the value is \" +\n \"loaded rather than passing `[]`.\"\n );\n // Placed after the warning so the defect is always reported, and after every hook so the\n // early return cannot change the order they are called in.\n if (isEmptyControlled) return null;\n // Everything assistive technology reads goes on the THUMB, which is what\n // carries the `slider` role and takes focus. Left on the root it is\n // announced by nothing.\n //\n // The single-thumb fallback keeps the documented one-thumb API working:\n // with one thumb the root's name is unambiguous, so it is forwarded. A\n // range has no such fallback — one name cannot distinguish two ends.\n // The requirement TypeScript cannot express: how many thumbs there are is\n // the length of an array, so nothing at compile time can insist a range\n // names both of its ends. Unmet, it fails silently — the control renders\n // and is unusable with a screen reader.\n // Every thumb needs a name from somewhere: its own entry, or — for a\n // single thumb only — the root's. A one-thumb slider with neither was\n // previously exempt from this check, which is the same silent failure the\n // check exists to report.\n const isNamed = (index: number): boolean => {\n const own = thumbs?.[index];\n if (hasAccessibleName(own?.[\"aria-label\"])) return true;\n if (hasAccessibleName(own?.[\"aria-labelledby\"])) return true;\n return (\n count === 1 &&\n (hasAccessibleName(ariaLabel) || hasAccessibleName(ariaLabelledBy))\n );\n };\n devWarnOnce(\n Array.from({ length: count }).every((_, i) => isNamed(i)),\n \"Slider: every thumb needs an accessible name. A single thumb may take \" +\n \"it from the root's `aria-label`/`aria-labelledby`; a range needs one \" +\n \"`thumbs` entry per thumb, because the root's name is not inherited \" +\n \"and two thumbs sharing one name are announced identically.\"\n );\n\n const ariaFor = (index: number): SliderThumbProps => {\n const supplied = thumbs?.[index] ?? {};\n // An empty naming attribute is dropped rather than forwarded. Emitting `aria-label=\"\"`\n // states a name and supplies none, which reads to a name computation as a deliberate\n // choice; omitting the attribute at least leaves the element honestly unnamed.\n const ownLabel = hasAccessibleName(supplied[\"aria-label\"])\n ? supplied[\"aria-label\"]\n : undefined;\n const ownLabelledBy = hasAccessibleName(supplied[\"aria-labelledby\"])\n ? supplied[\"aria-labelledby\"]\n : undefined;\n if (count !== 1) {\n return {\n ...supplied,\n \"aria-label\": ownLabel,\n \"aria-labelledby\": ownLabelledBy,\n };\n }\n // The two naming attributes are ALTERNATIVES, not independent slots, so\n // the fallback is all-or-nothing. Filling each one separately can emit a\n // thumb `aria-label` alongside a root `aria-labelledby`, and since\n // accessible-name computation prefers `aria-labelledby`, the caller's\n // explicit per-thumb name would lose to the root's without saying so.\n const namesItself = ownLabel !== undefined || ownLabelledBy !== undefined;\n return {\n \"aria-label\": namesItself ? ownLabel : ariaLabel,\n \"aria-labelledby\": namesItself ? ownLabelledBy : ariaLabelledBy,\n \"aria-valuetext\": supplied[\"aria-valuetext\"],\n \"aria-describedby\": supplied[\"aria-describedby\"],\n };\n };\n\n // Orientation is a prop, so the branch belongs in JavaScript rather than in a\n // `data-[orientation=vertical]:` variant. A variant compiles to an attribute selector, which\n // outranks the plain utility a caller passes in `className` — `h-48` would lose to the\n // wrapper's own height and the override would fail silently. Plain classes also let\n // tailwind-merge do the job it is here for: same property, caller wins.\n const isVertical = orientation === \"vertical\";\n\n return (\n // `aria-label`/`aria-labelledby` are destructured out above rather than\n // spread here: left on the root they would be a second, roleless copy\n // of a name only the thumb is read for.\n <SliderPrimitive.Root\n ref={ref}\n className={cn(\n \"relative flex touch-none select-none items-center\",\n // WCAG 2.5.8 wants a 24px target. Padding alone does not reach it: the\n // thumb is absolutely positioned, so the cross-axis size is the 6px\n // track plus the padding — 22px with `py-2`. An explicit minimum\n // states the target rather than leaving it to arithmetic that moves\n // whenever the track thickness does.\n isVertical\n ? // A vertical slider needs a LENGTH, and it cannot inherit one:\n // `h-full` inside an auto-height parent resolves to zero, leaving\n // a control with no track to drag along. A concrete default is\n // usable everywhere and, being a plain utility, is replaced by a\n // caller's own `h-*` — including `h-full`, for the fill-the-parent\n // case this default gives up.\n \"h-44 min-w-6 flex-col px-2\"\n : \"min-h-6 w-full py-2\",\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className\n )}\n orientation={orientation}\n value={value}\n // An empty array is forwarded as absent so Radix applies its own `[min]`\n // default; a populated one is passed through untouched.\n defaultValue={isEmptyDefault ? undefined : defaultValue}\n {...props}\n >\n <SliderPrimitive.Track\n className={cn(\n \"bg-secondary relative grow overflow-hidden rounded-full\",\n isVertical ? \"h-full w-1.5\" : \"h-1.5 w-full\"\n )}\n >\n <SliderPrimitive.Range\n className={cn(\n \"bg-primary absolute\",\n isVertical ? \"w-full\" : \"h-full\"\n )}\n />\n </SliderPrimitive.Track>\n {Array.from({ length: count }, (_, i) => (\n <SliderPrimitive.Thumb\n key={i}\n {...ariaFor(i)}\n className={cn(\n \"border-primary bg-background block h-4 w-4 rounded-full border-2\",\n \"ring-offset-background transition-colors\",\n \"focus-visible:ring-ring focus-visible:outline-none focus-visible:ring-2\",\n \"focus-visible:ring-offset-2\",\n \"disabled:pointer-events-none disabled:opacity-50\"\n )}\n />\n ))}\n </SliderPrimitive.Root>\n );\n }\n);\nSlider.displayName = SliderPrimitive.Root.displayName;\n\nexport { Slider };\n","/**\n * Development-time warnings for requirements the type system cannot express.\n *\n * Some contracts in this kit depend on runtime facts — a range slider needs one\n * accessible name per thumb, and how many thumbs there are is the length of an\n * array. TypeScript cannot see that, a doc comment is not checked by anything,\n * and the failure is silent: the control renders, looks finished, and is\n * unusable with a screen reader.\n *\n * **This follows the layer beneath us rather than inventing a policy.** Radix\n * Primitives warns when a Dialog is missing an accessible title or description;\n * React Aria warns for missing labels; React itself warns for missing keys. A\n * wrapper that stays silent about a defect the primitive underneath it reports\n * is less safe than the thing it wraps, and quietly removes a signal consumers\n * already had.\n *\n * The rules this module exists to enforce:\n *\n * - **Development only, proven rather than assumed.** The gate requires a\n * POSITIVE development signal. Asking instead whether the environment is\n * production fails open: this package publishes ESM that keeps the runtime\n * check, and a browser bundle that neither defines nor shims `process`\n * leaves the comparison false, so every warning would reach real users'\n * consoles. Silence in an unidentifiable environment is the cheaper mistake\n * of the two.\n * - **Once per message.** A control that re-renders through a drag would\n * otherwise emit the same line on every frame, which trains people to ignore\n * the console — the opposite of the point.\n * - **Never throws.** A missing label degrades; it must not take down the page\n * that contains it.\n *\n * @module lib/dev-warn\n */\n\n/**\n * Messages already emitted this session.\n *\n * Keyed by the message itself rather than by component instance: the same\n * defect repeated across twenty instances is one thing for the developer to\n * fix, and twenty identical lines make it harder to see, not easier.\n */\nconst emitted = new Set<string>();\n\n/**\n * The one field this module reads, declared rather than pulled in with\n * `@types/node`.\n *\n * This package targets the browser and deliberately carries no Node types;\n * adding them to reach a single string would widen what every consumer's\n * type-check sees. Bundlers replace `process.env.NODE_ENV` at build time, and\n * `typeof` guards the case where nothing does.\n */\ndeclare const process: { env?: { NODE_ENV?: string } | undefined } | undefined;\n\n/**\n * The environments a warning is allowed to speak in.\n *\n * `test` is here alongside `development` because a suite asserting that a\n * warning fires is checking the same contract a developer relies on; leaving\n * it out would make every such test pass for the wrong reason.\n */\nconst SPEAKING_ENVIRONMENTS = new Set([\"development\", \"test\"]);\n\n/**\n * Whether this runtime has positively identified itself as a development one.\n *\n * Deliberately not `!== \"production\"`. Bundlers replace `process.env.NODE_ENV`\n * at build time, but nothing obliges them to: a build that leaves `process`\n * undefined would answer \"not production\" and ship every warning to end users.\n * An unrecognized environment is treated as one to stay quiet in.\n *\n * Exported so a caller that needs to skip more than a `console.warn` in\n * production — a component gating an entire post-mount DOM check, for\n * example — reuses this SAME predicate rather than re-deriving its own\n * `process.env.NODE_ENV` guard next to it.\n */\nexport function isDevelopmentRuntime(): boolean {\n if (typeof process === \"undefined\") return false;\n const env = process?.env?.NODE_ENV;\n return env !== undefined && SPEAKING_ENVIRONMENTS.has(env);\n}\n\n/**\n * Warn once, in development, about a requirement that is unmet.\n *\n * @param condition - The requirement. Nothing is emitted while this holds.\n * @param message - What is wrong and what to do about it. Written for the\n * developer who will read it in a console with no other context.\n */\nexport function devWarnOnce(condition: boolean, message: string): void {\n if (condition) return;\n if (!isDevelopmentRuntime()) return;\n if (emitted.has(message)) return;\n emitted.add(message);\n console.warn(`[@nextlyhq/ui] ${message}`);\n}\n\n/**\n * Forget which messages have been emitted.\n *\n * For tests, which need each case to observe its own warning rather than\n * inheriting the suppression an earlier one caused.\n */\nexport function resetDevWarnings(): void {\n emitted.clear();\n}\n","/**\n * React bindings for the shortcut manager.\n *\n * Precedence follows the component tree. `ShortcutProvider` owns the single listener and is\n * depth 0; every `ShortcutScope` beneath it adds one. A shortcut registered deeper wins, which is\n * what makes an editor canvas outrank the shell that contains it without either one naming a\n * number the other has to stay clear of.\n *\n * @example\n * ```tsx\n * // The shell, once, at the root.\n * <ShortcutProvider>\n * <App />\n * </ShortcutProvider>\n *\n * // Anywhere inside it.\n * useShortcuts(\n * [{ keys: \"mod+s\", description: \"Save\", run: save, when: () => isDirty }],\n * { name: \"entry-form\" }\n * );\n *\n * // A canvas that must own the keyboard while a drag is in flight. `blocking` is what stops the\n * // shell's Escape from navigating away mid-drag: while the drag runs, nothing below this layer\n * // sees a keystroke at all.\n * //\n * // The bindings live in their own component so the hook is called at a component's top level.\n * // A scope's children are ordinary React children, so a hook cannot be called among them\n * // directly — the rules-of-hooks lint rejects it, and conditional rendering would change hook\n * // order.\n * function DragKeys({ isDragging, cancel }) {\n * useShortcuts([{ keys: \"Escape\", description: \"Cancel drag\", run: cancel }], {\n * name: \"canvas-drag\",\n * enabled: isDragging,\n * blocking: true,\n * });\n * return null;\n * }\n *\n * <ShortcutScope>\n * <DragKeys isDragging={isDragging} cancel={cancel} />\n * <Canvas />\n * </ShortcutScope>\n * ```\n *\n * @module lib/shortcuts/react\n */\n\"use client\";\n\nimport * as React from \"react\";\n\nimport { devWarnOnce } from \"../dev-warn\";\nimport { useIsomorphicLayoutEffect } from \"../isomorphic-layout-effect\";\n\nimport {\n createShortcutManager,\n type ActiveShortcut,\n type ShortcutBinding,\n type ShortcutManager,\n type ShortcutManagerOptions,\n} from \"./manager\";\n\ninterface ShortcutContextValue {\n manager: ShortcutManager;\n depth: number;\n /**\n * The target this provider's listener is installed on, already resolved.\n *\n * Carried so a nested provider can compare identity rather than props: an omitted target and\n * an explicit `document` name the same node, and comparing the props would call two providers\n * different while both attached a listener to it.\n */\n target: Pick<EventTarget, \"addEventListener\" | \"removeEventListener\"> | null;\n /**\n * The options the manager in use was built with, as a comparable string.\n *\n * Carried because the per-target registry cannot answer for a DETACHED provider: it is a\n * WeakMap keyed by the target, and `null` is not a key, so a provider that attaches nothing has\n * no entry to compare against. Two nested detached providers describe the same event stream and\n * share a manager exactly as two attached ones do, and an inner one passing different options\n * loses them the same way — with nothing in the registry to notice.\n */\n options: string;\n}\n\nconst ShortcutContext = React.createContext<ShortcutContextValue | null>(null);\n\n/** A target this kit is already listening on, and how many providers rely on that listener. */\ninterface TargetOwner {\n manager: ShortcutManager;\n providers: number;\n detach?: () => void;\n /** The options the manager was built with, so an adopting provider can tell they differ. */\n options: string;\n /**\n * Whether every provider that used this owner has since unmounted.\n *\n * Distinguishes a shell left behind, whose manager was configured by a provider that has gone,\n * from an entry a sibling RESERVED during the same render and has not mounted yet. Both have no\n * providers, and replacing the second discards the manager that sibling already registered its\n * bindings on.\n */\n retired: boolean;\n}\n\n/**\n * The manager already listening on each target.\n *\n * Keyed by the target rather than carried in context, because \"one listener per target\" is a\n * fact about the DOM and not about the React tree. Two sibling subtrees — or two independent\n * roots on one page — each render a provider with no shortcut ancestor between them, so a\n * context check sees nothing and both would attach. This registry is what makes the guarantee\n * hold across them.\n */\nconst ownersByTarget = new WeakMap<object, TargetOwner>();\n\n/**\n * The options that change how a manager behaves, as a comparable string.\n *\n * `now` is a function and cannot be compared usefully, so its PRESENCE is what is recorded: two\n * providers that both supply a clock may still disagree, and one that supplies none plainly\n * differs from one that does.\n */\nfunction optionsFingerprint(options: ShortcutManagerOptions): string {\n return [\n options.isApple ?? \"auto\",\n options.sequenceTimeoutMs ?? \"default\",\n options.now ? \"clock\" : \"no-clock\",\n ].join(\"\\u0000\");\n}\n\n/**\n * Props for {@link ShortcutProvider}.\n *\n * @experimental\n */\nexport interface ShortcutProviderProps extends ShortcutManagerOptions {\n children?: React.ReactNode;\n /**\n * Where the listener is installed. Defaults to `document`.\n *\n * The bubble phase is deliberate: a component that handles its own keys and calls\n * `stopPropagation` wins without knowing this exists, because React attaches its handlers\n * below `document`.\n */\n target?: Pick<EventTarget, \"addEventListener\" | \"removeEventListener\"> | null;\n}\n\n/**\n * Installs the application's one keydown listener and roots the layer stack.\n *\n * @experimental\n */\nexport function ShortcutProvider({\n children,\n target,\n ...managerOptions\n}: ShortcutProviderProps): React.JSX.Element {\n const parent = React.useContext(ShortcutContext);\n // A second provider on the same target is the very bug this module exists to remove: two\n // listeners on one node, where `stopPropagation` cannot suppress a sibling, so both run their\n // binding for one key. A nested provider therefore does NOT build a manager of its own — it\n // passes the outer one through, so the shortcuts inside it still work and there is still one\n // listener. Nesting with an EXPLICIT target is left alone: a second document, such as an\n // iframe or a pop-out window, genuinely needs its own listener.\n // Resolved before comparing, because `undefined` and an explicit `document` name the same\n // node. Comparing the PROPS would call two providers different while both attach a listener to\n // the same target, which is the arrangement this guard exists to prevent.\n const resolvedTarget =\n target === null\n ? null\n : (target ?? (typeof document === \"undefined\" ? null : document));\n // `null` is compared too: two providers that both attach nothing describe the SAME event\n // stream, the one the host drives through `handle()`. An inner provider building its own\n // manager there means the host never sees the bindings beneath it.\n const nestedOnSameTarget =\n parent !== null && parent.target === resolvedTarget;\n // Options are read once, when the manager is built. Re-creating it on a changed option would\n // drop every layer registered by a child, since registrations live on the manager instance.\n const optionsRef = React.useRef(managerOptions);\n // One manager per target this provider has served, rather than one for the provider.\n //\n // A single memoised manager becomes shared the moment a sibling adopts it, and then following\n // this provider to a new target would register that same manager for two documents — every\n // tree's shortcuts firing on both. Keyed by target, the manager this provider offers to a new\n // owner is one no other owner is using.\n // WEAK keys, so a pop-out or iframe document this provider has finished with can be collected.\n // A strong map would hold every former target, and its whole DOM, until the provider unmounted.\n const ownManagers = React.useRef(new WeakMap<object, ShortcutManager>());\n // The detached case has no target to key on, so it gets its own slot rather than a sentinel\n // object living in the map forever.\n const ownDetached = React.useRef<ShortcutManager | null>(null);\n const detached = React.useMemo(() => {\n if (resolvedTarget === null) {\n ownDetached.current ??= createShortcutManager(optionsRef.current);\n return ownDetached.current;\n }\n const existing = ownManagers.current.get(resolvedTarget);\n if (existing) return existing;\n const created = createShortcutManager(optionsRef.current);\n ownManagers.current.set(resolvedTarget, created);\n return created;\n }, [resolvedTarget]);\n\n // Looked up during render, because two sibling providers both need the same manager before\n // either one's effect has run. The lookup is idempotent and keyed by the target, so a repeated\n // render finds the entry it made rather than making a second one; the reference COUNT is kept\n // in the effect below, where React guarantees a matching cleanup.\n let owner =\n resolvedTarget === null ? null : ownersByTarget.get(resolvedTarget);\n // A RETIRED owner is a shell, kept only so a Strict Mode replay can find it. Its manager was\n // configured by a provider that has since gone, and adopting it would silently give this one\n // someone else's `isApple`, `sequenceTimeoutMs` and clock. An owner merely awaiting its first\n // effect is a different thing: a sibling rendered in the same pass has already taken its\n // manager and registered bindings on it, and replacing it would strand them.\n const fingerprint = optionsFingerprint(optionsRef.current);\n if (resolvedTarget !== null && (!owner || owner.retired)) {\n owner = {\n manager: detached,\n providers: 0,\n retired: false,\n options: fingerprint,\n };\n ownersByTarget.set(resolvedTarget, owner);\n }\n // Adopting a shared manager means adopting the options it was built with. That is what sharing\n // IS, and it is correct for genuine siblings — but a render that is abandoned before it commits\n // leaves a reservation nothing will ever clean up, and the next provider on that target adopts\n // its options silently. The mismatch is reported rather than hidden, because the symptom\n // otherwise is `mod` meaning the wrong key with nothing to point at.\n // Checked against the PARENT as well as the registry. The registry answers for a shared target;\n // the parent answers for the nested case, including the detached one the registry cannot see.\n const adoptedDiffers =\n (Boolean(owner) && owner?.options !== fingerprint) ||\n (nestedOnSameTarget && parent !== null && parent.options !== fingerprint);\n devWarnOnce(\n !adoptedDiffers,\n \"ShortcutProvider: another provider is already listening on this target with different \" +\n \"options, so the ones passed here are being ignored. Managers are shared per target; give \" +\n \"the providers matching options, or a target of their own.\"\n );\n // Nesting with matching options is SUPPORTED, not a mistake, and is deliberately not warned\n // about: a component that owns keys and can be rendered on its own — a command palette exported\n // for embedding — has to bring a provider with it, or it throws wherever no shell wrapped it.\n // Reusing the target's manager makes that composition free, and the warning above still reports\n // the case that genuinely loses something, which is options that disagree.\n const manager =\n nestedOnSameTarget && parent\n ? parent.manager\n : owner\n ? owner.manager\n : detached;\n\n // Layout timing, matching the effects that register the layers. A passive effect installs the\n // listener AFTER paint, so a keydown delivered between the commit and the passive flush reaches\n // no manager at all — the provider is on screen, its layers are registered, and a focused\n // control or a legacy listener still answers the first keystroke.\n useIsomorphicLayoutEffect(() => {\n // `null` is an explicit \"attach nothing\", for tests and for a host that drives `handle`\n // itself.\n if (resolvedTarget === null) return;\n let entry = ownersByTarget.get(resolvedTarget);\n if (!entry) {\n // Strict Mode replays effects as setup, cleanup, setup. Reading the entry made during\n // render would find nothing on the replayed setup, so nothing would reattach and every\n // shortcut would be dead for the rest of the mount — in development only, which is the\n // worst place for it to hide.\n entry = {\n manager,\n providers: 0,\n retired: false,\n options: optionsFingerprint(optionsRef.current),\n };\n ownersByTarget.set(resolvedTarget, entry);\n }\n const owned = entry;\n owned.providers += 1;\n owned.retired = false;\n // The first provider to arrive installs the listener; the rest share it. Ownership is a\n // property of the target rather than of the tree, so this holds for sibling subtrees and\n // independent React roots, which have no common context to consult.\n if (owned.providers === 1) {\n owned.detach = owned.manager.attach(resolvedTarget);\n }\n return () => {\n owned.providers -= 1;\n if (owned.providers === 0) {\n owned.detach?.();\n owned.detach = undefined;\n owned.retired = true;\n // The entry itself is KEPT. It is weakly keyed by the target, so it cannot outlive one,\n // and removing it is what made a Strict Mode replay lose the listener. An unused manager\n // holds no layers, since each layer is disposed by the hook that registered it.\n }\n };\n }, [resolvedTarget, manager]);\n\n // Depth continues from the parent rather than restarting, so a scope inside an ignored nested\n // provider still outranks what surrounds it.\n const depth = nestedOnSameTarget && parent ? parent.depth : 0;\n const value = React.useMemo(\n () => ({ manager, depth, target: resolvedTarget, options: fingerprint }),\n [manager, depth, resolvedTarget, fingerprint]\n );\n return (\n <ShortcutContext.Provider value={value}>\n {children}\n </ShortcutContext.Provider>\n );\n}\n\n/**\n * Raises the precedence of everything inside it by one level.\n *\n * @experimental\n */\nexport function ShortcutScope({\n children,\n}: {\n children?: React.ReactNode;\n}): React.JSX.Element {\n const parent = React.useContext(ShortcutContext);\n if (!parent) {\n throw new Error(\"ShortcutScope must be rendered inside a ShortcutProvider\");\n }\n const value = React.useMemo(\n () => ({\n manager: parent.manager,\n depth: parent.depth + 1,\n target: parent.target,\n // Inherited: a scope raises precedence, it does not build a manager, so the options in force\n // are still the ones the provider above it used.\n options: parent.options,\n }),\n [parent.manager, parent.depth, parent.target, parent.options]\n );\n return (\n <ShortcutContext.Provider value={value}>\n {children}\n </ShortcutContext.Provider>\n );\n}\n\n/**\n * Options for {@link useShortcuts}, minus the depth, which comes from the tree.\n *\n * @experimental\n */\nexport interface UseShortcutsOptions {\n /** Identifies this layer in a help panel. */\n name: string;\n /** Whether the layer participates. A disabled layer neither matches nor blocks. */\n enabled?: boolean;\n /**\n * Whether unmatched keys stop here rather than reaching layers beneath.\n *\n * Set this while a drag or a modal interaction owns the keyboard.\n */\n blocking?: boolean;\n /**\n * Sorted ABOVE depth, so a layer can outrank one nested deeper than itself.\n *\n * For a modal, whose hold must not be tied or beaten by a host scoping its own shortcuts one\n * level further. Ordinary layers leave this alone.\n */\n priority?: number;\n}\n\n/**\n * Register shortcuts for as long as the calling component is mounted.\n *\n * The bindings array may be rebuilt on every render; it is re-read in place rather than\n * re-registered, so inline closures are fine and the layer keeps its position in the stack.\n *\n * @experimental\n */\nexport function useShortcuts(\n bindings: readonly ShortcutBinding[],\n options: UseShortcutsOptions\n): void {\n const context = React.useContext(ShortcutContext);\n if (!context) {\n throw new Error(\"useShortcuts must be called inside a ShortcutProvider\");\n }\n const { manager, depth } = context;\n\n const registration = React.useRef<ReturnType<\n ShortcutManager[\"register\"]\n > | null>(null);\n\n // The newest bindings and options, reachable from an effect that must not re-run when they\n // change. Registration is deliberately NOT keyed on them: rebuilding the layer would move it\n // to the top of its depth, changing precedence for a reason the caller never asked for.\n const latest = React.useRef({ bindings, options });\n\n useIsomorphicLayoutEffect(() => {\n registration.current = manager.register([], {\n name: latest.current.options.name,\n depth,\n });\n return () => {\n registration.current?.dispose();\n registration.current = null;\n };\n }, [manager, depth]);\n\n // No dependency array: the bindings close over render-scoped values, so re-reading them every\n // render is what keeps them from going stale, and it is cheap.\n useIsomorphicLayoutEffect(() => {\n latest.current = { bindings, options };\n registration.current?.update(bindings, {\n name: options.name,\n depth,\n enabled: options.enabled,\n blocking: options.blocking,\n priority: options.priority,\n });\n });\n}\n\n/**\n * The manager itself, for a help panel that lists what is currently bound.\n *\n * @experimental\n */\nexport function useShortcutManager(): ShortcutManager {\n const context = React.useContext(ShortcutContext);\n if (!context) {\n throw new Error(\n \"useShortcutManager must be called inside a ShortcutProvider\"\n );\n }\n return context.manager;\n}\n\n/**\n * The shortcuts currently in effect, most precedent first.\n *\n * SUBSCRIBED rather than read once. A help panel mounting alongside the components that register\n * shortcuts reads before their effects have run, so a one-time read returns an empty list and no\n * later render corrects it — the panel simply shows nothing. The same applies whenever a layer is\n * enabled, disabled or replaced while the panel is open.\n *\n * The manager returns the same array until its stack changes, so this re-renders when the\n * shortcuts change and not on every read.\n *\n * @experimental\n */\nexport function useActiveShortcuts(): readonly ActiveShortcut[] {\n const manager = useShortcutManager();\n return React.useSyncExternalStore(\n manager.subscribe,\n manager.activeBindings,\n manager.activeBindings\n );\n}\n","/**\n * Parsing and matching for keyboard shortcut specifications.\n *\n * A spec is written the way it is spoken: `\"mod+s\"`, `\"Escape\"`, `\"shift+alt+f\"`, and — for a\n * sequence — `\"g d\"`, meaning `g` then `d`. Steps are separated by spaces; within a step,\n * modifiers are joined to the key with `+`.\n *\n * The space bar is written `\"Space\"`, because the character the browser reports for it is `\" \"`\n * and a spec split on whitespace has no way to carry that.\n *\n * **`mod` is the point of this module.** It resolves to Command on Apple platforms and Control\n * everywhere else, so a binding is written once. Writing `ctrl` or `meta` explicitly is still\n * possible and then means exactly that, which is what lets a platform-specific binding coexist\n * with a portable one — a distinction lost by any implementation that treats the two as\n * interchangeable.\n *\n * @module lib/shortcuts/key-spec\n */\n\n/**\n * One keystroke: a key plus the modifier state required with it.\n *\n * @experimental\n */\nexport interface KeyChord {\n /** The `KeyboardEvent.key` value, normalized to lower case for single characters. */\n readonly key: string;\n /** Command on Apple platforms, Control elsewhere. */\n readonly mod: boolean;\n readonly ctrl: boolean;\n readonly meta: boolean;\n readonly alt: boolean;\n readonly shift: boolean;\n}\n\n/**\n * A shortcut: one chord, or several pressed in order.\n *\n * @experimental\n */\nexport type KeySequence = readonly KeyChord[];\n\n/**\n * Named keys are compared exactly; single characters are compared case-insensitively.\n *\n * \"Single character\" is counted in CODE POINTS, matching the text-insertion path. A letter from\n * a supplementary plane occupies two UTF-16 units, so a length check on the string treats it as a\n * named key and skips the lowercasing — leaving its upper and lower case forms unable to match\n * each other, in a grammar that documents case-insensitive letters.\n */\nfunction normalizeKey(key: string): string {\n return [...key].length === 1 ? key.toLowerCase() : key;\n}\n\n/**\n * Whether shift is part of what a caller can meaningfully require for this key.\n *\n * On a US layout `?` is already Shift+/, so the browser reports `key: \"?\"` with `shiftKey: true`.\n * A spec of `\"?\"` must therefore match an event that carries shift, or the most natural way to\n * write the binding would never fire. For letters and named keys the opposite holds: `\"s\"` must\n * NOT match Shift+S, or a binding would swallow a keystroke its author never claimed.\n *\n * The dividing line is whether the character itself already encodes the shift.\n */\nexport function shiftIsMeaningful(key: string): boolean {\n if (key.length > 1) return true;\n // Space is a single character that shift does NOT produce, so Shift+Space is a distinct\n // keystroke and a plain `\"Space\"` binding must not answer for it.\n if (key === \" \") return true;\n // Unicode-aware on purpose: an ASCII-only test calls every non-Latin letter punctuation, so a\n // binding for `ж` would also answer for `Ж` on a Cyrillic layout and could swallow capitals.\n return /[\\p{L}\\p{N}]/u.test(key);\n}\n\n/**\n * Parse a spec into the sequence of chords it describes.\n *\n * @param spec - For example `\"mod+s\"`, `\"Escape\"`, or `\"g d\"`.\n * @throws If the spec is empty, or a step names modifiers but no key.\n *\n * @experimental\n */\nexport function parseKeys(spec: string): KeySequence {\n const steps = spec.trim().split(/\\s+/).filter(Boolean);\n if (steps.length === 0) {\n throw new Error(`Shortcut spec is empty: ${JSON.stringify(spec)}`);\n }\n return steps.map(step => parseChord(step, spec));\n}\n\nfunction parseChord(step: string, spec: string): KeyChord {\n // A `+` is both this grammar's separator and a key people bind. A LONE `+` is the key, and a\n // TRAILING one is too: `mod++` is the usual zoom-in shortcut, and splitting it naively leaves\n // a chord carrying modifiers and no key at all. Spelling it `mod+shift+=` is not a substitute,\n // because the browser reports that keystroke as `key: \"+\"`.\n // The separator has to still be there for the trailing `+` to be a KEY: `mod++` is a modifier,\n // a separator and the plus key, while `mod+` is a modifier and a separator with nothing after\n // it. Accepting the second registered the zoom-in chord for a step that names no key at all,\n // and made the \"no key\" error unreachable for exactly the steps that need it.\n const trailingPlusIsKey = step.length > 2 && step.endsWith(\"++\");\n const body = trailingPlusIsKey ? step.slice(0, -1) : step;\n const parts = step === \"+\" ? [\"+\"] : body.split(\"+\").filter(Boolean);\n let mod = false;\n let ctrl = false;\n let meta = false;\n let alt = false;\n let shift = false;\n let key: string | undefined;\n\n for (const raw of parts) {\n switch (raw.toLowerCase()) {\n case \"mod\":\n mod = true;\n break;\n case \"ctrl\":\n case \"control\":\n ctrl = true;\n break;\n case \"meta\":\n case \"cmd\":\n case \"command\":\n meta = true;\n break;\n case \"alt\":\n case \"option\":\n alt = true;\n break;\n case \"shift\":\n shift = true;\n break;\n case \"space\":\n // The browser reports the space bar as `key: \" \"`, which cannot survive a spec split on\n // whitespace — `\" \"` trims to nothing and a literal `\"Space\"` matches no event. Without\n // this alias the space bar is simply unbindable, which rules out canvas panning and\n // play/pause.\n key = \" \";\n break;\n default:\n if (key !== undefined) {\n throw new Error(\n `Shortcut step \"${step}\" names two keys (\"${key}\" and \"${raw}\") in ${JSON.stringify(spec)}`\n );\n }\n key = raw;\n }\n }\n\n if (trailingPlusIsKey) {\n if (key !== undefined) {\n throw new Error(\n `Shortcut step has more than one key: ${JSON.stringify(step)} in ${JSON.stringify(spec)}`\n );\n }\n key = \"+\";\n }\n\n if (key === undefined) {\n throw new Error(\n `Shortcut step \"${step}\" names modifiers but no key, in ${JSON.stringify(spec)}`\n );\n }\n return { key: normalizeKey(key), mod, ctrl, meta, alt, shift };\n}\n\n/**\n * The modifier state an event carries, with `mod` already resolved for the platform.\n *\n * @experimental\n */\nexport interface ModifierState {\n readonly ctrlKey: boolean;\n readonly metaKey: boolean;\n readonly altKey: boolean;\n readonly shiftKey: boolean;\n /** Optional, so a caller driving the matcher by hand need not synthesise one. */\n readonly getModifierState?: (key: string) => boolean;\n}\n\n/**\n * Whether a chord describes the given keystroke.\n *\n * Modifiers are matched EXACTLY rather than as a minimum: a binding for `s` must not fire on\n * `mod+s`, which is a different shortcut and very often a destructive one.\n *\n * @param chord - The chord to test.\n * @param key - The event's `key`.\n * @param state - The event's modifier flags.\n * @param isApple - Whether `mod` should resolve to Command rather than Control.\n *\n * @experimental\n */\nexport function chordMatches(\n chord: KeyChord,\n key: string,\n state: ModifierState,\n isApple: boolean\n): boolean {\n if (normalizeKey(key) !== chord.key) return false;\n\n // `mod` and an explicit `ctrl`/`meta` are folded into one requirement per physical modifier, so\n // a spec may combine them (`\"mod+ctrl+k\"`) without either one being silently dropped.\n const wantsCtrl = chord.ctrl || (chord.mod && !isApple);\n const wantsMeta = chord.meta || (chord.mod && isApple);\n\n if (state.metaKey !== wantsMeta) return false;\n // AltGraph produces a CHARACTER and reports itself as Ctrl+Alt. A binding written for that\n // character — `@` on a layout that needs AltGraph for it — would never match if those synthetic\n // flags had to be declared, and declaring them (`ctrl+alt+@`) is layout-specific: the same\n // character needs no modifiers at all elsewhere. So they are ignored for a character key.\n //\n // Only when the chord asks for NEITHER, though. A spec that explicitly declares `ctrl+alt+@`\n // wants those modifiers held for real; ignoring them would let a plain AltGraph `@` fire it,\n // and because declared modifiers make a binding typing-enabled by default, that firing can\n // happen inside a field and suppress the character the user was typing.\n const altGraph = state.getModifierState?.(\"AltGraph\") ?? false;\n const synthetic =\n altGraph && [...chord.key].length === 1 && !wantsCtrl && !chord.alt;\n if (!synthetic) {\n if (state.ctrlKey !== wantsCtrl) return false;\n if (state.altKey !== chord.alt) return false;\n }\n if (shiftIsMeaningful(chord.key) && state.shiftKey !== chord.shift)\n return false;\n return true;\n}\n\n/**\n * Whether this platform uses Command as its primary modifier.\n *\n * Reads the modern `userAgentData` hint before the deprecated `navigator.platform`, and answers\n * `false` when neither exists — the non-Apple default is also the correct answer for a server\n * render, where no keystroke can arrive.\n *\n * @experimental\n */\nexport function detectApplePlatform(): boolean {\n if (typeof navigator === \"undefined\") return false;\n const candidate = navigator as Navigator & {\n userAgentData?: { platform?: string };\n };\n const platform =\n candidate.userAgentData?.platform ?? navigator.platform ?? \"\";\n return /mac|iphone|ipad|ipod/i.test(platform);\n}\n","/**\n * The single owner of keyboard shortcuts for an application.\n *\n * ## Why this exists\n *\n * Shortcuts are usually registered by whoever needs them, each component adding its own\n * `document` listener. That works until two of them want the same key, and then it fails in a way\n * that is very hard to see: `stopPropagation()` does NOT stop other listeners on the same node —\n * that requires `stopImmediatePropagation()`, and even then only for listeners registered later.\n * So every global handler runs, in mount order, and mount order is not something a developer\n * chose. Pressing Escape during a drag can cancel the drag AND navigate away from the page,\n * because two independent listeners each believed they owned the key.\n *\n * This module replaces that with one listener and an explicit precedence rule.\n *\n * ## The model: a stack of layers\n *\n * A **layer** is a set of bindings belonging to one interactive context — the application shell,\n * a dialog, an editor canvas mid-drag. Layers are ordered, the topmost is offered each keystroke\n * first, and the first binding that matches consumes it.\n *\n * Precedence is `(depth, sequence)`: the deeper layer wins, and between layers at equal depth the\n * more recently registered wins.\n *\n * Of those two, **depth is declared and sequence is incidental** — and only declared properties\n * survive a refactor. A layer that unmounts and remounts takes a fresh sequence number, so a\n * subtree rebuilt for unrelated reasons can change equal-depth ordering. The guidance that falls\n * out: if relative order matters to you, express it as depth, because depth is the part of the\n * tuple you control. Equal-depth ordering is for stacking things that arrive in genuine\n * mount order, such as one dialog over another. Depth comes from how the application nests, so precedence\n * follows the component tree rather than a set of coordinated numbers — the z-index problem,\n * avoided. Equal-depth ordering is what stacks a second dialog above the first.\n *\n * A layer may be **blocking**, meaning it also swallows the keys it does NOT bind. That is the\n * property a drag or a modal needs: while it is up, nothing beneath it can act. This is the same\n * shape as a window manager's keyboard grab, and as the dismissable-layer stack this kit's\n * dialogs already sit on.\n *\n * ## What it deliberately does not do\n *\n * It listens in the BUBBLE phase, so a focused component that handles its own keys and calls\n * `stopPropagation()` wins without needing to know this module exists. React attaches its\n * handlers at the app root, below `document`, so an `onKeyDown` prop is a sufficient opt-out.\n * Capturing instead would make this module outrank every component in the tree, including the\n * kit's own dialogs, and there would be no way for a component to decline.\n *\n * @module lib/shortcuts/manager\n */\n\nimport { devWarnOnce } from \"../dev-warn\";\n\nimport {\n chordMatches,\n detectApplePlatform,\n parseKeys,\n shiftIsMeaningful,\n type KeyChord,\n type KeySequence,\n} from \"./key-spec\";\n\n/**\n * One shortcut and what it does.\n *\n * @experimental\n */\nexport interface ShortcutBinding {\n /** The keys, as understood by `parseKeys` — `\"mod+s\"`, `\"Escape\"`, `\"g d\"`. */\n keys: string;\n /**\n * What this does, in words, for a shortcuts help panel. Required because an undiscoverable\n * shortcut helps only the person who wrote it.\n */\n description: string;\n /** Runs when the shortcut fires. */\n run: (event: KeyboardEvent) => void;\n /** Checked at press time; a binding whose condition is false is skipped and passes the key on. */\n when?: () => boolean;\n /**\n * Whether this fires while the user is typing in a field.\n *\n * Defaults to true for bindings whose FIRST chord carries a non-shift modifier or is Escape,\n * and false otherwise — the rule nearly every application converges on. `mod+s` must save\n * mid-sentence and Escape must dismiss, while a bare `n` must be able to be the letter n.\n *\n * The first chord decides because it is the keystroke that has to be taken from the field.\n * `mod+k c` is a command from its opening chord, so its bare `c` completes it in an input. A\n * sequence that OPENS on a plain character cannot fire while typing whatever it ends with:\n * allowing `g Escape` would mean swallowing the `g` of every word containing one.\n */\n whenTyping?: boolean;\n /** Whether to call `preventDefault()` when it fires. Defaults to true. */\n preventDefault?: boolean;\n}\n\n/**\n * How a layer behaves for keys it does not bind.\n *\n * @experimental\n */\nexport interface ShortcutLayerOptions {\n /** Identifies the layer in diagnostics and in a help panel. */\n name: string;\n /** Precedence: deeper layers are offered keystrokes first. */\n depth: number;\n /**\n * Whether unmatched keys stop here instead of reaching layers beneath.\n *\n * The reason a drag can be interrupted safely: everything below is inert for as long as this\n * is set, so no other context can act on a keystroke aimed at this one.\n */\n blocking?: boolean;\n /**\n * Sorted ABOVE depth, so a layer can outrank one nested deeper than itself.\n *\n * Depth alone cannot express a modal. A modal wants to sit above every ordinary layer, but the\n * host chooses how deeply its own shortcuts are scoped, so any depth a modal picks can be tied\n * or beaten by a scope the host nests one level further. Priority is the axis the host does not\n * control: ordinary layers leave it at 0 and a modal raises it.\n *\n * KNOWN LIMIT, stated so it is not discovered: layers at EQUAL priority still compare depth\n * before registration order. Two modals therefore stack by how deeply each is scoped rather\n * than by which opened last, so a modal opened later at a shallower depth can sit under one\n * opened earlier and nested deeper — while whatever renders them puts the newer on top.\n *\n * Fixing it needs the manager to record when a layer is ACTIVATED, which registration order\n * does not capture: `useShortcuts` registers once at mount and updates its options in place, so\n * a layer enabled later still carries its mount-time sequence. Not attempted here because\n * nothing reaches it yet — `priority` is new and one layer sets it, so no two layers currently\n * share a nonzero value.\n */\n priority?: number;\n /** Whether the layer participates at all. A disabled layer neither matches nor blocks. */\n enabled?: boolean;\n}\n\n/** A registered layer, which can be updated in place or removed. */\ninterface RegisteredLayer {\n options: ShortcutLayerOptions;\n bindings: readonly PreparedBinding[];\n sequence: number;\n /** What this layer MATCHES, so a re-render that changed nothing can be told apart. */\n shape: string;\n}\n\ninterface PreparedBinding {\n binding: ShortcutBinding;\n keys: KeySequence;\n}\n\n/**\n * A layer's registration, held by whoever created it.\n *\n * @experimental\n */\nexport interface ShortcutRegistration {\n /** Replace this layer's bindings and options without changing its precedence. */\n update: (\n bindings: readonly ShortcutBinding[],\n options: ShortcutLayerOptions\n ) => void;\n /** Remove the layer. */\n dispose: () => void;\n}\n\n/**\n * Options for creating a manager.\n *\n * @experimental\n */\nexport interface ShortcutManagerOptions {\n /** Whether `mod` means Command. Detected from the platform when omitted. */\n isApple?: boolean;\n /** How long a partially typed sequence waits for its next key, in milliseconds. */\n sequenceTimeoutMs?: number;\n /** Clock source, for tests that need to control sequence expiry. */\n now?: () => number;\n}\n\n/**\n * A shortcut manager: the registry, the matcher, and the one listener.\n *\n * @experimental\n */\nexport interface ShortcutManager {\n /** Add a layer. */\n register: (\n bindings: readonly ShortcutBinding[],\n options: ShortcutLayerOptions\n ) => ShortcutRegistration;\n /**\n * Offer a keystroke to the stack. Returns whether it was consumed.\n *\n * Public so the behaviour can be tested without a DOM, and so a host that already owns its\n * event plumbing can drive the manager itself.\n */\n handle: (event: KeyboardEvent) => boolean;\n /** Install the single listener on a target, returning a function that removes it. */\n attach: (\n target: Pick<EventTarget, \"addEventListener\" | \"removeEventListener\">\n ) => () => void;\n /**\n * Every active binding, most-precedent layer first, for a shortcuts help panel.\n *\n * The same array is returned until the layer stack changes, so it is safe to use as an external\n * store snapshot without re-rendering on every read.\n */\n activeBindings: () => readonly ActiveShortcut[];\n /**\n * Watch for changes to the layer stack.\n *\n * A help panel mounting alongside the components that register shortcuts would otherwise read\n * BEFORE their effects run and show nothing, with no later render to correct it.\n */\n subscribe: (onChange: () => void) => () => void;\n}\n\n/**\n * A binding as presented to a help panel, with the layer it came from.\n *\n * @experimental\n */\nexport interface ActiveShortcut {\n keys: string;\n description: string;\n layer: string;\n}\n\nconst DEFAULT_SEQUENCE_TIMEOUT_MS = 1000;\n\n/**\n * Identifies the physical press, for matching a repeat back to the keystroke that began it.\n *\n * `code` rather than `key` and the modifier flags, because those CHANGE while a key is held:\n * press Ctrl+S, then add Shift, and the repeats arrive as `S` with a different modifier set. A\n * signature built from them stops matching mid-hold, the repeat is reported unhandled, and the\n * browser takes it. The physical key does not move, so the physical key is what is remembered.\n */\nfunction signature(event: KeyboardEvent): string {\n return event.code || event.key;\n}\n\n/**\n * The shape this module reads off an event target.\n *\n * Structural rather than `HTMLElement`, because `instanceof` is per-realm: a document inside an\n * iframe or a pop-out window has its OWN `HTMLElement`, and the manager documents a custom\n * `target`, so checking against the outer window's constructor rejects every control in exactly\n * the case the option exists to support. `nodeType === 1` identifies an element in any realm.\n */\ninterface ElementLike {\n tagName: string;\n isContentEditable: boolean;\n getAttribute: (name: string) => string | null;\n}\n\n/**\n * The element the keystroke actually reached.\n *\n * `event.target` is RETARGETED to the shadow host when focus is inside an open shadow root, so\n * reading it alone reports a custom element rather than the input inside it. The composed path\n * starts at the true target and crosses the boundary.\n */\nfunction eventTarget(event: KeyboardEvent): EventTarget | null {\n const path = event.composedPath?.();\n return path && path.length > 0 ? (path[0] ?? null) : event.target;\n}\n\n/** The event target as an element, whichever document it came from. */\nfunction asElement(target: EventTarget | null): ElementLike | null {\n if (target === null || typeof target !== \"object\") return null;\n const node = target as { nodeType?: unknown; tagName?: unknown };\n if (node.nodeType !== 1 || typeof node.tagName !== \"string\") return null;\n return target as unknown as ElementLike;\n}\n\n/** The `type` of an input element, or \"\" for anything else. */\nfunction inputType(element: ElementLike): string {\n if (element.tagName !== \"INPUT\") return \"\";\n const value = (element as { type?: unknown }).type;\n return typeof value === \"string\" ? value.toLowerCase() : \"\";\n}\n\n/**\n * Whether a focused native control owns this key itself.\n *\n * A checkbox is not a typing target, so bare-letter shortcuts should still fire over it — but\n * Space is how it toggles, Enter is how a button activates, and the arrows are how a radio group\n * moves. Offering those to the shortcut stack means a global `Space` binding silently stops a\n * focused checkbox working, which is a worse failure than the shortcut not firing.\n */\nfunction controlOwnsKey(\n target: EventTarget | null,\n event: KeyboardEvent\n): boolean {\n if (event.ctrlKey || event.metaKey || event.altKey) return false;\n const element = asElement(target);\n if (!element) return false;\n const tag = element.tagName;\n const type = inputType(element);\n // `reset` belongs with the other button types: it is not a text field, and Space activates it.\n if (\n tag === \"BUTTON\" ||\n type === \"button\" ||\n type === \"submit\" ||\n type === \"reset\" ||\n type === \"image\"\n ) {\n return event.key === \" \" || event.key === \"Enter\";\n }\n // A link activates on Enter. Space scrolls the page rather than following it, so it is not\n // an activation key here.\n if (tag === \"A\" && element.getAttribute(\"href\") !== null) {\n return event.key === \"Enter\";\n }\n // A summary toggles its details on either key, and the admin renders focusable ones today.\n if (tag === \"SUMMARY\") return event.key === \" \" || event.key === \"Enter\";\n if (type === \"checkbox\") return event.key === \" \";\n // A colour input opens its native picker on either key, and this product puts focusable ones\n // on screen in the page builder's colour and gradient controls.\n if (type === \"color\") return event.key === \" \" || event.key === \"Enter\";\n // A file input opens its chooser the same way, and the public `Input` accepts every native\n // type, so this is reachable without anyone writing a raw input element.\n if (type === \"file\") return event.key === \" \" || event.key === \"Enter\";\n // A range input is a slider: the arrows, Home/End and PageUp/PageDown are how its value moves.\n if (type === \"range\") {\n return event.key.startsWith(\"Arrow\") || RANGE_KEYS.has(event.key);\n }\n if (type === \"radio\") {\n return event.key === \" \" || event.key.startsWith(\"Arrow\");\n }\n return false;\n}\n\n/** Whether a keystroke is going into something the user is typing into. */\nfunction isTypingTarget(target: EventTarget | null): boolean {\n const element = asElement(target);\n if (!element) return false;\n if (element.isContentEditable) return true;\n const tag = element.tagName;\n if (tag === \"TEXTAREA\") return true;\n // A native select does type-ahead on bare letters, so a single-key shortcut firing over it\n // would both act and suppress the control's own behaviour.\n if (tag === \"SELECT\") return true;\n if (tag === \"INPUT\") {\n // Only the text-bearing input types capture letters. A checkbox or a button is an input\n // element that a bare-letter shortcut should still fire over.\n return !NON_TEXT_INPUT_TYPES.has(inputType(element));\n }\n // A custom widget that reports itself as taking text does, even when it is a div. `combobox`\n // and `listbox` are here for type-ahead rather than text entry: Radix's Select renders a\n // button with `role=\"combobox\"` and jumps between options on bare letters without stopping\n // propagation, so a single-key shortcut would fire on top of the value it just changed. This\n // kit's own `Select` wraps that trigger, so the case is reachable from our own components.\n const role = element.getAttribute(\"role\");\n return role !== null && TYPE_AHEAD_ROLES.has(role);\n}\n\nconst NON_TEXT_INPUT_TYPES = new Set([\n \"button\",\n \"checkbox\",\n \"color\",\n \"file\",\n \"hidden\",\n \"image\",\n \"radio\",\n \"range\",\n \"reset\",\n \"submit\",\n]);\n\n/** The default answer to \"does this fire while typing?\", explained on `ShortcutBinding`. */\nfunction firesWhileTyping(prepared: PreparedBinding): boolean {\n const explicit = prepared.binding.whenTyping;\n if (explicit !== undefined) return explicit;\n // The FIRST chord decides, because that is the keystroke separating \"issuing a command\"\n // from \"typing\". Reading the last one rejects `mod+k c` in an editor: the sequence is\n // unmistakably a command, but its final chord is a bare letter.\n const first = prepared.keys[0];\n if (first === undefined) return false;\n return (\n first.mod || first.ctrl || first.meta || first.alt || first.key === \"Escape\"\n );\n}\n\n/**\n * Create a shortcut manager.\n *\n * @experimental\n */\nexport function createShortcutManager(\n options: ShortcutManagerOptions = {}\n): ShortcutManager {\n const isApple = options.isApple ?? detectApplePlatform();\n const sequenceTimeoutMs =\n options.sequenceTimeoutMs ?? DEFAULT_SEQUENCE_TIMEOUT_MS;\n const now = options.now ?? (() => Date.now());\n\n const layers = new Set<RegisteredLayer>();\n let nextSequence = 0;\n\n // The partially typed sequence, shared across layers. It is global rather than per-layer\n // because the keystrokes are: once `g` has been pressed, the next key belongs to whichever\n // layer completes it, and a per-layer prefix would let two layers each hold half a sequence.\n let pendingAt: number | null = null;\n\n /**\n * The layer that claimed the sequence in progress.\n *\n * A prefix is not a property of the keyboard, it is a promise made by ONE layer. Without this,\n * disabling the claimer between keystrokes lets a lower layer's `g d` fire on a `d` whose `g`\n * it never saw, and a layer mounted mid-sequence inherits a prefix typed before it existed.\n */\n let pendingLayer: RegisteredLayer | null = null;\n\n /**\n * What each held key was consumed as, keyed by the physical key, so its repeats stay consumed.\n *\n * Keyed by the physical press rather than by the binding that answered it: by the time a repeat\n * arrives, the binding may have made itself ineligible.\n *\n * A map rather than one slot, because several keys are held at once routinely. A single slot\n * was overwritten by the next press: hold `mod+s`, press `mod+k` while `s` is still down, and\n * the repeats of `s` matched nothing, so a binding that had made itself ineligible let the\n * browser take them. The map is bounded by the number of distinct physical keys on the keyboard.\n */\n const consumedPresses = new Map<string, { prevented: boolean }>();\n\n /**\n * The physical key that opened the pending sequence, so its own repeats can be told apart from\n * every other key's.\n *\n * Holding the key that started a prefix must not cancel that prefix, but a repeat arriving from\n * any OTHER key is a real keystroke in between and does cancel it.\n */\n let pendingKey: string | null = null;\n\n /**\n * What a layer matches, ignoring the parts that change on every render.\n *\n * `useShortcuts` calls `update()` after each render, so a callback identity or an inline object\n * differs constantly while the shortcuts themselves are identical. Cancelling a sequence on\n * every update would make `g d` fail whenever a timer or a context change happened to land\n * between the two keystrokes.\n */\n function layerShape(\n bindings: readonly PreparedBinding[],\n options: ShortcutLayerOptions\n ): string {\n const keys = bindings.map(b => b.binding.keys).join(\"\\u0000\");\n return `${keys}\\u0001${options.depth}\\u0001${options.priority ?? 0}\\u0001${options.blocking === true}\\u0001${options.enabled !== false}`;\n }\n\n /** Whether any enabled layer is currently holding the keyboard. */\n function blocking(): boolean {\n return ordered().some(layer => layer.options.blocking === true);\n }\n\n /**\n * Forget a partially typed sequence.\n *\n * Every path that hands a keystroke to someone else calls this. A pending sequence models \"the\n * user is part-way through a command\", and any real keystroke in between falsifies it — a\n * dismissal, a control taking its own key, a composition, a callback that threw. One function\n * rather than a reset open-coded at each exit, so standing down and forgetting the prefix\n * cannot come apart: an exit that stands down without resetting leaves a later `d` completing\n * a `g` typed before the keystroke that interrupted it.\n */\n function abandonSequence(): void {\n pendingAt = null;\n pressedEvents.length = 0;\n pendingLayer = null;\n pendingKey = null;\n }\n\n function prepare(bindings: readonly ShortcutBinding[]): PreparedBinding[] {\n return bindings.map(binding => ({\n binding,\n keys: parseKeys(binding.keys),\n }));\n }\n\n /** Most precedent first: deeper wins, then more recently registered. */\n function ordered(): RegisteredLayer[] {\n return [...layers]\n .filter(layer => layer.options.enabled !== false)\n .sort(\n (a, b) =>\n (b.options.priority ?? 0) - (a.options.priority ?? 0) ||\n b.options.depth - a.options.depth ||\n b.sequence - a.sequence\n );\n }\n\n /**\n * Whether a binding's sequence matches the keys pressed so far.\n *\n * Returns `\"exact\"` when the sequence is complete, `\"prefix\"` when more keys would complete it,\n * and `\"none\"` otherwise. Distinguishing the middle case is what lets a sequence in progress\n * hold the keyboard without firing anything.\n */\n function matchDepth(\n prepared: PreparedBinding,\n pressed: readonly KeyboardEvent[]\n ): \"exact\" | \"prefix\" | \"none\" {\n if (pressed.length > prepared.keys.length) return \"none\";\n for (let i = 0; i < pressed.length; i++) {\n const chord = prepared.keys[i];\n const event = pressed[i];\n if (chord === undefined || event === undefined) return \"none\";\n if (!chordMatches(chord, event.key, event, isApple)) return \"none\";\n }\n return pressed.length === prepared.keys.length ? \"exact\" : \"prefix\";\n }\n\n function fire(\n prepared: PreparedBinding,\n event: KeyboardEvent,\n invoke: boolean\n ): void {\n if (prepared.binding.preventDefault !== false) event.preventDefault();\n if (invoke) prepared.binding.run(event);\n }\n\n /**\n * Whether letting this keystroke through would put a character into a field.\n *\n * The single case a blocking layer must not suppress. Everything else it swallows has to be,\n * or the grab is only half of one: the application stops acting while the BROWSER still does.\n */\n function insertsText(event: KeyboardEvent, typing: boolean): boolean {\n // Tab first, and regardless of what has focus. A modal's focus trap only cancels the WRAP at\n // its first and last tabbable element and relies on the browser default in between, so every\n // control inside it needs Tab to pass — a button and a checkbox just as much as a field.\n //\n // Only the focus-navigation spellings, though. Shift+Tab is the backwards move and belongs\n // here; Ctrl+Tab and its Shift variant change BROWSER TAB, which is a way out of the grab\n // rather than a move inside it. Exempting those reported the keystroke consumed while leaving\n // its default in place, so the layer both silenced other listeners and let the user leave.\n // A layer that genuinely wants a modified Tab can still bind it: an explicit binding matches\n // before this fallback is consulted.\n if (event.key === \"Tab\")\n return !event.ctrlKey && !event.metaKey && !event.altKey;\n if (!typing) return false;\n // AltGraph arrives as ctrl+alt on the layouts that use it, so it must be unwrapped before\n // either modifier is read as a chord.\n const altGraph = event.getModifierState?.(\"AltGraph\") ?? false;\n\n if (!altGraph && (event.ctrlKey || event.metaKey)) {\n // A field owns its own editing commands. Suppressing these would leave a user unable to\n // copy, paste, undo or select inside an input that sits in a blocking modal — a far worse\n // outcome than an unbound accelerator reaching the browser. A binding that wants one of\n // these still matches first; only UNBOUND combinations reach here.\n const letter =\n event.key.length === 1 ? event.key.toLowerCase() : event.key;\n // Redo is the one editing command spelled WITH shift on Apple platforms; everywhere else\n // it is Ctrl+Y. Both are the field's.\n if (letter === \"z\" && event.shiftKey) return !event.altKey;\n if (letter === REDO_LETTER)\n return !isApple && !event.shiftKey && !event.altKey;\n // Shift is how a selection is EXTENDED: mod+shift+arrow selects by word and\n // mod+shift+Home to a boundary, so navigation keeps it. Letters do not — allowing\n // arbitrary modified variants let Ctrl+Shift+A, the browser's tab search, pass as though\n // it were select-all and escape the grab entirely.\n if (EDITING_NAVIGATION.has(event.key)) return !event.altKey || isApple;\n if (event.shiftKey || event.altKey) return false;\n return EDITING_LETTERS.has(letter);\n }\n // Option turns caret keys into their by-word forms on macOS, and is a text modifier there;\n // on Windows and Linux, Alt with a named key is a menu accelerator.\n if (!altGraph && event.altKey) {\n // A native select opens and closes its option popup with Alt and the vertical arrows, so\n // the control's own claim is checked before the key is written off as an accelerator.\n if (\n (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") &&\n asElement(eventTarget(event))?.tagName === \"SELECT\"\n ) {\n return true;\n }\n if (!isApple) return false;\n if (EDITING_NAVIGATION.has(event.key)) return true;\n }\n // Both are the start of composed text and both precede `isComposing`.\n if (event.key === \"Dead\" || event.key === \"Process\") return true;\n // One CODE POINT, not one code unit: an astral character is a single letter written as two\n // UTF-16 units, and rejecting it stops emoji and many scripts being typed at all.\n if ([...event.key].length === 1) return true;\n // Enter, PageUp and PageDown edit or scroll only where the target owns multiple lines. In a\n // single-line input Enter submits the form and the page keys scroll the document behind it —\n // application behaviour running underneath the grab, not text entry.\n if (AMBIGUOUS_KEYS.has(event.key)) return targetOwnsAmbiguousKey(event);\n return FIELD_KEYS.has(event.key);\n }\n\n /**\n * Offer one candidate sequence to the stack.\n *\n * Takes the triggering event alongside the pressed sequence rather than reading the last\n * element back out: the sequence is the matching key, the event is what gets acted on, and\n * conflating them made the non-empty invariant something a reader had to reconstruct.\n */\n function offer(\n pressed: readonly KeyboardEvent[],\n event: KeyboardEvent,\n typing: boolean,\n invoke: boolean\n ): \"fired\" | \"pending\" | \"blocked\" | \"none\" {\n for (const layer of ordered()) {\n // Only the layer that opened a sequence may complete it. That is a rule about MATCHING and\n // deliberately not about precedence: skipping the whole layer let a modal that mounted\n // mid-sequence be stepped over entirely, so a shell command ran straight through the\n // keyboard grab the modal had just taken.\n const mayMatch =\n pressed.length <= 1 || pendingLayer === null || layer === pendingLayer;\n\n if (mayMatch) {\n // Exact matches are resolved across the WHOLE layer before any prefix is considered.\n // Scanning in registration order instead makes one of `g` and `g d` unreachable purely\n // by which was registered first: `g` fires and clears the sequence, or `g d` returns\n // pending and the exact `g` is never examined. Order of registration should not decide\n // which binding exists.\n let prefixed = false;\n for (const prepared of layer.bindings) {\n if (typing && !firesWhileTyping(prepared)) continue;\n if (prepared.binding.when && !prepared.binding.when()) continue;\n const depth = matchDepth(prepared, pressed);\n if (depth === \"exact\") {\n fire(prepared, event, invoke);\n return \"fired\";\n }\n if (depth === \"prefix\") prefixed = true;\n }\n if (prefixed) {\n pendingLayer = layer;\n // A sequence in progress must swallow its own keystroke, or the `g` of `g d` would be\n // typed into the page while the sequence waits for `d`.\n event.preventDefault();\n return \"pending\";\n }\n }\n\n if (layer.options.blocking) return \"blocked\";\n }\n return \"none\";\n }\n\n /**\n * Warn when one binding's sequence is a strict prefix of another's in the same layer.\n *\n * `g` and `g d` cannot both be reachable: the first keystroke either acts or waits, and\n * whichever answer the matcher gives, the other binding is dead. Resolving it by registration\n * order would make the outcome depend on the order of an array, so the matcher is\n * deterministic (exact wins) and the ambiguity is reported instead of hidden.\n */\n function warnOnPrefixConflicts(\n prepared: readonly PreparedBinding[],\n layerName: string\n ): void {\n // `mod` is an alias, so the comparison has to happen after it is resolved: on Windows,\n // `mod+k` and `ctrl+k` are the same physical chord and raw flags call them different.\n const resolved = (chord: KeyChord): string => {\n const ctrl = chord.ctrl || (chord.mod && !isApple);\n const meta = chord.meta || (chord.mod && isApple);\n // Shift is normalised the way the MATCHER treats it. For punctuation whose glyph already\n // encodes shift, the matcher ignores the flag, so `?` and `shift+?` are one chord to it —\n // and a diagnostic that called them different stayed silent about a genuine conflict.\n const shift = shiftIsMeaningful(chord.key) ? chord.shift : false;\n return `${chord.key}\\u0000${ctrl}${meta}${chord.alt}${shift}`;\n };\n const sameChord = (a: KeyChord, b: KeyChord): boolean =>\n resolved(a) === resolved(b);\n for (const short of prepared) {\n for (const long of prepared) {\n if (short === long || short.keys.length >= long.keys.length) continue;\n // Only claim the longer binding is dead when nothing can separate the two at press time.\n // A conditional shorter binding is skipped while its `when` is false, and a difference in\n // typing eligibility means one of them is out of play in a focused field — in both cases\n // the sequence does become reachable, and telling the developer to delete one of them\n // would be wrong.\n if (short.binding.when !== undefined) continue;\n // Only ONE direction makes the longer binding reachable. A typing-disabled shorter\n // binding paired with a typing-enabled longer one is genuinely separable: inside a field\n // the short one is out of play and the sequence can run. The reverse is not — outside a\n // field both are eligible and the exact match wins, inside it only the short one is — so\n // the longer binding is dead either way and the warning belongs.\n if (!firesWhileTyping(short) && firesWhileTyping(long)) continue;\n if (short.keys.every((chord, i) => sameChord(chord, long.keys[i]))) {\n devWarnOnce(\n false,\n `shortcuts: in layer \"${layerName}\", \"${short.binding.keys}\" is a prefix of ` +\n `\"${long.binding.keys}\", so the longer one can never fire. Bind one or the other.`\n );\n }\n }\n }\n }\n\n const watchers = new Set<() => void>();\n /** The last computed binding list, so repeated reads return the same array identity. */\n let snapshot: readonly ActiveShortcut[] | null = null;\n\n /** The bindings a reader sees, in precedence order. */\n function computeSnapshot(): readonly ActiveShortcut[] {\n return ordered().flatMap(layer =>\n layer.bindings.map(prepared => ({\n keys: prepared.binding.keys,\n description: prepared.binding.description,\n layer: layer.options.name,\n }))\n );\n }\n\n /** Whether two binding lists describe the same surface, field by field. */\n function sameShortcuts(\n a: readonly ActiveShortcut[],\n b: readonly ActiveShortcut[]\n ): boolean {\n return (\n a.length === b.length &&\n a.every(\n (entry, index) =>\n entry.keys === b[index]?.keys &&\n entry.description === b[index]?.description &&\n entry.layer === b[index]?.layer\n )\n );\n }\n\n /**\n * Invalidate the snapshot and tell anyone watching that the stack changed.\n *\n * Watchers are notified only when what they can OBSERVE differs. `update()` runs after every\n * render of a registering component, so notifying unconditionally makes a component that both\n * registers shortcuts and reads them re-render, update, and notify again without end, until\n * React stops it with \"Maximum update depth exceeded\". An unchanged surface also keeps its\n * previous array identity, which is what an external store must return for a reader not to\n * re-render on a read.\n */\n function changed(): void {\n const previous = snapshot;\n snapshot = null;\n if (watchers.size === 0) return;\n const next = computeSnapshot();\n if (previous && sameShortcuts(previous, next)) {\n snapshot = previous;\n return;\n }\n snapshot = next;\n for (const watcher of watchers) watcher();\n }\n\n const pressedEvents: KeyboardEvent[] = [];\n\n /**\n * Offer the keystroke, leaving no sequence behind if a consumer's callback throws.\n *\n * An uncaught handler exception does not stop the page, so without this the half-typed prefix\n * outlives the keystroke that failed: a later key could complete a DIFFERENT command in a\n * lower layer, long after the one that threw had already acted.\n */\n function runOffer(\n pressed: readonly KeyboardEvent[],\n event: KeyboardEvent,\n typing: boolean\n ): \"fired\" | \"pending\" | \"blocked\" | \"none\" {\n try {\n return offer(pressed, event, typing, true);\n } catch (error) {\n abandonSequence();\n // Only THIS key's consumption is dropped. Clearing the map forgot every other key still\n // held: a later repeat of one of those was re-offered rather than inheriting its\n // suppression, and a binding whose own action had made it ineligible reported the repeat\n // unhandled, handing the browser an accelerator the first press had suppressed.\n consumedPresses.delete(signature(event));\n throw error;\n }\n }\n\n function handle(event: KeyboardEvent): boolean {\n // An event this manager cannot read as a keystroke at all.\n //\n // `attach` listens on `document`, so EVERYTHING dispatched on the page arrives here,\n // including synthetic events from code that is not ours -- `new CustomEvent(\"keydown\")`,\n // password managers, autofill shims. Those carry no `key`, and the match path spreads it\n // (`[...key]`) and calls `startsWith` on it, both of which throw on `undefined`.\n //\n // Admitted ONCE, here, rather than defended at each read: `handle` is the only way in, and\n // `key` is the only property whose absence throws. The modifier flags degrade to \"no match\"\n // when undefined, and `getModifierState` is already optional-chained at both call sites.\n //\n // Reported as NOT consumed, so `attach` leaves it propagating: an event this manager cannot\n // interpret must reach whatever listener does understand it.\n if (typeof event.key !== \"string\") return false;\n\n // Checked FIRST among real keystrokes: an owner closer to the keystroke has already answered it, and that stays\n // true even while an IME is composing. Reported as consumed so `attach` stops it\n // propagating — the manager runs no binding, but it is the one place that can keep a\n // window-level owner from acting on a key someone else already answered.\n if (event.defaultPrevented) {\n abandonSequence();\n return true;\n }\n // Composition keystrokes belong to the IME. Escape there means \"abandon what I am\n // composing\", so acting on it would cancel the composition AND whatever the application\n // binds Escape to.\n if (event.isComposing) {\n abandonSequence();\n // Reported as consumed WITHOUT preventing the default: the IME's own handling must go\n // ahead, and no other listener should act on the keystroke either. During a staged\n // migration a window-level owner would otherwise dismiss or navigate on the Escape the\n // user pressed to cancel what they were composing.\n return true;\n }\n // Pressing a modifier on its own is not a keystroke to match, and treating it as one would\n // clear any sequence in progress the moment the user reached for Shift. A layer holding the\n // keyboard still consumes it, though — without preventing its default, since a modifier press\n // has no default worth suppressing, and without disturbing the sequence. Otherwise a legacy\n // window-level handler reacting to Shift or Alt still changes application state underneath a\n // grab that claims to hold every unmatched key.\n if (MODIFIER_KEYS.has(event.key)) return blocking();\n\n // A focused native control gets its own activation keys before the shortcut stack sees them.\n if (controlOwnsKey(eventTarget(event), event)) {\n abandonSequence();\n // Consumed WITHOUT preventing the default, exactly as a composing keystroke is: the\n // control's own activation must go ahead, and no other listener should act on it either.\n // A window-level owner acting on the Space that ticked a checkbox is the same double\n // action in a quieter place.\n return true;\n }\n\n const typing = isTypingTarget(eventTarget(event));\n\n // A held key repeats. The binding must not run again, but the key must stay CONSUMED: a\n // shortcut that suppressed the browser on the first keydown and then let every repeat\n // through would open the browser's own save dialog while the key was held down.\n if (event.repeat) {\n // A repeat of some OTHER key is a real keystroke between the sequence's own. While `x` is\n // held, pressing `g`, receiving another `x` repeat, then pressing `d` must not complete\n // `g d` as though nothing had come between them.\n //\n // Measured against the key that OPENED the prefix, not against whether this manager\n // consumed the repeating key. Holding a consumed key — `mod+s` — while typing `g d` put\n // that key in the consumed map, so asking the map preserved the prefix across a keystroke\n // from an entirely different key.\n if (pendingKey !== signature(event)) {\n abandonSequence();\n }\n // Re-offering is not enough on its own. A binding whose action changes its own condition —\n // `mod+s` saving and clearing the dirty flag — is no longer eligible by the second\n // keydown, so the repeat would be reported unhandled and the browser would take it. What\n // was consumed is a PRESS, not a match, so the press is what gets remembered.\n const held = consumedPresses.get(signature(event));\n if (held) {\n // Two different questions about one held key, and they have different answers.\n //\n // CONSUMED belongs to the physical press: it does not move when the modifiers around it\n // do, so the repeats of a keystroke this manager answered stay its own.\n //\n // SUPPRESSED is a property of the keystroke, and modifiers change what that is. A press\n // that was prevented stays prevented — adding shift to a held `mod+s` must not hand the\n // browser a Save As. A press that was PERMITTED, though, was permitted because it was\n // text: add Ctrl to a held `w` and it becomes the accelerator that closes the tab, so the\n // decision is re-made rather than inherited.\n //\n // A PERMITTED press is re-decided by ASKING the stack again, rather than by comparing a\n // signature of the things that might have changed.\n //\n // Three independent inputs decide it — the modifiers, the layer stack, and each binding's\n // own `when` — and the last cannot be signed at all: it is a function, so every render\n // supplies a new identity while the condition is unchanged, and signing it would re-decide\n // constantly. Re-offering reads all three at once, so a binding whose action falsified its\n // own condition stops permitting the browser default on its next repeat, rather than\n // leaving the page scrolling under a layer that claims to hold the keyboard.\n //\n // Offered with `invoke` false, so the matching binding's `preventDefault` policy applies\n // without its action running a second time.\n if (held.prevented) {\n event.preventDefault();\n } else {\n const still = offer([event], event, typing, false);\n // \"fired\" means a binding matched and its own `preventDefault` policy has already been\n // applied, so nothing more is decided here. Every other outcome leaves a press this\n // manager still owns with no one applying a policy to it, and the browser must not act\n // on a key we claim — unless it is text, which is the one thing a grab may never eat.\n //\n // The \"none\" case is not hypothetical: hold a plain `w` bound with\n // `preventDefault: false`, then add Ctrl. No binding matches Ctrl+W, there may be no\n // blocking layer to report it, and the browser closes the tab.\n if (still !== \"fired\" && !insertsText(event, typing)) {\n event.preventDefault();\n }\n }\n return true;\n }\n const repeated = offer([event], event, typing, false);\n if (repeated === \"blocked\" && !insertsText(event, typing)) {\n // A key can begin repeating BEFORE the layer that grabs the keyboard appears, so this is\n // the first time the manager sees it and there is no earlier press to inherit from.\n // Without this the browser keeps scrolling underneath the grab.\n event.preventDefault();\n }\n return repeated !== \"none\";\n }\n\n if (pendingAt !== null && now() - pendingAt > sequenceTimeoutMs) {\n abandonSequence();\n }\n\n pressedEvents.push(event);\n let outcome = runOffer(pressedEvents, event, typing);\n\n // A sequence that led nowhere must not eat the key that broke it: `g` then `mod+k` should\n // open the palette rather than being discarded with the abandoned prefix.\n //\n // \"blocked\" counts as leading nowhere. A blocking layer holding both a sequence and a\n // single-key binding would otherwise swallow the key that broke its own sequence — press\n // `g`, then Escape, and the layer's own Escape handler would need a SECOND press.\n if (\n pressedEvents.length > 1 &&\n (outcome === \"none\" || outcome === \"blocked\")\n ) {\n abandonSequence();\n pressedEvents.push(event);\n outcome = runOffer(pressedEvents, event, typing);\n }\n\n if (outcome === \"pending\") {\n pendingAt = now();\n pendingKey = signature(event);\n consumedPresses.set(signature(event), {\n prevented: event.defaultPrevented,\n });\n return true;\n }\n\n abandonSequence();\n if (outcome === \"blocked\") {\n // Applied HERE rather than inside `offer`, because a \"blocked\" from a multi-key candidate\n // is tentative: the retry below may still find an exact single-key binding, and one that\n // sets `preventDefault: false` cannot uncancel an event the fallback already cancelled.\n // A grab that leaves the browser default in place is still not a grab, so this runs once\n // the outcome is final.\n if (!insertsText(event, typing)) event.preventDefault();\n }\n const consumed = outcome === \"fired\" || outcome === \"blocked\";\n if (consumed) {\n consumedPresses.set(signature(event), {\n prevented: event.defaultPrevented,\n });\n } else {\n consumedPresses.delete(signature(event));\n }\n return consumed;\n }\n\n return {\n register(bindings, layerOptions) {\n const prepared = prepare(bindings);\n const layer: RegisteredLayer = {\n options: layerOptions,\n bindings: prepared,\n sequence: nextSequence++,\n shape: layerShape(prepared, layerOptions),\n };\n warnOnPrefixConflicts(layer.bindings, layerOptions.name);\n layers.add(layer);\n changed();\n return {\n update(nextBindings, nextOptions) {\n layer.bindings = prepare(nextBindings);\n layer.options = nextOptions;\n // The React hook registers empty and supplies its real bindings here, so a diagnostic\n // that only ran at `register` would never see the bindings anyone actually writes.\n warnOnPrefixConflicts(layer.bindings, nextOptions.name);\n const shape = layerShape(layer.bindings, nextOptions);\n const shapeChanged = shape !== layer.shape;\n layer.shape = shape;\n // Only a change to what this layer MATCHES can invalidate a promise it made. `update`\n // runs after every render, so cancelling unconditionally made a sequence fail whenever\n // an unrelated re-render landed between its two keystrokes.\n if (shapeChanged && pendingLayer === layer) abandonSequence();\n changed();\n },\n dispose() {\n layers.delete(layer);\n changed();\n if (pendingLayer === layer) abandonSequence();\n },\n };\n },\n handle,\n attach(target) {\n const listener = (event: Event): void => {\n // `preventDefault` suppresses the BROWSER, not other JavaScript listeners. A consumed\n // key must also stop bubbling, or a window-level owner runs the second half of the\n // double action this manager exists to remove — which is the state of the tree during a\n // staged migration, when some owners have moved over and some have not.\n try {\n if (handle(event as KeyboardEvent)) event.stopPropagation();\n } catch (error) {\n // A binding whose callback threw still CLAIMED the key. Dispatch continues to later\n // listeners after an exception is reported, so leaving the event unstopped would hand\n // the same keystroke to a window-level owner and recreate the double action — with a\n // failed handler, which is the worst moment to run a fallback as though nothing had.\n event.stopPropagation();\n throw error;\n }\n };\n target.addEventListener(\"keydown\", listener);\n return () => {\n target.removeEventListener(\"keydown\", listener);\n // A sequence belongs to the event stream that began it. A provider swapping targets\n // would otherwise let a `g` from the old document be completed by a `d` on the new one,\n // and a repeat inherit consumption state from keystrokes this target never saw.\n abandonSequence();\n consumedPresses.clear();\n };\n },\n subscribe(onChange) {\n watchers.add(onChange);\n return () => {\n watchers.delete(onChange);\n };\n },\n activeBindings() {\n // Cached, because an external store must return a stable identity for an unchanged stack:\n // a fresh array on every read makes React re-render without end.\n if (snapshot) return snapshot;\n snapshot = computeSnapshot();\n return snapshot;\n },\n };\n}\n\nconst MODIFIER_KEYS = new Set([\n \"Control\",\n \"Meta\",\n \"Alt\",\n \"Shift\",\n // A dedicated AltGraph key reports its own keydown before the character-producing one. Without\n // it here, pressing AltGraph mid-sequence abandons the sequence before the character that would\n // have completed it ever arrives.\n \"AltGraph\",\n]);\n\n/**\n * Roles whose widgets consume bare characters themselves.\n *\n * `textbox` takes text; the rest do type-ahead — Radix's Select jumps between options on a\n * letter, and its menus move focus the same way, neither preventing default nor stopping\n * propagation. A shortcut firing over them acts on top of a selection the user just made.\n */\nconst TYPE_AHEAD_ROLES = new Set([\n \"textbox\",\n \"combobox\",\n \"listbox\",\n // The focused element inside an open listbox is the OPTION, and it is what the event reports;\n // the listbox itself is only its ancestor.\n \"option\",\n \"menu\",\n \"menuitem\",\n \"menuitemcheckbox\",\n \"menuitemradio\",\n]);\n\n/** The non-arrow keys a native range input uses to move its value. */\nconst RANGE_KEYS = new Set([\"Home\", \"End\", \"PageUp\", \"PageDown\"]);\n\n/**\n * The letters a text field claims with Ctrl or Command: clipboard, select-all, undo and redo.\n *\n * Unbound, these belong to the field rather than to the application, so a modal that grabbed the\n * keyboard would otherwise make copy and paste impossible inside its own inputs.\n */\nconst EDITING_LETTERS = new Set([\"a\", \"c\", \"v\", \"x\", \"z\"]);\n\n/**\n * Redo, which is spelled differently on each platform.\n *\n * Ctrl+Y is redo on Windows and Linux. On macOS redo is Command+Shift+Z, and Command+Y is a\n * BROWSER accelerator that opens history — so treating it as an editing key everywhere would let\n * it escape a keyboard grab on the one platform where it is not editing at all.\n */\nconst REDO_LETTER = \"y\";\n\n/** Caret movement and deletion, which a modifier turns into their by-word forms. */\nconst EDITING_NAVIGATION = new Set([\n \"Insert\",\n \"ArrowLeft\",\n \"ArrowRight\",\n \"ArrowUp\",\n \"ArrowDown\",\n \"Home\",\n \"End\",\n \"Backspace\",\n \"Delete\",\n]);\n\n/** Keys whose owner depends on which control has focus. */\nconst AMBIGUOUS_KEYS = new Set([\"Enter\", \"PageUp\", \"PageDown\"]);\n\n/**\n * Whether the focused target owns this particular ambiguous key.\n *\n * Enter, PageUp and PageDown mean different things to different controls, so one answer for all\n * three would be wrong for at least one of them. Enter inserts a newline only where there are\n * lines; the page keys page through content, which a native select does with its option list.\n */\nfunction targetOwnsAmbiguousKey(event: KeyboardEvent): boolean {\n const element = asElement(eventTarget(event));\n if (element === null) return false;\n const multiline = element.tagName === \"TEXTAREA\" || element.isContentEditable;\n if (event.key === \"Enter\") return multiline;\n return multiline || element.tagName === \"SELECT\";\n}\n\n/**\n * Keys a focused field consumes itself: caret movement and the edits that carry no character.\n *\n * Tab is here because a focus trap needs it: it only cancels the wrap at the first and last\n * tabbable element, and relies on the browser default for every move in between.\n *\n * Used to decide what a blocking layer may suppress while the user is typing. A key outside this\n * set and not a character belongs to the browser, not the field.\n */\nconst FIELD_KEYS = new Set([\n \"Backspace\",\n \"Delete\",\n \"ArrowUp\",\n \"ArrowDown\",\n \"ArrowLeft\",\n \"ArrowRight\",\n \"Home\",\n \"End\",\n // Shift+Insert pastes and carries no ctrl or meta, so it arrives here rather than at the\n // chord branch where Ctrl+Insert is recognised.\n \"Insert\",\n // Tab moves focus, and a blocking layer must NOT take it. The documented case for blocking is\n // a modal, whose focus trap only calls `preventDefault()` at the first and last tabbable\n // element — ordinary moves between the controls inside it rely on the browser default.\n // Suppressing every Tab therefore pinned focus to one control in exactly the situation\n // blocking exists to serve. A layer that genuinely wants Tab binds it.\n \"Tab\",\n]);\n","\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport type * as React from \"react\";\nimport { cloneElement, Fragment, useEffect, useId } from \"react\";\n\nimport { devWarnOnce, isDevelopmentRuntime } from \"../lib/dev-warn\";\nimport { cn } from \"../lib/utils\";\nimport type {\n FieldShellProps,\n FieldShellRenderProps,\n} from \"../types/form-layout\";\n\n/**\n * The width cap applies to a wrapper around the control, not to the field row.\n *\n * The row keeps its container's full width so labels, descriptions and errors\n * align down the form; only the control itself is bounded. Capping the row\n * would indent the label along with the input and make a column of mixed-width\n * fields read as ragged.\n *\n * The fallbacks are the literals a caller would otherwise reach for, so the\n * component works before any theme defines these properties.\n */\nconst controlWidth = cva(\"w-full\", {\n variants: {\n width: {\n half: \"max-w-[var(--nx-field-half,380px)]\",\n full: \"max-w-[var(--nx-field-full,760px)]\",\n fill: \"\",\n },\n },\n defaultVariants: { width: \"half\" },\n});\n\n/**\n * The subset of a child's own props this component reads before deciding\n * what to merge onto it.\n *\n * `child.props` is untyped (`ReactElement<unknown>`), so this narrows it\n * defensively — checking each key is actually present with the expected\n * primitive type — rather than asserting a shape onto a value nothing has\n * verified. A key present with the wrong type (an `id` that is a number, an\n * `aria-describedby` that is a boolean) is treated the same as absent: the\n * caller's field-shell contract is about ids, id-reference strings and a\n * validity flag, and a value that cannot serve as one is not a real\n * override.\n */\ninterface KnownControlProps {\n id?: unknown;\n \"aria-describedby\"?: unknown;\n \"aria-invalid\"?: unknown;\n}\n\nfunction readControlProps(child: React.ReactElement): KnownControlProps {\n const props: unknown = child.props;\n // An object with no properties the type checker knows about is already\n // assignable to a type whose properties are all optional, so no cast is\n // needed here: only the `typeof` guard is doing real work.\n return props && typeof props === \"object\" ? props : {};\n}\n\n/**\n * The props this component injects onto a cloned control, computed once and\n * applied with a single `cloneElement` call.\n *\n * Declared as its own type, rather than inlined at the call site, so the\n * object passed to `cloneElement` carries real key names instead of a\n * loosely-typed record. `children`'s props are unknown to this component (see\n * `KnownControlProps` above), so `cloneElement`'s `Partial<P>` parameter\n * collapses to `{}` for any child it is handed — meaning this type is the\n * only thing constraining what gets attached, and getting its keys right is\n * what keeps a typo from silently landing on the DOM as a data attribute.\n */\ninterface ControlOverrides {\n id: string;\n \"aria-describedby\"?: string;\n \"aria-invalid\"?: boolean;\n}\n\n/**\n * `children` may be a single element (cloned) or a function that receives\n * the computed wiring and applies it itself.\n *\n * `typeof` is the only check that can tell the two apart at runtime: both\n * are valid members of the union, and nothing about a value's STATIC type\n * alone settles which one a given `children` is. Declaring this as a real\n * type-guard function — rather than inlining `typeof children === \"function\"`\n * at each call site — is what lets every caller below narrow `children`\n * without a cast.\n */\nfunction isRenderFunction(\n children: FieldShellProps[\"children\"]\n): children is (field: FieldShellRenderProps) => React.ReactNode {\n return typeof children === \"function\";\n}\n\n/**\n * The id, `aria-describedby` and `aria-invalid` this component computes for\n * its control — ONE computation, shared by both the element-clone path and\n * the render-function path, so the two can never silently drift into\n * answering the same question differently.\n *\n * `ownProps` carries whatever the caller's single element already had (its\n * own id, an existing `aria-describedby` to compose with, an\n * `aria-invalid` to defer to when there is no error). The render-function\n * path passes an empty object: there is no pre-existing child to read those\n * from — the caller applies the returned wiring itself — so \"nothing to\n * defer to\" is simply the empty case of this same function rather than a\n * second, parallel computation.\n */\nfunction computeControlWiring(\n ownProps: KnownControlProps,\n requestedId: string,\n renderedMessageIds: readonly string[],\n hasError: boolean\n): FieldShellRenderProps {\n // A non-empty string the child already carries wins over the requested id;\n // anything else — including an explicitly-present `id={undefined}`, which\n // a naive object spread would let win — does not. Deciding this here,\n // rather than leaving it to a generic prop-merge, is the entire point of\n // owning the merge: there is exactly one rule for what counts as \"the\n // child already has an id\", and it is applied before the clone rather than\n // discovered afterward in whatever a merge library happened to do.\n const ownId =\n typeof ownProps.id === \"string\" && ownProps.id !== \"\"\n ? ownProps.id\n : undefined;\n const id = ownId ?? requestedId;\n\n const ownDescribedByIds =\n typeof ownProps[\"aria-describedby\"] === \"string\"\n ? ownProps[\"aria-describedby\"].split(\" \").filter(Boolean)\n : [];\n // Compose, never replace: a child may already point at ids of its own (a\n // unit label, a character counter) that this component knows nothing\n // about, and overwriting them would break whatever wired them up. The\n // child's own ids come first so the reading order matches what the caller\n // wrote; `Set` then drops any id both sides already agree on.\n const describedByIds = Array.from(\n new Set([...ownDescribedByIds, ...renderedMessageIds])\n );\n const describedBy =\n describedByIds.length > 0 ? describedByIds.join(\" \") : undefined;\n\n const ownInvalid =\n typeof ownProps[\"aria-invalid\"] === \"boolean\"\n ? ownProps[\"aria-invalid\"]\n : undefined;\n // A rendered error always forces the control invalid: a child that\n // already set `aria-invalid={false}`, or left it unset, must not\n // suppress a validation message that is visibly on the page. With no\n // error, the child's own claim about itself (if any) passes through\n // unmodified instead of being cleared to absent.\n const invalid = hasError ? true : ownInvalid;\n\n return { id, describedBy, invalid };\n}\n\n/** @experimental */\nexport function FieldShell({\n label,\n description,\n error,\n width = \"half\",\n htmlFor,\n className,\n children,\n}: FieldShellProps) {\n // Two independent id namespaces: one for the control (below), one for the\n // description/error text this field may render. The latter never depends\n // on `htmlFor` or the child's own id, because those name the CONTROL, not\n // FieldShell's own paragraphs.\n const generatedControlId = useId();\n const messageBaseId = useId();\n const descriptionId = `${messageBaseId}-description`;\n const errorId = `${messageBaseId}-error`;\n\n // What FieldShell would use for the control absent any id the child\n // already carries: `htmlFor` when the caller supplied one, a generated id\n // otherwise.\n const requestedId = htmlFor ?? generatedControlId;\n\n // Only messages that actually render get an id, and only those ids are\n // listed: a control pointed at an id nothing carries is worse than one\n // with no description at all.\n const renderedMessageIds = [\n description ? descriptionId : null,\n error ? errorId : null,\n ].filter((id): id is string => id !== null);\n\n const wiring = isRenderFunction(children)\n ? computeControlWiring({}, requestedId, renderedMessageIds, Boolean(error))\n : computeControlWiring(\n readControlProps(children),\n requestedId,\n renderedMessageIds,\n Boolean(error)\n );\n\n // A Fragment is a valid `ReactElement` — it type-checks as one — but it\n // forwards none of these props to anything inside it, so cloning it would\n // silently disconnect the label and the validation wiring from every real\n // element the Fragment contains. The type system cannot rule this out\n // (`Fragment`'s element type is indistinguishable from any other\n // component's at the type level), so it is checked at runtime instead, and\n // computed here — once — rather than separately by the render branch below\n // and the mount check that follows it.\n const isFragmentChild =\n !isRenderFunction(children) && children.type === Fragment;\n\n // Development-only: confirm the id this component computed actually\n // landed on something in the document. A compound Radix control (the\n // `Select` root, and by the same shape `RadioGroup`) destructures a fixed,\n // named prop list and never spreads the remainder, so an id attached via\n // `cloneElement` — or one a render function forgot to apply to its real\n // control — is silently dropped: nothing throws, nothing else warns, and\n // the label ends up pointing at an id nothing carries. Gated on\n // `isDevelopmentRuntime()` up front, rather than only inside\n // `devWarnOnce`, so the DOM query itself never runs in production — not\n // merely its console output. Skipped for a Fragment child: that case is\n // already reported, precisely and without a DOM query, by the warning\n // below — this check would only restate the same defect less specifically.\n useEffect(() => {\n if (!isDevelopmentRuntime()) return;\n if (isFragmentChild) return;\n const landed = document.getElementById(wiring.id) !== null;\n const fieldName = typeof label === \"string\" ? `\"${label}\"` : \"this field\";\n devWarnOnce(\n landed,\n `FieldShell: the id computed for ${fieldName} never appeared on any element in the ` +\n \"document, so its label and any description are not connected to the control. This \" +\n \"happens when the control is a compound component — a Radix `Select`, `RadioGroup`, \" +\n \"or similar — whose root does not forward `id`/`aria-describedby`/`aria-invalid` to a \" +\n \"real DOM node. Pass `children` as a function and apply those to the control's actual \" +\n \"focusable element (its trigger) instead of a single top-level clone.\"\n );\n // `wiring.id` is the value being checked; `label` supplies the message's\n // field name; `isFragmentChild` decides whether the check runs at all.\n // Re-running when any of these changes lets the check re-evaluate a\n // field whose identity, generated id or child shape shifted, rather\n // than only ever inspecting the very first commit.\n }, [wiring.id, label, isFragmentChild]);\n\n let control: React.ReactNode;\n if (isRenderFunction(children)) {\n control = children(wiring);\n } else {\n devWarnOnce(\n !isFragmentChild,\n \"FieldShell: `children` must be a single element, not a Fragment. A Fragment forwards \" +\n \"no props to the elements inside it, so the id, aria-describedby and aria-invalid this \" +\n \"component computes would have nowhere to land — the label and the control would look \" +\n \"wired up and never actually connect. Wrap the intended elements in a real element \" +\n \"instead, such as a `<div>`.\"\n );\n const controlOverrides: ControlOverrides = {\n id: wiring.id,\n ...(wiring.describedBy !== undefined\n ? { \"aria-describedby\": wiring.describedBy }\n : {}),\n ...(wiring.invalid !== undefined\n ? { \"aria-invalid\": wiring.invalid }\n : {}),\n };\n // Cloning a Fragment with these props would only add React's own\n // \"invalid prop supplied to React.Fragment\" warning on top of the one\n // above without fixing anything, so it is rendered unmodified and the\n // warning is the only signal.\n control = isFragmentChild\n ? children\n : cloneElement(children, controlOverrides);\n }\n\n return (\n <div className={cn(\"flex flex-col gap-1.5\", className)}>\n {label ? (\n <label\n htmlFor={wiring.id}\n className=\"text-sm font-medium text-foreground\"\n >\n {label}\n </label>\n ) : null}\n <div className={controlWidth({ width })}>{control}</div>\n {description ? (\n <p id={descriptionId} className=\"text-sm text-muted-foreground\">\n {description}\n </p>\n ) : null}\n {error ? (\n <p id={errorId} className=\"text-sm font-medium text-destructive\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n","import type * as React from \"react\";\nimport { useId } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\nimport { Card } from \"./card\";\n\n/** @experimental */\nexport interface FormSectionProps {\n /** Short label above the card, rendered uppercase. */\n label: string;\n /** Optional sentence under the label. */\n description?: React.ReactNode;\n className?: string;\n children: React.ReactNode;\n}\n\n/**\n * A labelled card holding a group of fields.\n *\n * Composes `Card` rather than hand-rolling its own border and background, so\n * a section carries the CONTAINER radius tier `Card` already defines instead\n * of a second, drifting copy of the same chrome. There is deliberately no\n * footer slot. A form commits as one document, so its action belongs to the\n * page rather than to a section.\n * @experimental\n */\nexport function FormSection({\n label,\n description,\n className,\n children,\n}: FormSectionProps) {\n // The visible label stays a `<p>` — promoting it to a heading would pick a\n // heading LEVEL, which depends on where in the page this section lands and\n // this component has no way to know. `aria-labelledby` names the region\n // for assistive tech without making that document-structure claim.\n const labelId = useId();\n\n return (\n <section aria-labelledby={labelId} className={cn(\"space-y-2\", className)}>\n <div className=\"space-y-1\">\n <p\n id={labelId}\n className=\"text-xs font-semibold tracking-[0.08em] uppercase text-muted-foreground\"\n >\n {label}\n </p>\n {description ? (\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n ) : null}\n </div>\n <Card className=\"overflow-hidden\">\n {/* The section owns its vertical rhythm rather than leaving each child\n to pad itself. A card renders whatever children it is handed and\n cannot tell one row idiom from another, so a rhythm supplied by the\n rows is only as reliable as the least careful of them — and a row\n that supplies none renders flush against the card's borders.\n\n One token serves both the card's edge padding and the gap between\n two fields, because they are the same measurement seen twice. Two\n tokens could drift apart with nothing to notice.\n\n The rhythm itself is a plain CSS rule shipped in the theme\n (`.nx-form-section-rows`) rather than a Tailwind utility here. The\n utility spelling differs between Tailwind majors, and an\n arbitrary-value token is extracted from any file the scanner reads —\n a comment naming one included. A theme rule has neither property.\n\n A child must not pad itself: the two are additive, so a row carrying\n its own `py-*` doubles the rhythm on the sections that are already\n correct. */}\n <div className=\"nx-form-section-rows divide-y divide-foreground/10 px-6\">\n {children}\n </div>\n </Card>\n </section>\n );\n}\n","import { cn } from \"../lib/utils\";\nimport type { FormActionsProps } from \"../types/form-layout\";\n\n/**\n * One action bar per form, at the end of the page's measure.\n *\n * A form commits as a single document, so there is one place to commit it. The\n * dirty flag arrives from the page because the form state already answers that\n * question, and a second implementation of it here would disagree with the\n * first as soon as either changed.\n * @experimental\n */\nexport function FormActions({ dirty, className, children }: FormActionsProps) {\n return (\n <div\n className={cn(\n \"sticky bottom-0 mt-8 flex items-center justify-end gap-3\",\n \"border-t border-border bg-background/95 py-4 backdrop-blur\",\n className\n )}\n >\n {dirty ? (\n // `role=\"status\"` (implying `aria-live=\"polite\"`) so a screen-reader\n // user is told when the flag flips false to true, not only sighted\n // users watching the bar. This is the only live region FormActions\n // renders, one per form.\n <span role=\"status\" className=\"mr-auto text-sm text-muted-foreground\">\n You have unsaved changes\n </span>\n ) : null}\n {children}\n </div>\n );\n}\n","import type { CSSProperties, HTMLAttributes } from \"react\";\nimport {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useRef,\n} from \"react\";\n\nimport { devWarnOnce, isDevelopmentRuntime } from \"../lib/dev-warn\";\nimport { cn } from \"../lib/utils\";\n\n/** @experimental */\nexport interface PageShellProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Which measure the content column is bounded to. `full` removes the cap so\n * the column takes whatever the panel gives it, while KEEPING the gutter — a\n * full-width page is still inset from the panel's edge.\n */\n width?: \"form\" | \"wide\" | \"full\";\n}\n\n/**\n * `CSSProperties` models only the properties csstype knows about, so a CSS\n * custom property is not assignable to it.\n *\n * Naming the single property this component sets keeps the object CHECKED: a\n * typo in the property name is still a compile error, and the value still has\n * to be a string. The blanket `as CSSProperties` assertion used elsewhere in\n * this repo would accept a misspelled custom property silently, which for a\n * value the grid template reads by name is the failure worth preventing — the\n * layout would fall back to its default measure and nothing would say so.\n */\ntype ShellStyle = CSSProperties & Record<\"--nx-shell-measure\", string>;\n\n/**\n * Whether the shell has a direct child TEXT node with visible content.\n *\n * Read from the DOM after mount rather than by walking `children` before it,\n * because the element tree cannot answer this question. A component child is\n * opaque to a pre-render walk — `() => \"hello\"` is an element whose type is a\n * function, and what it returns is decided at render — so a traversal can only\n * ever recognise the shapes someone thought to enumerate: a bare literal, then\n * a fragment, then a component, then a component returning a fragment. The\n * rendered DOM is where the answer already exists, and it covers every shape at\n * once.\n *\n * Whitespace-only nodes are ignored: JSX routinely leaves them between elements\n * and CSS Grid does not make a grid item of one.\n */\nfunction hasBareTextChild(shell: HTMLElement): boolean {\n return Array.from(shell.childNodes).some(\n node => node.nodeType === Node.TEXT_NODE && node.textContent?.trim() !== \"\"\n );\n}\n\n/**\n * A shell already owns the inset somewhere up the tree.\n *\n * Nesting reintroduces the exact defect this primitive exists to end: an outer\n * shell places the inner one in its content column and the inner grid adds a\n * second pair of gutter tracks, so content is inset twice. Relying on every\n * caller to know whether an ancestor layout already rendered a shell is the\n * kind of unwritten precondition that holds until one page is composed\n * differently, so it is REPORTED.\n *\n * It is reported and not silently corrected, which is a deliberate choice\n * between two imperfect options. Suppressing the inner grid means either\n * keeping its wrapper — which lands in the outer content column and puts a\n * `Bleed` below it out of reach of `.nx-page-shell > .nx-bleed`, collapsing a\n * full-bleed block to the measure in PRODUCTION — or dropping the wrapper, and\n * with it the caller's `className`, `style` and `ref`. Both trade a visible,\n * warned mistake for a silent one. A double inset is conspicuous and arrives\n * with a message naming the fix.\n *\n * React context crosses a portal while DOM ancestry does not, so a shell\n * rendered through `createPortal` into a host outside this tree is reported as\n * nested when it is not. That costs a spurious development message and nothing\n * else: what renders no longer depends on this value.\n */\nconst InsideShell = createContext(false);\n\n/**\n * Whether a direct child has been taken out of the grid by `display: contents`.\n *\n * Such a child generates no box, so the `grid-column` rule has nothing to\n * apply to, while ITS children are promoted into this grid and match no\n * selector — they auto-place from the first track, which is a gutter. The\n * element is present and correctly classed, so nothing about the markup says\n * the content left the measure.\n */\nfunction hasDisplayContentsChild(shell: HTMLElement): boolean {\n return Array.from(shell.children).some(\n child => getComputedStyle(child).display === \"contents\"\n );\n}\n\n/**\n * What each named width resolves to, owned here because this is what applies it.\n *\n * Declared as a lookup rather than branched at the call site so the three arms\n * are one list. A `switch` here would let a fourth width be added to the type\n * and forgotten in the mapping, which the checker cannot see through a\n * `default` arm.\n *\n * Exported because a caller whose CONTENT carries the measure needs the same\n * value as a length, and the alternative is a second table naming the same\n * tokens — which drifts silently, since both look correct beside their own\n * neighbours. Reading it here means there is one answer rather than two that\n * agree today.\n *\n * @experimental\n */\nexport const SHELL_MEASURE: Record<\n NonNullable<PageShellProps[\"width\"]>,\n string\n> = {\n form: \"var(--nx-measure-form)\",\n wide: \"var(--nx-measure-wide)\",\n full: \"100%\",\n};\n\n/**\n * The page's inset and measure, owned in one place and spent as GRID COLUMNS.\n *\n * This replaces a pairing in which an outer container padded the panel and an\n * inner one padded again while capping the width. That shape had three\n * defects, and all three are structural rather than cosmetic:\n *\n * - The two insets ADDED, because padding is not something a descendant can\n * cancel. Measured on the settings page, the header sat at x=360 and the\n * form card at x=384 — a 24px disagreement between two elements that are\n * supposed to share a left edge. Here the inset is a column, so there is one\n * declaration and no second site to disagree with it.\n * - A measure applied INSIDE a form component lets anything the page renders\n * beside that form escape it. With the page owning the shell, a sibling is\n * inside the measure by default and leaves it only by saying `Bleed`.\n * - Centring by `mx-auto` on a max-width box does nothing at panel widths\n * where the cap does not bind. Here the two outer tracks are equal and\n * flexible, so the content column is centred at every width and no\n * `justify-content` is declared — with flexible tracks the grid fills its\n * container and there is no free space for one to distribute.\n *\n * Vertical padding stays ordinary `padding-block`: it is not in tension with\n * the columns, and keeping it here means one component answers the whole of\n * \"how far is content from the panel's edge\".\n * @experimental\n */\nexport const PageShell = forwardRef<HTMLDivElement, PageShellProps>(\n ({ width = \"form\", className, children, style, ...props }, ref) => {\n // The shell's own handle on its node, kept alongside whatever ref the\n // caller passed so the development check below can read the rendered DOM\n // without taking the ref away from them.\n const shellRef = useRef<HTMLDivElement | null>(null);\n const attachRef = useCallback(\n (node: HTMLDivElement | null) => {\n shellRef.current = node;\n // A callback ref's RETURN is the caller's cleanup under React 19, and\n // React runs it instead of calling the ref again with null. Discarding\n // it here would silently drop, say, an observer's disconnect. Passing it\n // straight through is also correct under the React 18 half of this\n // package's peer range, where such a ref returns nothing.\n if (typeof ref === \"function\") return ref(node);\n if (ref) ref.current = node;\n },\n [ref]\n );\n\n const nested = useContext(InsideShell);\n\n // Gated on the runtime up front so neither the DOM read nor the observer\n // below exists in production, not merely their console output.\n useEffect(() => {\n if (!isDevelopmentRuntime()) return;\n const shell = shellRef.current;\n if (!shell) return;\n\n devWarnOnce(\n !nested,\n \"PageShell: an ancestor already renders a PageShell. The two grids each add a pair of \" +\n \"gutter tracks, so this page's content is inset twice. Remove this shell, or move \" +\n \"the outer one.\"\n );\n\n const check = () => {\n devWarnOnce(\n !hasBareTextChild(shell),\n \"PageShell: a direct child renders as bare text. CSS Grid wraps it in an anonymous \" +\n \"grid item, which no selector can reach, so it is placed in the gutter rather than \" +\n \"the content column and sits outside the page's measure. Wrap it in an element — \" +\n \"a `<p>`, or the section it belongs to.\"\n );\n devWarnOnce(\n !hasDisplayContentsChild(shell),\n \"PageShell: a direct child has `display: contents`, so it generates no grid item and \" +\n \"the content-column rule has nothing to apply to. Its own children are promoted \" +\n \"into this grid, match no selector, and are placed from the gutter onward. Give \" +\n \"the child a box, or move `display: contents` inside it.\"\n );\n };\n\n check();\n\n // A child that swaps an element for text through its OWN state does not\n // re-render this component, so the effect above would never run again and\n // the defect would arrive unreported. Watching the child list is what\n // makes the check a property of the rendered DOM rather than of when this\n // component happened to render.\n //\n // `childList` ALONE, deliberately, and this is the boundary of the check\n // rather than an oversight. A child that stays mounted and mutates its\n // own class or style to `display: contents` is not reported, because\n // catching it needs `attributes` with `subtree: true` — MutationObserver\n // cannot scope attributes to direct children — which fires on every\n // descendant class change anywhere in the page. In an admin full of hover\n // states, transitions and editor chrome that is continuous, and each\n // notification re-runs `getComputedStyle` over every direct child.\n //\n // This is an advisory development warning: a miss costs only the report,\n // while a check that makes every developer's page churn is one that gets\n // deleted, taking its true positives with it. The mount-time pass above\n // still catches `display: contents` present at first render, which is how\n // it is almost always written.\n const observer = new MutationObserver(check);\n observer.observe(shell, { childList: true });\n return () => {\n observer.disconnect();\n };\n });\n\n // The caller's `style` is spread FIRST so the measure this component\n // computes from `width` wins over a hand-written `--nx-shell-measure`.\n // Two sources for one value would otherwise disagree silently, and\n // `width` is the supported way to choose it.\n const shellStyle: ShellStyle = {\n ...style,\n \"--nx-shell-measure\": SHELL_MEASURE[width],\n };\n\n return (\n <InsideShell.Provider value={true}>\n <div\n ref={attachRef}\n data-slot=\"page-shell\"\n // The measure travels as a custom property rather than as a utility\n // class because the grid template reads it: one `grid-template-columns`\n // serves all three widths, instead of three near-identical templates\n // that would each have to be corrected together.\n style={shellStyle}\n className={cn(\"nx-page-shell py-8\", className)}\n {...props}\n >\n {children}\n </div>\n </InsideShell.Provider>\n );\n }\n);\nPageShell.displayName = \"PageShell\";\n\n/** @experimental */\nexport type BleedProps = HTMLAttributes<HTMLDivElement>;\n\n/**\n * Opts one child out of the measure, edge to edge across the shell's gutter.\n *\n * The sanctioned form of something that previously only happened by accident.\n * A wide data table, a delivery log or a toolbar declares that it wants the\n * full panel, so a reviewer can see the intent — and, just as usefully, a block\n * that is merely in the wrong place no longer LOOKS like a deliberate\n * full-bleed.\n *\n * Valid only as a DIRECT child of `PageShell`. The `full-start`/`full-end`\n * lines are named on the shell's own grid, so they are in scope for its\n * children and nowhere else; nested inside a `FormSection` this renders a plain\n * block and the `grid-column` is inert. That is a real constraint rather than a\n * stylistic preference, and `page-shell.test.tsx` pins both halves: that a\n * `Bleed` rendered directly under the shell is its child, and that one nested a\n * level deeper does NOT receive the full column.\n *\n * It forwards its ref and any div attributes for the same reason: a consumer\n * cannot reach for the usual remedy of wrapping it, because a wrapper is\n * precisely what makes it stop working.\n * @experimental\n */\nexport const Bleed = forwardRef<HTMLDivElement, BleedProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n data-slot=\"bleed\"\n className={cn(\"nx-bleed\", className)}\n {...props}\n >\n {children}\n </div>\n )\n);\nBleed.displayName = \"Bleed\";\n","import type { HTMLAttributes, ReactNode } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** @experimental */\nexport interface PageHeaderProps\n extends Omit<HTMLAttributes<HTMLElement>, \"title\"> {\n /** The page's name, rendered as its `h1`. */\n title: string;\n /**\n * A sentence under the title. A `ReactNode` rather than a string because a\n * description carrying a link or an inline code span is ordinary here, and\n * typing it narrowly would push those pages back to hand-rolling the header.\n */\n description?: ReactNode;\n /** The trail above the title. The page supplies it; this only places it. */\n breadcrumbs?: ReactNode;\n /** Page-level actions, trailing the title on one line where there is room. */\n actions?: ReactNode;\n}\n\n/**\n * A page's own identity — its trail, its name, its one-line summary and its\n * actions — rendered once instead of at every page that needs one.\n *\n * Every value arrives as a PROP, and that is the point rather than an\n * implementation detail. The markup this replaces was written out by hand on 22\n * pages, and the settings pages took their title from a ~130-line chain that\n * matched `window.location.pathname` in a file none of them import. Both are\n * the same defect from opposite ends: a page knows what it is, and nothing let\n * it say so — so the title lived either in 22 copies or in one foreign file\n * that had to be edited whenever a route was added.\n *\n * The route registry already made this decision for the sidebar. A private\n * route must DECLARE the rail section it belongs to, because the sidebar reads\n * that declaration rather than matching the URL, which makes a route added\n * without one a compile error instead of a page that silently highlights the\n * wrong entry. A title derived from a pathname is the same defect in the half\n * nobody had covered.\n *\n * It also makes a plugin's page indistinguishable from a first-party one: a\n * plugin cannot add a branch to an if-chain it does not ship, but it can pass a\n * prop.\n * @experimental\n */\nexport const PageHeader = forwardRef<HTMLElement, PageHeaderProps>(\n ({ title, description, breadcrumbs, actions, className, ...props }, ref) => (\n <header\n ref={ref}\n data-slot=\"page-header\"\n className={cn(\"mb-8\", className)}\n {...props}\n >\n {breadcrumbs ? <div className=\"mb-6\">{breadcrumbs}</div> : null}\n\n <div className=\"flex flex-col justify-between gap-4 sm:flex-row sm:items-center\">\n <div className=\"space-y-1\">\n <h1 className=\"text-xl font-semibold tracking-tight\">{title}</h1>\n {/* Muted rather than a faint tint of the primary: the latter was tried\n and did not meet contrast for secondary text. */}\n {description ? (\n <p className=\"mt-1 text-sm font-normal text-muted-foreground\">\n {description}\n </p>\n ) : null}\n </div>\n\n {/* Each optional slot is omitted rather than rendered empty. An empty\n <p> still occupies a line and still separates the title from what\n follows, so a title-only page would not keep the spacing of a page\n that never had a description. */}\n {actions ? (\n <div className=\"flex items-center gap-3\">{actions}</div>\n ) : null}\n </div>\n </header>\n )\n);\nPageHeader.displayName = \"PageHeader\";\n"],"mappings":"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","names":["CollapsibleContent","CollapsibleTrigger","import_class_variance_authority","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","LabelRoot","React","import_react","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_class_variance_authority","import_jsx_runtime","import_class_variance_authority","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_class_variance_authority","import_react","import_jsx_runtime","import_jsx_runtime","React","import_jsx_runtime","import_class_variance_authority","React","import_jsx_runtime","import_lucide_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","SwitchRoot","SwitchThumb","CollapsibleTrigger","CollapsibleContent","import_lucide_react","import_react","import_jsx_runtime","import_class_variance_authority","import_react","import_jsx_runtime","AvatarRoot","AvatarImagePrimitive","AvatarFallbackPrimitive","import_class_variance_authority","import_react","import_jsx_runtime","React","import_jsx_runtime","import_class_variance_authority","import_lucide_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_lucide_react","React","import_jsx_runtime","import_class_variance_authority","import_lucide_react","import_react","import_jsx_runtime","DialogPrimitive","import_class_variance_authority","React","import_jsx_runtime","DialogPrimitive","import_lucide_react","import_react","import_jsx_runtime","CommandPrimitive","useCommandStatePrimitive","import_class_variance_authority","import_lucide_react","import_react","import_jsx_runtime","import_lucide_react","import_jsx_runtime","Sonner","React","import_jsx_runtime","import_lucide_react","import_jsx_runtime","import_lucide_react","import_jsx_runtime","import_jsx_runtime","_","import_lucide_react","React","clamp01","clamp01","React","import_jsx_runtime","import_lucide_react","React","import_jsx_runtime","menuItemBase","import_lucide_react","import_jsx_runtime","import_lucide_react","React","import_jsx_runtime","React","import_jsx_runtime","React","options","import_jsx_runtime","import_class_variance_authority","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/components/button.tsx","../src/lib/utils.ts","../src/components/input.tsx","../src/components/textarea.tsx","../src/components/label.tsx","../src/components/form-label-with-tooltip.tsx","../src/components/tooltip.tsx","../src/providers/portal-provider.tsx","../src/components/badge.tsx","../src/components/card.tsx","../src/components/layout.tsx","../src/components/alert.tsx","../src/components/separator.tsx","../src/components/skeleton.tsx","../src/components/progress.tsx","../src/components/checkbox.tsx","../src/components/radio-group.tsx","../src/components/switch.tsx","../src/components/collapsible.tsx","../src/components/accordion.tsx","../src/components/avatar.tsx","../src/components/tabs.tsx","../src/components/popover.tsx","../src/components/dialog.tsx","../src/components/alert-dialog.tsx","../src/components/dropdown-menu.tsx","../src/components/select.tsx","../src/components/sheet.tsx","../src/components/command.tsx","../src/components/spinner.tsx","../src/components/toaster.tsx","../src/components/table.tsx","../src/components/table-search.tsx","../src/components/table-states.tsx","../src/components/table-skeleton.tsx","../src/components/color-picker.tsx","../src/lib/color/convert.ts","../src/lib/color/hex.ts","../src/lib/color/picker-geometry.ts","../src/lib/isomorphic-layout-effect.ts","../src/components/context-menu.tsx","../src/components/resizable.tsx","../src/components/tree-view.tsx","../src/components/slider.tsx","../src/lib/dev-warn.ts","../src/lib/shortcuts/react.tsx","../src/lib/shortcuts/key-spec.ts","../src/lib/shortcuts/manager.ts","../src/components/field-shell.tsx","../src/components/form-section.tsx","../src/components/form-actions.tsx","../src/components/page-shell.tsx","../src/components/page-header.tsx"],"sourcesContent":["/**\n * The presentational half of the plugin-author API surface.\n *\n * Export groups below carry a TSDoc release tag mirroring `STABILITY.md`, which\n * is the authoritative ledger — where the two disagree, the ledger wins. A\n * group is `@public` only once a first-party plugin exercises it; everything\n * else is `@experimental` and may change in any release.\n *\n * `cn` and the Tailwind preset are deliberately NOT re-exported here: this\n * barrel ships a `\"use client\"` banner (see tsup.config.ts), because all but a\n * couple of these modules use hooks, context, forwardRef or Radix and cannot\n * render in a Server Component. Those two contain no React runtime and are\n * published as \"@nextlyhq/ui/utils\" and \"@nextlyhq/ui/tailwind-preset\" so\n * server code and build tooling can import them.\n */\n\n/** @public Button. Exercised by form-builder and page-builder. */\n// Components — Button\nexport { Button } from \"./components/button\";\n\n/** @experimental Styling helper; no first-party plugin imports it. */\nexport { buttonVariants } from \"./components/button\";\n/** @public */\nexport type { ButtonProps } from \"./types/button\";\n\n/** @public Form controls (input, textarea, label, tooltip label). */\n// Components — Input\nexport { Input } from \"./components/input\";\n\n/** @experimental Styling helper; no first-party plugin imports it. */\nexport { inputVariants } from \"./components/input\";\n/** @public */\nexport type { InputProps } from \"./components/input\";\n/** @public */\nexport { Textarea } from \"./components/textarea\";\n/** @public */\nexport { Label } from \"./components/label\";\n/** @public */\nexport { FormLabelWithTooltip } from \"./components/form-label-with-tooltip\";\n/** @public */\nexport type { FormLabelWithTooltipProps } from \"./components/form-label-with-tooltip\";\n\n// Components — Display. Release tags are per clause below.\n/** @public */\nexport { Badge } from \"./components/badge\";\n\n/** @experimental */\nexport { badgeVariants } from \"./components/badge\";\n/** @public */\nexport type { BadgeProps } from \"./components/badge\";\n/** @experimental */\nexport {\n Card,\n CardHeader,\n CardFooter,\n CardTitle,\n CardAction,\n CardDescription,\n CardContent,\n cardVariants,\n} from \"./components/card\";\n/** @experimental */\nexport type {\n CardProps,\n CardHeaderProps,\n CardTitleProps,\n CardDescriptionProps,\n CardActionProps,\n CardContentProps,\n CardFooterProps,\n} from \"./components/card\";\n/** @experimental */\nexport { Stack, Grid, Stat } from \"./components/layout\";\n/** @experimental */\nexport type { StackProps, GridProps, StatProps } from \"./components/layout\";\n/** @experimental */\nexport {\n Alert,\n AlertTitle,\n AlertDescription,\n alertVariants,\n} from \"./components/alert\";\n/** @experimental */\nexport type {\n AlertProps,\n AlertTitleProps,\n AlertDescriptionProps,\n} from \"./components/alert\";\n/** @experimental */\nexport { Separator } from \"./components/separator\";\n/** @experimental */\nexport { Skeleton } from \"./components/skeleton\";\n/** @experimental */\nexport type { SkeletonProps } from \"./components/skeleton\";\n/** @experimental */\nexport { Progress, progressVariants } from \"./components/progress\";\n/** @experimental */\nexport type { ProgressProps } from \"./components/progress\";\n\n/** @public Checkbox, switch and radio group. */\n// Components — Toggle\nexport { Checkbox } from \"./components/checkbox\";\n/** @public */\nexport { RadioGroup, RadioGroupItem } from \"./components/radio-group\";\n/** @public */\nexport { Switch } from \"./components/switch\";\n/** @experimental */\nexport {\n Collapsible,\n CollapsibleTrigger,\n CollapsibleContent,\n} from \"./components/collapsible\";\n\n// Components — Radix Primitives. Release tags are per clause below.\n/** @experimental */\nexport {\n Accordion,\n AccordionItem,\n AccordionTrigger,\n AccordionContent,\n} from \"./components/accordion\";\n/** @experimental */\nexport type {\n AccordionProps,\n AccordionItemProps,\n AccordionTriggerProps,\n AccordionContentProps,\n} from \"./types/accordion\";\n\n/** @experimental */\nexport {\n Avatar,\n AvatarImage,\n AvatarFallback,\n avatarVariants,\n} from \"./components/avatar\";\n/** @experimental */\nexport type {\n AvatarProps,\n AvatarImageProps,\n AvatarFallbackProps,\n} from \"./types/avatar\";\n\n/** @public */\nexport { Tabs, TabsList, TabsTrigger, TabsContent } from \"./components/tabs\";\n/** @public */\nexport type { TabsProps, TabsContentProps } from \"./types/tabs\";\n/**\n * From the COMPONENT module, not from `./types/tabs`.\n *\n * `./types/tabs` describes the Radix props alone, so an alias taken from there\n * rejects `variant` and `size` — and this barrel is what a consumer imports, so\n * exporting the derived aliases from the component file alone leaves them\n * unreachable.\n * @public\n */\nexport type { TabsListProps, TabsTriggerProps } from \"./components/tabs\";\n\n/** @public */\nexport { Tooltip, TooltipTrigger, TooltipContent } from \"./components/tooltip\";\n\n/** @experimental */\nexport { TooltipProvider } from \"./components/tooltip\";\n\n/** @experimental */\nexport {\n Popover,\n PopoverTrigger,\n PopoverContent,\n PopoverAnchor,\n} from \"./components/popover\";\n\n// Components — Dialog. Exercised by page-builder.\n/** @public */\nexport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogFooter,\n DialogTitle,\n DialogDescription,\n} from \"./components/dialog\";\n\n/** @experimental */\nexport {\n DialogPortal,\n DialogOverlay,\n DialogClose,\n DialogTrigger,\n dialogContentVariants,\n} from \"./components/dialog\";\n/** @public Prop types carry the same guarantee as their component. */\nexport type {\n DialogContentProps,\n DialogHeaderProps,\n DialogFooterProps,\n DialogTitleProps,\n DialogDescriptionProps,\n} from \"./components/dialog\";\n\n/** @experimental */\nexport type { DialogOverlayProps } from \"./components/dialog\";\n\n/** @experimental No first-party plugin depends on it yet. */\n// Components — AlertDialog\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n} from \"./components/alert-dialog\";\n/** @experimental */\nexport type {\n AlertDialogOverlayProps,\n AlertDialogContentProps,\n AlertDialogHeaderProps,\n AlertDialogFooterProps,\n AlertDialogTitleProps,\n AlertDialogDescriptionProps,\n AlertDialogActionProps,\n AlertDialogCancelProps,\n} from \"./components/alert-dialog\";\n\n// Components — DropdownMenu. Exercised by page-builder.\n/** @public */\nexport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuSeparator,\n} from \"./components/dropdown-menu\";\n\n/** @experimental */\nexport {\n DropdownMenuRadioItem,\n DropdownMenuLabel,\n DropdownMenuShortcut,\n DropdownMenuGroup,\n DropdownMenuPortal,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuRadioGroup,\n} from \"./components/dropdown-menu\";\n/** @public Prop types carry the same guarantee as their component. */\nexport type {\n DropdownMenuContentProps,\n DropdownMenuItemProps,\n DropdownMenuCheckboxItemProps,\n DropdownMenuSeparatorProps,\n} from \"./types/dropdown-menu\";\n\n/** @experimental */\nexport type {\n DropdownMenuSubTriggerProps,\n DropdownMenuSubContentProps,\n DropdownMenuRadioItemProps,\n DropdownMenuLabelProps,\n DropdownMenuShortcutProps,\n} from \"./types/dropdown-menu\";\n\n// Components — Select. Exercised by both first-party plugins.\n/** @public */\nexport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"./components/select\";\n\n/** @experimental */\nexport {\n SelectGroup,\n SelectLabel,\n SelectScrollDownButton,\n SelectScrollUpButton,\n SelectSeparator,\n selectTriggerVariants,\n} from \"./components/select\";\n/** @public */\nexport type { SelectTriggerProps } from \"./components/select\";\n\n// Components — Sheet. Exercised by page-builder.\n/** @public */\nexport {\n Sheet,\n SheetContent,\n SheetHeader,\n SheetTitle,\n SheetDescription,\n} from \"./components/sheet\";\n\n/** @experimental */\nexport {\n SheetPortal,\n SheetOverlay,\n SheetTrigger,\n SheetClose,\n SheetFooter,\n sheetVariants,\n} from \"./components/sheet\";\n/** @public */\nexport type { SheetContentProps } from \"./components/sheet\";\n/** @public Prop types carry the same guarantee as their component. */\nexport type {\n SheetProps,\n SheetHeaderProps,\n SheetTitleProps,\n SheetDescriptionProps,\n} from \"./types/sheet\";\n\n/** @experimental */\nexport type {\n SheetTriggerProps,\n SheetCloseProps,\n SheetOverlayProps,\n SheetFooterProps,\n SheetOverlayRef,\n SheetContentRef,\n SheetTitleRef,\n SheetDescriptionRef,\n} from \"./types/sheet\";\n\n/** @experimental No first-party plugin depends on it yet. */\n// Components — Command\nexport {\n Command,\n CommandDialog,\n CommandInput,\n CommandList,\n CommandEmpty,\n CommandGroup,\n CommandItem,\n commandDefaultFilter,\n useCommandHighlight,\n CommandSeparator,\n CommandShortcut,\n} from \"./components/command\";\n/** @experimental */\nexport type {\n CommandProps,\n CommandDialogProps,\n CommandInputProps,\n CommandListProps,\n CommandEmptyProps,\n CommandGroupProps,\n CommandItemProps,\n CommandSeparatorProps,\n CommandShortcutProps,\n} from \"./components/command\";\n\n/** @experimental No first-party plugin depends on it yet. */\n// Components — Spinner\nexport { Spinner, spinnerVariants } from \"./components/spinner\";\n/** @experimental */\nexport type { SpinnerProps } from \"./components/spinner\";\n\n// Components — Toaster\n/** @public */\nexport { toast } from \"./components/toaster\";\n\n/** @experimental */\nexport { Toaster } from \"./components/toaster\";\n/** @experimental */\nexport type { ToasterProps } from \"sonner\";\n\n/** @experimental No first-party plugin depends on them yet. */\n// Components — Table Primitives\nexport {\n Table,\n TableHeader,\n TableBody,\n TableFooter,\n TableHead,\n TableRow,\n TableCell,\n TableCaption,\n} from \"./components/table\";\n\n/** @experimental No first-party plugin depends on them yet. */\n// Components — Table Utilities\nexport { TableSearch } from \"./components/table-search\";\n/** @experimental */\nexport type { TableSearchProps } from \"./components/table-search\";\n\n/** @experimental */\nexport {\n TableError,\n TableLoading,\n TableEmpty,\n} from \"./components/table-states\";\n/** @experimental */\nexport type {\n TableErrorProps,\n TableEmptyProps,\n} from \"./components/table-states\";\n\n/** @experimental */\nexport { TableSkeleton } from \"./components/table-skeleton\";\n/** @experimental */\nexport type { TableSkeletonProps } from \"./components/table-skeleton\";\n\n// Components — ColorPicker. A colour control that knows nothing about tokens:\n// a swatch carries an opaque `value` it hands back untouched, so a host storing\n// a token reference keeps it rather than receiving the colour it resolved to.\n/** @experimental */\nexport { ColorPicker } from \"./components/color-picker\";\n/** @experimental */\nexport type { ColorPickerProps, ColorSwatch } from \"./components/color-picker\";\n\n/** @experimental */\n// Types: Table\nexport type {\n PaginationMeta,\n SortInfo,\n FilterInfo,\n TableParams,\n ListResponse,\n PaginationConfig,\n ActionCallbacks,\n DataFetcher,\n} from \"./types/table\";\n\n/** @public Required to use styles.scoped.css correctly; see STABILITY.md. */\n// Providers\nexport {\n PortalProvider,\n usePortalContainer,\n} from \"./providers/portal-provider\";\n\n// Utilities\n\n// Tailwind Preset\n\n/**\n * @experimental Editor-shell primitives.\n *\n * A right-click menu and a resizable split. Nothing in a first-party plugin imports them yet, so\n * they stay experimental: this kit graduates a surface only once one does.\n */\nexport {\n ContextMenu,\n ContextMenuCheckboxItem,\n ContextMenuContent,\n ContextMenuGroup,\n ContextMenuItem,\n ContextMenuLabel,\n ContextMenuRadioGroup,\n ContextMenuRadioItem,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n} from \"./components/context-menu\";\n\n/** @experimental */\nexport {\n ResizableHandle,\n ResizablePanel,\n ResizablePanelGroup,\n} from \"./components/resizable\";\n\n/**\n * @experimental A virtualized, keyboard-operable tree — the layers panel of an editor.\n *\n * Renders only the visible window, which is what makes a document of thousands of blocks usable\n * and what forces the flat `aria-level` markup: an item's children may not be in the DOM at all.\n */\nexport { TreeView } from \"./components/tree-view\";\n/** @experimental The node shape a tree is built from, and the control's props. */\nexport type { TreeNode, TreeViewProps } from \"./components/tree-view\";\n\n/**\n * @experimental A bounded numeric value chosen by dragging.\n *\n * Every inspector is full of these — opacity, blur radius, letter spacing, a colour's alpha —\n * and each is a property where \"more or less?\" is the useful question. `value` is an ARRAY even\n * for one thumb, which is what makes a range slider the same component rather than a second one.\n */\nexport { Slider } from \"./components/slider\";\n/**\n * @experimental The slider's props, and the per-thumb attributes assistive\n * technology reads — which are read from the THUMB and inherited from nothing,\n * so they cannot be passed through the root.\n */\nexport type { SliderProps, SliderThumbProps } from \"./components/slider\";\n\n/**\n * @experimental One owner for the shortcuts registered through it.\n *\n * It is the single listener for ITS OWN bindings, and it becomes the application's single owner\n * only once the surfaces with their own listeners adopt it. A component that still calls\n * `addEventListener(\"keydown\", ...)` is unaffected by anything here.\n *\n * The reason to adopt it: per-component `document` listeners cannot decide who owns a key —\n * `stopPropagation` does not stop siblings on the same node, so every global handler runs and\n * the winner is whichever component mounted first. Precedence here follows the component tree,\n * and a blocking layer lets a drag or a modal hold the keyboard while it is up.\n */\nexport {\n ShortcutProvider,\n ShortcutScope,\n useActiveShortcuts,\n useShortcutManager,\n useShortcuts,\n} from \"./lib/shortcuts/react\";\n/** @experimental The provider's props, and the options a layer registers with. */\nexport type {\n ShortcutProviderProps,\n UseShortcutsOptions,\n} from \"./lib/shortcuts/react\";\n/** @experimental The binding shape, and the manager for a host that drives its own events. */\nexport { createShortcutManager } from \"./lib/shortcuts/manager\";\n/**\n * @experimental The types a host needs to register shortcuts and inspect what is active:\n * `ShortcutBinding` is one shortcut, `ShortcutLayerOptions` its precedence and blocking policy,\n * `ShortcutRegistration` the handle for updating or removing it, and `ActiveShortcut` a binding\n * as a help panel sees it.\n */\nexport type {\n ActiveShortcut,\n ShortcutBinding,\n ShortcutLayerOptions,\n ShortcutManager,\n ShortcutManagerOptions,\n ShortcutRegistration,\n} from \"./lib/shortcuts/manager\";\n/** @experimental A layout effect in the browser, a plain effect where there is no DOM. */\nexport { useIsomorphicLayoutEffect } from \"./lib/isomorphic-layout-effect\";\n/** @experimental Key-spec parsing, for a host rendering its own shortcut hints. */\nexport { parseKeys } from \"./lib/shortcuts/key-spec\";\n/**\n * @experimental A parsed key spec, for rendering a shortcut hint from the same source the matcher\n * uses rather than re-splitting the string.\n */\nexport type { KeyChord, KeySequence } from \"./lib/shortcuts/key-spec\";\n/**\n * @experimental Deciding whether a keystroke IS a given chord, for a surface that must act on one\n * before the manager sees it — a capture-phase listener flushing uncommitted work ahead of a form's\n * own submit. Exported so that surface asks the same question the manager asks, rather than keeping\n * a second definition that is broader: `event.key === \"s\" && (metaKey || ctrlKey)` also fires on\n * Ctrl+Shift+S, which the manager rejects and the browser uses for Save As.\n */\nexport { chordMatches, detectApplePlatform } from \"./lib/shortcuts/key-spec\";\n/** @experimental The modifier flags {@link chordMatches} reads; a `KeyboardEvent` satisfies it. */\nexport type { ModifierState } from \"./lib/shortcuts/key-spec\";\n\n/** @experimental Form layout. No first-party plugin has exercised it in production yet. */\nexport { FieldShell } from \"./components/field-shell\";\n/** @experimental */\nexport type {\n FieldShellProps,\n FieldShellRenderProps,\n FieldWidth,\n} from \"./types/form-layout\";\n\n/**\n * @experimental A labelled card holding a group of fields, composing `Card`\n * rather than hand-rolling its own chrome. No first-party plugin has\n * exercised it in production yet.\n */\nexport { FormSection } from \"./components/form-section\";\n/** @experimental */\nexport type { FormSectionProps } from \"./components/form-section\";\n\n/**\n * @experimental A form's single action bar. The page measure it used to sit\n * beside is `PageShell`'s, reached through the page rather than the form. No\n * first-party plugin has exercised it in production yet.\n */\nexport { FormActions } from \"./components/form-actions\";\n/** @experimental */\nexport type { FormActionsProps } from \"./types/form-layout\";\n\n/**\n * @experimental The page shell: the gutter, the measure and the sanctioned\n * full-bleed escape, spent as grid columns so a second wrapper cannot add a\n * second inset and a full-bleed child does not have to be rendered outside the\n * measure in order to escape it. No first-party plugin has exercised it yet.\n */\nexport { Bleed, PageShell, SHELL_MEASURE } from \"./components/page-shell\";\n/**\n * @experimental A page's own identity — trail, name, summary and actions — fed\n * entirely by props, so a page declares what it is instead of a foreign file\n * deriving it from the URL. No first-party plugin has exercised it yet.\n */\nexport { PageHeader } from \"./components/page-header\";\n/** @experimental */\nexport type { PageHeaderProps } from \"./components/page-header\";\n/** @experimental */\nexport type { BleedProps, PageShellProps } from \"./components/page-shell\";\n","import { Slot } from \"@radix-ui/react-slot\";\nimport { cva } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport type { ButtonProps } from \"../types/button\";\n\n/**\n * Button Component - Design System Specification\n *\n * Interactive button element for user actions. Supports multiple variants,\n * sizes, and the asChild pattern for composition.\n *\n * Variants:\n * - default/primary: Primary action button (blue background, white text)\n * - secondary: Secondary action button (gray background)\n * - destructive: Destructive action button (red background)\n * - outline: Outlined button (transparent background, border)\n * - ghost: Minimal button (transparent, no border)\n * - link: Link-style button (underlined text)\n *\n * Note: 'primary' is a semantic alias for 'default' variant for better code readability\n * @experimental\n */\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium cursor-pointer transition-all duration-150 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-0 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed active:scale-[0.98] [&_svg]:text-current\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground border border-transparent hover:opacity-90\",\n primary:\n \"bg-primary text-primary-foreground border border-transparent hover:opacity-90\",\n // Solid fill uses the emphasis token so on-color text stays AA in dark\n // mode (the base token is the readable text color, too light here).\n // Hover darkens to a deeper shade rather than opacity-90, which would\n // composite the fill toward the page and drop the label under 4.5:1.\n // One step, not two: the label is white in light mode and black in\n // dark, so mixing the fill toward black moves it away from the label in\n // one mode and into it in the other. `-600` clears both (5.92:1 light,\n // 5.67:1 dark); `-700` reads at 3.70:1 against the dark label.\n destructive:\n \"bg-destructive-solid text-destructive-foreground border border-transparent hover:bg-destructive-600\",\n // border-border is the decorative separator token, and it is the right\n // one here: a button is identified by its label and fill, so its edge\n // carries no meaning on its own, unlike border-input, which is the\n // token for controls identified by their boundary (that token is now\n // below 1.4.11's 3:1 in light mode; see contrast/accepted.ts). It is\n // still used in preference to a faint primary alpha, which reads as a\n // tint of the brand colour rather than as an edge.\n outline:\n \"border border-border text-foreground hover-unified bg-background\",\n secondary:\n \"bg-background border border-border text-foreground hover:bg-primary/5\",\n ghost: \"text-foreground border border-transparent hover-unified\",\n link: \"text-primary border border-transparent underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-[var(--nx-control-height)] px-6 py-2\",\n sm: \"h-[var(--nx-control-height-md)] px-4 text-sm\",\n md: \"h-[var(--nx-control-height)] px-6 text-sm\",\n lg: \"h-[var(--nx-control-height-lg)] px-8 text-base\",\n icon: \"h-[var(--nx-control-height)] w-[var(--nx-control-height)] p-0\",\n \"icon-sm\":\n \"h-[var(--nx-control-height-md)] w-[var(--nx-control-height-md)] p-0\",\n \"icon-lg\":\n \"h-[var(--nx-control-height-lg)] w-[var(--nx-control-height-lg)] p-0\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"md\",\n },\n }\n);\n\n/** @public */\nconst Button = forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n className,\n variant = \"default\",\n size = \"md\",\n asChild = false,\n children,\n ...props\n },\n ref\n ) => {\n const Comp = asChild ? Slot : \"button\";\n\n // Automatically apply gap-2 if there are multiple children (e.g., icon + text)\n const hasMultipleChildren = React.Children.count(children) > 1;\n\n return (\n <Comp\n data-slot={`button.${variant}`}\n className={cn(\n buttonVariants({ variant, size, className }),\n hasMultipleChildren && \"gap-1.5\"\n )}\n ref={ref}\n {...props}\n >\n {children}\n </Comp>\n );\n }\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n","import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Utility function to merge class names with Tailwind CSS support.\n *\n * Combines clsx for conditional class names with tailwind-merge\n * to properly handle Tailwind CSS class conflicts.\n *\n * @example\n * ```typescript\n * cn('px-2 py-1', 'px-4') // => 'py-1 px-4'\n * cn('text-muted-foreground', condition && 'text-foreground')\n * ```\n *\n * @experimental\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { cva, type VariantProps } from \"class-variance-authority\";\nimport { forwardRef, type ComponentProps } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * Input Component - Design System Specification\n *\n * Text input fields for collecting user data. Supports various types (text,\n * email, password, number) and three size variants.\n *\n * Accessibility:\n * - Full keyboard navigation support\n * - Proper focus indicators (2px ring with offset)\n * - Error state support via aria-invalid\n * - Label association via htmlFor/id\n * - Placeholder text for guidance (not a replacement for labels)\n *\n * Design Specs:\n * - Height: sm=36px, default=40px, lg=44px\n * - Padding: Horizontal varies by size (sm=10px, default=12px, lg=16px)\n * - Border radius: `rounded-md`, the control step of the `--radius` scale\n * - Border: 1px solid, changes on focus/error\n * - Transition: 150ms (consistent with design system)\n * - Font size: sm/default=14px (text-sm), lg=16px (text-base)\n *\n * Size Variants:\n * - sm: Height 36px - Compact forms and filters, matching a small Button\n * - default: Height 40px (h-10) - Standard forms\n * - lg: Height 44px (h-11) - Prominent inputs, marketing forms\n *\n * Supported Types:\n * - text: General text input\n * - email: Email validation\n * - password: Hidden text input\n * - number: Numeric input with steppers\n * - tel: Phone number input\n * - url: URL validation\n * - search: Search input with clear button\n * @experimental\n */\nconst inputVariants = cva(\n // `text-foreground` is explicit rather than inherited. Tailwind's preflight\n // sets `color: inherit` on form controls, so without it the typed value takes\n // whatever colour an ancestor happens to carry -- muted inside a\n // `text-muted-foreground` block, red inside a `text-destructive` one. Select\n // and Textarea have always pinned it; Input was the one control that did not,\n // and callers were compensating by putting the token on a wrapper.\n \"file:text-foreground text-foreground placeholder:text-muted-foreground placeholder:opacity-50 selection:bg-primary selection:text-primary-foreground w-full min-w-0 rounded-md border border-input bg-background text-sm transition-all duration-150 outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 focus:ring-0 focus:ring-offset-0 focus:outline-none focus:border-primary! focus-visible:border-primary! aria-invalid:border-destructive aria-invalid:focus:border-destructive! data-[invalid=true]:border-destructive data-[invalid=true]:focus:border-destructive!\",\n {\n variants: {\n size: {\n // `-md` rather than `-sm`, so that a small input is the same height as\n // a small button standing beside it in a toolbar or a filter row.\n // Button's `sm` has always used this step; an input reading `-sm` made\n // `size=\"sm\"` mean 36px on one control and 32px on another, and a form\n // row mixing them sat 4px out of line.\n sm: \"h-[var(--nx-control-height-md)] px-2.5 py-2 text-sm\",\n default: \"h-[var(--nx-control-height)] px-3 py-2.5 text-sm\",\n lg: \"h-[var(--nx-control-height-lg)] px-4 py-3 text-base\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n }\n);\n\n/** @public */\nexport interface InputProps\n extends Omit<ComponentProps<\"input\">, \"size\">,\n VariantProps<typeof inputVariants> {}\n\n/** @public */\nconst Input = forwardRef<HTMLInputElement, InputProps>(\n ({ className, type, size, ...props }, ref) => {\n return (\n <input\n type={type}\n data-slot=\"input\"\n className={cn(inputVariants({ size, className }))}\n ref={ref}\n {...props}\n />\n );\n }\n);\n\nInput.displayName = \"Input\";\n\nexport { Input, inputVariants };\n","import type { TextareaHTMLAttributes } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** @public */\nconst Textarea = forwardRef<\n HTMLTextAreaElement,\n TextareaHTMLAttributes<HTMLTextAreaElement>\n>(({ className, ...props }, ref) => {\n return (\n <textarea\n data-slot=\"textarea\"\n className={cn(\n // hover:border-primary (full strength) keeps the hover boundary more\n // visible than the resting border-input, not a fainter alpha of it.\n \"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground placeholder:opacity-50 transition-all duration-200 focus:border-primary! focus-visible:border-primary! focus:outline-none hover:border-primary disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-primary/5 resize-y\",\n \"aria-invalid:border-destructive aria-invalid:focus:border-destructive!\",\n className\n )}\n ref={ref}\n {...props}\n />\n );\n});\nTextarea.displayName = \"Textarea\";\n\nexport { Textarea };\n","import { Root as LabelRoot } from \"@radix-ui/react-label\";\nimport type { ComponentProps } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** @public */\nfunction Label({ className, ...props }: ComponentProps<typeof LabelRoot>) {\n return (\n <LabelRoot\n data-slot=\"label\"\n className={cn(\n \"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Label };\n","import { Info } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\nimport { Label } from \"./label\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"./tooltip\";\n\n/** @public */\nexport interface FormLabelWithTooltipProps\n extends React.ComponentPropsWithoutRef<typeof Label> {\n label: React.ReactNode;\n description?: React.ReactNode;\n required?: boolean;\n labelClassName?: string;\n tooltipClassName?: string;\n}\n\n/** @public */\nexport const FormLabelWithTooltip = React.forwardRef<\n React.ElementRef<typeof Label>,\n FormLabelWithTooltipProps\n>(\n (\n {\n className,\n labelClassName,\n tooltipClassName,\n label,\n description,\n required,\n ...props\n },\n ref\n ) => {\n return (\n <div className={cn(\"flex items-center gap-2\", className)}>\n <Label ref={ref} className={labelClassName} {...props}>\n {label}\n {required && <span className=\"text-destructive ml-1\">*</span>}\n </Label>\n {description && (\n <TooltipProvider>\n <Tooltip delayDuration={200}>\n <TooltipTrigger\n type=\"button\"\n tabIndex={-1}\n className=\"shrink-0 text-muted-foreground hover:text-foreground focus:outline-none focus:text-foreground transition-colors cursor-help\"\n >\n <Info className=\"h-3.5 w-3.5\" />\n <span className=\"sr-only\">Toggle description</span>\n </TooltipTrigger>\n <TooltipContent\n side=\"right\"\n className={cn(\n \"max-w-[250px] text-xs break-words relative z-[100] shadow-md border border-border bg-primary text-primary-foreground px-3 py-2 rounded-lg\",\n tooltipClassName\n )}\n >\n {description}\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n )}\n </div>\n );\n }\n);\nFormLabelWithTooltip.displayName = \"FormLabelWithTooltip\";\n","import {\n Provider,\n Root,\n Trigger,\n Portal,\n Content,\n} from \"@radix-ui/react-tooltip\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\n\n/** @experimental */\nconst TooltipProvider = Provider;\n\n/** @public */\nconst Tooltip = Root;\n\n/** @public */\nconst TooltipTrigger = Trigger;\n\n/** @public */\nconst TooltipContent = forwardRef<\n React.ElementRef<typeof Content>,\n React.ComponentPropsWithoutRef<typeof Content>\n>(({ className, sideOffset = 4, ...props }, ref) => {\n const portalContainer = usePortalContainer();\n\n return (\n // Portalled for the same reason as every other overlay here, plus one\n // specific to the tooltip: the positioner measures against the nearest\n // containing block, and it counts `container-type` as one while the\n // browser does not. Left inline under a `@container` element, the content\n // is offset by that element's own position. Portalling lifts it out of any\n // such ancestor, so the two agree again.\n <Portal container={portalContainer}>\n <Content\n ref={ref}\n sideOffset={sideOffset}\n data-slot=\"tooltip-content\"\n className={cn(\n \"z-50 overflow-hidden rounded-lg px-3 py-1.5 text-xs shadow-lg border border-border bg-popover text-popover-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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\",\n className\n )}\n {...props}\n />\n </Portal>\n );\n});\nTooltipContent.displayName = Content.displayName;\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };\n","\"use client\";\n\nimport { createContext, useContext, type ReactNode } from \"react\";\n\ntype PortalContextValue = {\n container: HTMLElement | null;\n};\n\nconst PortalContext = createContext<PortalContextValue>({ container: null });\n\ninterface PortalProviderProps {\n /** The DOM element to portal overlay content into. Defaults to document.body (Radix default). */\n container: HTMLElement | null;\n children: ReactNode;\n}\n\n/** @public */\nfunction PortalProvider({ container, children }: PortalProviderProps) {\n return (\n <PortalContext.Provider value={{ container }}>\n {children}\n </PortalContext.Provider>\n );\n}\n\n/** @public */\nfunction usePortalContainer(): HTMLElement | undefined {\n const { container } = useContext(PortalContext);\n return container ?? undefined; // undefined = Radix default (document.body)\n}\n\nexport { PortalProvider, usePortalContainer };\n","import { cva, type VariantProps } from \"class-variance-authority\";\nimport type { HTMLAttributes } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * Badge Component - Design System Specification\n *\n * Badges are non-interactive elements used to highlight important information,\n * such as status indicators, counts, or labels. They should not be focusable\n * or interactive.\n *\n * Accessibility:\n * - Badges are non-interactive (no keyboard focus or click handlers)\n * - Color is not the only indicator - text conveys meaning\n * - Use aria-label for icon-only badges to provide context\n * - Provide contextual information in surrounding UI\n *\n * Design Specs:\n * - Height: 22px\n * - Padding: 2px 10px (vertical × horizontal)\n * - Border radius: Full (pill shape)\n * - Font: 12px (text-xs), medium weight (500)\n * - Colors: Light backgrounds with dark text for visibility in both light/dark modes\n *\n * Variants (6 total per design spec):\n * - default: Light gray background\n * - primary: Light blue background\n * - success: Light green background\n * - warning: Light amber background\n * - destructive: Light red background\n * - outline: Transparent background with border border-border\n * @experimental\n */\nconst badgeVariants = cva(\n \"inline-flex items-center rounded-sm px-2.5 py-0.5 h-[22px] text-xs font-medium transition-colors\",\n {\n variants: {\n variant: {\n // Clear, legible chip in both modes (was bg-primary/5 at ~5% opacity,\n // which was nearly invisible on dark backgrounds).\n default: \"bg-muted text-foreground\",\n primary: \"bg-primary/10 text-primary dark:bg-primary/20\",\n success:\n \"bg-success-100 text-success-700 dark:bg-success-900 dark:text-success-100\",\n warning:\n \"bg-warning-100 text-warning-700 dark:bg-warning-900 dark:text-warning-100\",\n destructive:\n \"bg-destructive-100 text-destructive-700 dark:bg-destructive-900 dark:text-destructive-100\",\n /*\n * The border colour is NOT important-marked. The base sets no border\n * colour, so nothing inside this component competes for it — the only\n * thing a mark could win against is the caller's own class. Seven\n * outline badges pass one, including a status pill whose comment gives\n * a 3:1 contrast reason for the colour it asks for, and every one of\n * them was being overridden without any sign that it had been.\n */\n outline:\n \"border border-border bg-transparent text-foreground dark:text-muted-foreground dark:border-border\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/** @public */\nexport interface BadgeProps\n extends HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof badgeVariants> {}\n\n/** @public */\nfunction Badge({ className, variant = \"default\", ...props }: BadgeProps) {\n return (\n <div\n data-slot={`badge.${variant}`}\n className={cn(badgeVariants({ variant }), className)}\n {...props}\n />\n );\n}\n\nexport { Badge, badgeVariants };\n","import { cva, type VariantProps } from \"class-variance-authority\";\nimport type { HTMLAttributes } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * Card Component - Design System Specification\n *\n * A container component for grouping related content with clear visual separation.\n * Cards provide a structured layout with header, content, and footer sections.\n *\n * Design Specs:\n * - Border radius: `rounded-lg`, the container step of the `--radius` scale\n * - Padding: 24px (p-6) for header/content, 16px 24px for footer\n * - Shadow: sm (default), md (hover/elevated)\n * - Border: 1px solid border border-border color\n *\n * Variants:\n * - default: Standard card with subtle shadow\n * - interactive: Hover effects for clickable cards (border border-border highlight, shadow increase)\n * ⚠️ IMPORTANT: When using the interactive variant, you MUST add appropriate\n * accessibility attributes:\n * - Add role=\"button\" or use an actual <button> wrapper\n * - Add tabIndex={0} to make it keyboard accessible\n * - Add onClick handler for mouse/touch interaction\n * - Add onKeyDown handler to support Enter/Space keys\n * - Add aria-label or aria-labelledby to describe the action\n * Example:\n * <Card\n * variant=\"interactive\"\n * role=\"button\"\n * tabIndex={0}\n * onClick={handleClick}\n * onKeyDown={(e) => e.key === 'Enter' && handleClick()}\n * aria-label=\"View user details\"\n * >\n * - elevated: More prominent shadow for emphasis\n *\n * Structure:\n * <Card>\n * <CardHeader>\n * <CardTitle>Title</CardTitle>\n * <CardDescription>Description</CardDescription>\n * <CardAction>Action buttons</CardAction>\n * </CardHeader>\n * <CardContent>Main content</CardContent>\n * <CardFooter>Footer actions</CardFooter>\n * </Card>\n *\n * Accessibility:\n * - Semantic HTML structure supports screen readers\n * - Interactive cards MUST have role, tabIndex, and keyboard handlers (see above)\n * - Ensure sufficient color contrast for all text (WCAG 2.2 AA minimum)\n * - Use aria-label or aria-labelledby for cards without visible text labels\n * @experimental\n */\nconst cardVariants = cva(\n \"bg-card text-foreground rounded-lg border border-border transition-all duration-200\",\n {\n variants: {\n variant: {\n default: \"\",\n interactive: \"cursor-pointer hover:border-primary active:scale-[0.99]\",\n elevated: \"shadow-md\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/** @experimental */\nexport type CardProps = HTMLAttributes<HTMLDivElement> &\n VariantProps<typeof cardVariants>;\n\n/** @experimental */\nconst Card = forwardRef<HTMLDivElement, CardProps>(\n ({ className, variant, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot={`card.${variant || \"default\"}`}\n className={cn(cardVariants({ variant }), className)}\n {...props}\n />\n );\n }\n);\nCard.displayName = \"Card\";\n\n/** @experimental */\nexport interface CardHeaderProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Whether to hide the bottom border border-border separator between header and content.\n * Default: false (border border-border is shown per design spec)\n */\n noBorder?: boolean;\n}\n\n/** @experimental */\nconst CardHeader = forwardRef<HTMLDivElement, CardHeaderProps>(\n ({ className, noBorder = false, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"card-header\"\n className={cn(\n // Mirrors CardFooter: a header that carries its own tint runs the full\n // width of the card, so at a nonzero --radius it would paint square\n // across the card's curved top corners. `inherit` takes the parent's\n // computed radius rather than restating a step. It only helps when the\n // header is a direct child of the card; a header nested inside another\n // wrapper inherits that wrapper's radius instead, and such a card needs\n // `overflow-hidden` to clip the fill.\n \"flex flex-col rounded-t-[inherit] p-4\",\n !noBorder && \"border-b border-border\",\n className\n )}\n {...props}\n />\n );\n }\n);\nCardHeader.displayName = \"CardHeader\";\n\n/** @experimental */\nexport type CardTitleProps = HTMLAttributes<HTMLHeadingElement>;\n\n/** @experimental */\nconst CardTitle = forwardRef<HTMLHeadingElement, CardTitleProps>(\n ({ className, ...props }, ref) => {\n return (\n <h3\n ref={ref}\n data-slot=\"card-title\"\n className={cn(\"text-xl font-semibold leading-none\", className)}\n {...props}\n />\n );\n }\n);\nCardTitle.displayName = \"CardTitle\";\n\n/** @experimental */\nexport type CardDescriptionProps = HTMLAttributes<HTMLParagraphElement>;\n\n/** @experimental */\nconst CardDescription = forwardRef<HTMLParagraphElement, CardDescriptionProps>(\n ({ className, ...props }, ref) => {\n return (\n <p\n ref={ref}\n data-slot=\"card-description\"\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n );\n }\n);\nCardDescription.displayName = \"CardDescription\";\n\n/** @experimental */\nexport type CardActionProps = HTMLAttributes<HTMLDivElement>;\n\n/** @experimental */\nconst CardAction = forwardRef<HTMLDivElement, CardActionProps>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"card-action\"\n className={cn(\"flex items-center justify-end\", className)}\n {...props}\n />\n );\n }\n);\nCardAction.displayName = \"CardAction\";\n\n/** @experimental */\nexport type CardContentProps = HTMLAttributes<HTMLDivElement>;\n\n/** @experimental */\nconst CardContent = forwardRef<HTMLDivElement, CardContentProps>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"card-content\"\n className={cn(\"p-6\", className)}\n {...props}\n />\n );\n }\n);\nCardContent.displayName = \"CardContent\";\n\n/** @experimental */\nexport type CardFooterProps = HTMLAttributes<HTMLDivElement>;\n\n/** @experimental */\nconst CardFooter = forwardRef<HTMLDivElement, CardFooterProps>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"card-footer\"\n className={cn(\n // The footer's tint runs the full width of the card, so at a nonzero\n // --radius it would paint square across the card's curved bottom\n // corners. `inherit` takes the card's own computed radius rather than\n // restating a step, so a card whose radius is overridden stays\n // matched, and it can never disagree with the card at any --radius,\n // including the shipped 0 where `rounded-lg` is 0.\n \"flex items-center px-6 py-4 border-t border-border bg-primary/5 rounded-b-[inherit]\",\n className\n )}\n {...props}\n />\n );\n }\n);\nCardFooter.displayName = \"CardFooter\";\n\nexport {\n Card,\n CardHeader,\n CardFooter,\n CardTitle,\n CardAction,\n CardDescription,\n CardContent,\n cardVariants,\n};\n","/**\n * Layout primitives for admin UI (plugins included).\n *\n * Token/utility-driven wrappers so a plugin can build common layouts —\n * vertical/horizontal stacks, responsive grids, labelled stat blocks — from the\n * admin's compiled stylesheet with no plugin build step. Gap/column values are\n * mapped to literal class names (not template strings) so Tailwind's scanner\n * detects and emits them.\n */\nimport { forwardRef, type HTMLAttributes, type ReactNode } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\ntype Gap = 0 | 1 | 2 | 3 | 4 | 6 | 8;\ntype Cols = 1 | 2 | 3 | 4 | 6;\n\nconst GAP: Record<Gap, string> = {\n 0: \"gap-0\",\n 1: \"gap-1\",\n 2: \"gap-2\",\n 3: \"gap-3\",\n 4: \"gap-4\",\n 6: \"gap-6\",\n 8: \"gap-8\",\n};\n\nconst COLS: Record<Cols, string> = {\n 1: \"grid-cols-1\",\n 2: \"grid-cols-2\",\n 3: \"grid-cols-3\",\n 4: \"grid-cols-4\",\n 6: \"grid-cols-6\",\n};\n\n/**\n * Container-query column counts, used when `responsive` is set.\n *\n * The grid starts at one column and widens at ITS OWN container's breakpoint\n * rather than the viewport's or an ancestor's. Unnamed `@` variants resolve\n * against the nearest container ancestor, which `responsive` mode guarantees\n * by rendering its own `@container` wrapper below — so this works wherever the\n * grid is mounted, with no dependency on a named container declared elsewhere.\n * Literal class names, not template strings, so Tailwind's scanner emits them.\n */\nconst RESPONSIVE_COLS: Record<Cols, string> = {\n 1: \"grid-cols-1\",\n 2: \"grid-cols-1 @2xl:grid-cols-2\",\n 3: \"grid-cols-1 @2xl:grid-cols-3\",\n 4: \"grid-cols-1 @2xl:grid-cols-4\",\n 6: \"grid-cols-1 @2xl:grid-cols-6\",\n};\n\n/** @experimental */\nexport interface StackProps extends HTMLAttributes<HTMLDivElement> {\n /** Main-axis direction. Default `col`. */\n direction?: \"col\" | \"row\";\n /** Gap between children (Tailwind spacing step). Default `4`. */\n gap?: Gap;\n}\n\n/** Flex stack: vertical by default, horizontal with `direction=\"row\"`.\n * @experimental\n */\nexport const Stack = forwardRef<HTMLDivElement, StackProps>(\n ({ direction = \"col\", gap = 4, className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n \"flex\",\n direction === \"col\" ? \"flex-col\" : \"flex-row\",\n GAP[gap],\n className\n )}\n {...props}\n />\n )\n);\nStack.displayName = \"Stack\";\n\n/** @experimental */\nexport interface GridProps extends HTMLAttributes<HTMLDivElement> {\n /** Column count. Default `2`. */\n cols?: Cols;\n /** Gap between cells. Default `4`. */\n gap?: Gap;\n /**\n * Collapse to one column in a narrow container. Off by default so existing\n * callers keep the fixed column count they were written against.\n */\n responsive?: boolean;\n}\n\n/** Simple fixed-column grid, or a container-responsive one via `responsive`.\n * @experimental\n */\nexport const Grid = forwardRef<HTMLDivElement, GridProps>(\n (\n { cols = 2, gap = 4, responsive = false, className, children, ...rest },\n ref\n ) => {\n if (!responsive) {\n // No wrapper: the single element IS the grid, exactly as before\n // `responsive` existed, so an existing caller's className, style and\n // other HTML attributes keep landing on the one node it renders.\n return (\n <div\n ref={ref}\n className={cn(\"grid\", COLS[cols], GAP[gap], className)}\n {...rest}\n >\n {children}\n </div>\n );\n }\n\n // Responsive mode renders its own unnamed `@container` wrapper so the\n // grid queries the space IT has, not any ancestor's — no dependency on a\n // named container declared elsewhere in the tree.\n //\n // That wrapper is the element that actually participates in the PARENT's\n // layout, so everything describing how this Grid sits in its parent —\n // `className`, `style` and the rest of the HTML attributes, plus `ref` —\n // belongs on it rather than on the inner grid. `cols` and `gap` describe\n // the grid's OWN internal layout and stay on the inner element regardless\n // of which mode is active. A caller passing spacing through `className`\n // instead of `gap` is already misusing the prop, not losing information.\n return (\n <div ref={ref} className={cn(\"@container\", className)} {...rest}>\n <div className={cn(\"grid\", RESPONSIVE_COLS[cols], GAP[gap])}>\n {children}\n </div>\n </div>\n );\n }\n);\nGrid.displayName = \"Grid\";\n\n/** @experimental */\nexport interface StatProps extends HTMLAttributes<HTMLDivElement> {\n /** Muted label above the value. */\n label: string;\n /** The emphasized value (string or node). */\n value: ReactNode;\n}\n\n/** Labelled metric block for dashboard-style plugin widgets.\n * @experimental\n */\nexport const Stat = forwardRef<HTMLDivElement, StatProps>(\n ({ label, value, className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex flex-col gap-1\", className)} {...props}>\n <span className=\"text-sm text-muted-foreground\">{label}</span>\n <span className=\"text-2xl font-semibold text-foreground\">{value}</span>\n </div>\n )\n);\nStat.displayName = \"Stat\";\n","import { cva, type VariantProps } from \"class-variance-authority\";\nimport { forwardRef, type HTMLAttributes } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * Alert Component - Design System Specification\n *\n * Alerts display important messages that require user attention or awareness.\n * They are non-interactive callouts used for inline notifications and feedback.\n *\n * Design Specs:\n * - Padding: 16px (p-4)\n * - Border radius: `rounded-md`, one step tighter than Card's `rounded-lg`\n * for inline/flow content vs. larger container components\n * - Border: 1px solid matching variant color\n * - Shadow: sm (subtle elevation)\n * - Font: 14px (text-sm)\n * - Layout: Flex with gap-3 for icon/content spacing\n * - Colors: Light backgrounds with dark text for WCAG 2.2 AA compliance\n *\n * Variants (4 total):\n * - info (default): Blue - informational messages, neutral announcements\n * - success: Green - successful operations, confirmations\n * - warning: Amber - cautions, warnings that need attention\n * - destructive: Red - errors, critical issues, failures\n *\n * Structure:\n * <Alert variant=\"info\">\n * <InfoIcon className=\"h-4 w-4\" />\n * <div>\n * <AlertTitle>Optional Title</AlertTitle>\n * <AlertDescription>Alert message content</AlertDescription>\n * </div>\n * </Alert>\n *\n * Accessibility:\n * - Defaults to role=\"alert\" for assertive screen reader announcements\n * - Override with role=\"status\" for non-urgent updates (polite announcements)\n * - Override with role={undefined} to remove ARIA role if needed\n * - Color is not the only indicator - icons and text convey meaning\n * - Supports rich content (links, lists) within AlertDescription\n * - WCAG 2.2 AA compliant color contrast (4.5:1 minimum)\n *\n * Usage Examples:\n *\n * // Simple alert with icon and description (default role=\"alert\")\n * <Alert variant=\"success\">\n * <CheckCircle2 className=\"h-4 w-4\" />\n * <AlertDescription>User created successfully!</AlertDescription>\n * </Alert>\n *\n * // Alert with title and description\n * <Alert variant=\"warning\">\n * <AlertTriangle className=\"h-4 w-4\" />\n * <div>\n * <AlertTitle>Warning</AlertTitle>\n * <AlertDescription>This action cannot be undone.</AlertDescription>\n * </div>\n * </Alert>\n *\n * // Non-urgent informational update\n * <Alert variant=\"info\" role=\"status\">\n * <AlertCircle className=\"h-4 w-4\" />\n * <AlertDescription>New features are now available.</AlertDescription>\n * </Alert>\n *\n * Icons (from lucide-react):\n * - Info: <AlertCircle className=\"h-4 w-4\" />\n * - Success: <CheckCircle2 className=\"h-4 w-4\" />\n * - Warning: <AlertTriangle className=\"h-4 w-4\" />\n * - Destructive: <XCircle className=\"h-4 w-4\" />\n * @experimental\n */\nconst alertVariants = cva(\n \"relative flex items-start gap-3 rounded-md border border-border p-4 text-sm transition-colors duration-150\",\n {\n variants: {\n variant: {\n // text-primary is mode-correct (dark ink on light in light mode, light\n // ink on dark in dark mode); the previous dark text override rendered\n // dark slate on the dark tint at about 1:1.\n info: \"bg-primary/5 text-primary\",\n // dark:border-l-* re-asserts the strong base accent on the left after\n // the dark:border-*-900 all-sides rule, so the meaningful accent stays\n // visible in dark mode instead of collapsing to the faint -900 shade.\n success:\n \"border-success-200 bg-success-50 text-success-900 border-l-4 border-l-success dark:border-success-900 dark:border-l-success dark:bg-success-950 dark:text-success-100\",\n warning:\n \"border-warning-200 bg-warning-50 text-warning-900 border-l-4 border-l-warning dark:border-warning-900 dark:border-l-warning dark:bg-warning-950 dark:text-warning-100\",\n destructive:\n \"border-destructive-200 bg-destructive-50 text-destructive-900 border-l-4 border-l-destructive dark:border-destructive-900 dark:border-l-destructive dark:bg-destructive-950 dark:text-destructive-100\",\n },\n },\n defaultVariants: {\n variant: \"info\",\n },\n }\n);\n\n/** @experimental */\nexport type AlertProps = HTMLAttributes<HTMLDivElement> &\n VariantProps<typeof alertVariants>;\n\n/**\n * Alert - Root container for alert messages\n *\n * Defaults to role=\"alert\" for screen reader announcements. Override with\n * role=\"status\" for non-urgent updates or role={undefined} to remove.\n *\n * @example\n * <Alert variant=\"success\">\n * <CheckCircle2 className=\"h-4 w-4\" />\n * <AlertDescription>Operation completed successfully</AlertDescription>\n * </Alert>\n * @experimental\n */\nconst Alert = forwardRef<HTMLDivElement, AlertProps>(\n ({ className, variant = \"info\", role = \"alert\", ...props }, ref) => {\n return (\n <div\n ref={ref}\n role={role}\n data-slot={`alert.${variant}`}\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n );\n }\n);\nAlert.displayName = \"Alert\";\n\n/** @experimental */\nexport type AlertTitleProps = HTMLAttributes<HTMLHeadingElement>;\n\n/**\n * AlertTitle - Heading text for alert message\n *\n * Renders as <h5> for semantic HTML structure. Use for brief, scannable\n * alert headings that summarize the message (e.g., \"Success\", \"Warning\").\n *\n * @example\n * <AlertTitle>Payment Successful</AlertTitle>\n * @experimental\n */\nconst AlertTitle = forwardRef<HTMLHeadingElement, AlertTitleProps>(\n ({ className, ...props }, ref) => {\n return (\n <h5\n ref={ref}\n data-slot=\"alert-title\"\n className={cn(\n \"mb-1 text-sm font-semibold leading-tight tracking-tight\",\n className\n )}\n {...props}\n />\n );\n }\n);\nAlertTitle.displayName = \"AlertTitle\";\n\n/** @experimental */\nexport type AlertDescriptionProps = HTMLAttributes<HTMLDivElement>;\n\n/**\n * AlertDescription - Supporting detail text for alert message\n *\n * Renders as <div> to support rich content (links, lists, formatting).\n * Use for detailed explanations, instructions, or contextual information.\n *\n * @example\n * <AlertDescription>\n * Your changes have been saved. <a href=\"/view\">View details</a>\n * </AlertDescription>\n * @experimental\n */\nconst AlertDescription = forwardRef<HTMLDivElement, AlertDescriptionProps>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"alert-description\"\n className={cn(\"text-sm leading-relaxed\", className)}\n {...props}\n />\n );\n }\n);\nAlertDescription.displayName = \"AlertDescription\";\n\nexport { Alert, AlertTitle, AlertDescription, alertVariants };\n","import * as SeparatorPrimitive from \"@radix-ui/react-separator\";\nimport type * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** @experimental */\nfunction Separator({\n className,\n orientation = \"horizontal\",\n decorative = true,\n ...props\n}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {\n return (\n <SeparatorPrimitive.Root\n data-slot=\"separator\"\n decorative={decorative}\n orientation={orientation}\n className={cn(\n \"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Separator };\n","import * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * Skeleton Loading Component\n *\n * A flexible loading placeholder component that provides visual feedback while content is loading.\n * Uses a subtle pulse animation to indicate ongoing loading state.\n *\n * @design_specs\n * - Background: bg-accent (slate-100 in light mode, slate-800 in dark mode)\n * - Animation: animate-pulse with motion-reduce:animate-none (respects prefers-reduced-motion)\n * - Border-radius: `rounded-md` by default; override per placeholder shape\n * - Contrast: 3:1 minimum for WCAG 1.4.11 (Non-text Contrast) compliance\n *\n * @accessibility\n * - Uses aria-hidden=\"true\" to hide from screen readers (visual indicator only)\n * - Skeleton should be purely decorative - actual loading state must be conveyed via:\n * 1. aria-busy=\"true\" on the parent content container\n * 2. Visually hidden loading text for screen readers\n * - Animation automatically disabled when user prefers reduced motion\n * - Reference: https://adrianroselli.com/2020/11/more-accessible-skeletons.html\n *\n * @usage_patterns\n *\n * **Text Line Skeleton:**\n * ```tsx\n * <Skeleton className=\"h-4 w-[250px]\" />\n * ```\n *\n * **Avatar Skeleton:**\n * ```tsx\n * <Skeleton className=\"h-12 w-12 rounded-md\" />\n * ```\n *\n * **Card Skeleton:**\n * ```tsx\n * <div className=\"space-y-3\">\n * <Skeleton className=\"h-[125px] w-[250px] rounded-lg\" />\n * <div className=\"space-y-2\">\n * <Skeleton className=\"h-4 w-[250px]\" />\n * <Skeleton className=\"h-4 w-[200px]\" />\n * </div>\n * </div>\n * ```\n *\n * **Proper Accessible Loading Pattern:**\n * ```tsx\n * <div aria-busy={isLoading} aria-label=\"User profile\">\n * {isLoading ? (\n * <>\n * <span className=\"sr-only\">Loading user profile...</span>\n * <Skeleton className=\"h-12 w-12 rounded-md\" />\n * <Skeleton className=\"h-4 w-[200px]\" />\n * </>\n * ) : (\n * <UserProfile data={userData} />\n * )}\n * </div>\n * ```\n *\n * @important\n * - DO: Use aria-busy=\"true\" on the parent container while loading\n * - DO: Provide visually hidden loading text for screen readers\n * - DO: Control dimensions via className (h-* w-* utilities)\n * - DON'T: Use aria-live, role=\"alert\", or role=\"progressbar\" on skeleton\n * - DON'T: Use skeleton without aria-busy on parent container\n *\n * @wcag_compliance WCAG 2.2 Level AA\n * - 1.4.11 Non-text Contrast: ✅ 3:1 minimum contrast ratio\n * - 2.3.3 Animation from Interactions: ✅ Respects prefers-reduced-motion\n * - 4.1.3 Status Messages: ✅ When used with aria-busy on parent\n *\n * @see {@link https://ui.shadcn.com/docs/components/skeleton shadcn/ui Skeleton}\n * @see {@link https://adrianroselli.com/2020/11/more-accessible-skeletons.html More Accessible Skeletons}\n * @experimental\n */\nconst Skeleton = React.forwardRef<HTMLDivElement, SkeletonProps>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"skeleton\"\n aria-hidden=\"true\"\n className={cn(\n \"bg-primary/5 animate-pulse rounded-md motion-reduce:animate-none\",\n className\n )}\n {...props}\n />\n );\n }\n);\n\nSkeleton.displayName = \"Skeleton\";\n\n/** @experimental */\nexport type SkeletonProps = React.ComponentProps<\"div\">;\n\nexport { Skeleton };\n","\"use client\";\n\n/**\n * Progress Component\n *\n * A horizontal progress bar component with variant support for different states.\n *\n * ## Design Specifications\n *\n * - **Height**: 8px (h-2)\n * - **Border Radius**: `rounded-full` on the track, fixed rather than derived\n * from `--radius` so an 8px bar always reads as a capsule; the fill stays\n * square so it always meets the clipped track edge flush\n * - **Animation**: Width transition (300ms linear) for smooth progress updates\n * - **Variants**:\n * - `default`: Primary blue (bg-primary-500)\n * - `success`: Green (bg-success-500)\n * - `error`: Red (bg-destructive)\n *\n * ## Accessibility\n *\n * - Uses `role=\"progressbar\"` for screen readers\n * - Includes `aria-valuenow`, `aria-valuemin`, `aria-valuemax` attributes\n * - Includes `aria-label` for context (e.g., \"Upload progress: 45%\")\n *\n * ## Usage Examples\n *\n * ### Basic usage\n * ```tsx\n * <Progress value={45} />\n * ```\n *\n * ### Success state\n * ```tsx\n * <Progress value={100} variant=\"success\" />\n * ```\n *\n * ### Error state\n * ```tsx\n * <Progress value={30} variant=\"error\" />\n * ```\n *\n * ### With custom label\n * ```tsx\n * <Progress\n * value={progress}\n * aria-label={`Uploading ${filename}: ${progress}%`}\n * />\n * ```\n *\n * @see ui-revamp/media-library-design-spec.md - Progress component specification\n */\n\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * Progress variants using CVA\n *\n * Defines color variants for different progress states.\n *\n * @experimental\n */\n// Square corners: the capsule track clips the trailing edge already, so a radius\n// here would only round the leading edge, tapering low percentages into a sliver\n// narrower than the value they represent.\nexport const progressVariants = cva(\"h-full rounded-none transition-all\", {\n variants: {\n variant: {\n default: \"bg-primary-500\",\n success: \"bg-success-500\",\n error: \"bg-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n});\n\n/**\n * Progress component props\n * @experimental\n */\nexport type ProgressProps = {\n /**\n * Current progress value (0-100)\n *\n * @example\n * ```tsx\n * <Progress value={45} /> // 45% progress\n * ```\n */\n value: number;\n\n /**\n * Maximum value (default: 100)\n *\n * @example\n * ```tsx\n * <Progress value={30} max={50} /> // 60% progress (30/50)\n * ```\n */\n max?: number;\n\n /**\n * Visual variant for different states\n *\n * - `default`: Primary blue (bg-primary-500)\n * - `success`: Green (bg-success-500)\n * - `error`: Red (bg-destructive)\n *\n * @default \"default\"\n */\n variant?: VariantProps<typeof progressVariants>[\"variant\"];\n\n /**\n * Optional CSS class name for custom styling\n */\n className?: string;\n\n /**\n * Optional ARIA label for screen readers\n *\n * If not provided, defaults to \"Progress: X%\"\n *\n * @example\n * ```tsx\n * <Progress value={45} aria-label=\"Uploading image.jpg: 45%\" />\n * ```\n */\n \"aria-label\"?: string;\n} & React.HTMLAttributes<HTMLDivElement>;\n\n/**\n * Progress component\n *\n * Displays a horizontal progress bar with smooth animations and variant support.\n *\n * @param props - Progress component props\n * @returns Progress bar component\n *\n * @example\n * ```tsx\n * function FileUpload() {\n * const [progress, setProgress] = React.useState(0);\n *\n * return (\n * <div>\n * <p>Uploading file...</p>\n * <Progress value={progress} aria-label={`Upload progress: ${progress}%`} />\n * </div>\n * );\n * }\n * ```\n * @experimental\n */\nconst Progress = React.forwardRef<HTMLDivElement, ProgressProps>(\n (\n {\n value,\n max = 100,\n variant = \"default\",\n className,\n \"aria-label\": ariaLabel,\n ...props\n },\n ref\n ) => {\n // Clamp value between 0 and max\n const clampedValue = Math.min(Math.max(0, value), max);\n const percentage = (clampedValue / max) * 100;\n\n return (\n <div\n ref={ref}\n role=\"progressbar\"\n aria-valuenow={clampedValue}\n aria-valuemin={0}\n aria-valuemax={max}\n aria-label={ariaLabel || `Progress: ${Math.round(percentage)}%`}\n className={cn(\n \"relative h-2 w-full overflow-hidden rounded-full bg-accent\",\n className\n )}\n {...props}\n >\n <div\n className={cn(progressVariants({ variant }))}\n style={{\n width: `${percentage}%`,\n transition: \"width 300ms linear\",\n }}\n />\n </div>\n );\n }\n);\n\nProgress.displayName = \"Progress\";\n\nexport { Progress };\n","import * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport { Check, Minus } from \"lucide-react\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** @public */\nconst Checkbox = forwardRef<\n ElementRef<typeof CheckboxPrimitive.Root>,\n ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root> & {\n indeterminate?: boolean;\n }\n>(({ className, indeterminate, ...props }, ref) => (\n <CheckboxPrimitive.Root\n ref={ref}\n data-slot=\"checkbox\"\n className={cn(\n // Resting border uses border-control-border, NOT border-input. An\n // unchecked box has no label, value or focus ring to identify it -- the\n // border is the whole control -- so it is held to 1.4.11's 3:1, which\n // border-input deliberately no longer meets. The checked state switches\n // to border-primary below, keeping the two states distinct.\n \"peer relative h-4 w-4 shrink-0 rounded-sm border border-control-border ring-offset-background before:absolute before:left-1/2 before:top-1/2 before:h-6 before:w-6 before:-translate-x-1/2 before:-translate-y-1/2 before:content-[''] focus:border-primary! focus-visible:border-primary! focus:outline-none focus-visible:outline-none aria-invalid:border-destructive aria-invalid:focus:border-destructive! aria-invalid:focus-visible:border-destructive! disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground data-[state=indeterminate]:border-primary transition-all duration-200\",\n className\n )}\n {...props}\n >\n <CheckboxPrimitive.Indicator\n className={cn(\"flex items-center justify-center text-current\")}\n >\n {indeterminate ? (\n <Minus className=\"h-3 w-3\" />\n ) : (\n <Check className=\"h-3 w-3\" />\n )}\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n));\n\nCheckbox.displayName = \"Checkbox\";\n\nexport { Checkbox };\n","import * as RadioGroupPrimitive from \"@radix-ui/react-radio-group\";\nimport type { ElementRef, ComponentPropsWithoutRef } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * RadioGroup Component - Design System Specification\n *\n * Radio buttons allow users to select a single option from a set of mutually\n * exclusive options. They should be used when only one selection is allowed.\n *\n * Accessibility:\n * - Full keyboard navigation support (Arrow keys, Tab, Space)\n * - Proper ARIA attributes provided by Radix UI\n * - Focus indicators for keyboard users\n * - Disabled state support\n *\n * Design Specs:\n * - Size: 16px (h-4 w-4) - Fixed size matching Checkbox\n * - Border: 1px solid, expands to 5px when checked (visual indicator)\n * - Border radius: `rounded-full`. Round means \"pick one\" and square means\n * \"pick many\"; a square radio would announce the wrong behaviour, so the\n * shape is fixed and deliberately outside the `--radius` scale. Checkbox\n * keeps the derived radius for the same reason.\n * - Transition: 150ms (consistent with design system)\n * - Focus ring: 2px ring with 2px offset\n *\n * Implementation Notes:\n * - Uses Radix UI primitives for robust accessibility\n * - Visual \"checked\" state achieved via border border-border expansion (border-[5px])\n * - No inner indicator needed - border border-border expansion provides clear visual feedback\n * - Hover state changes border border-border color for better interactivity\n * @public\n */\nconst RadioGroup = forwardRef<\n ElementRef<typeof RadioGroupPrimitive.Root>,\n ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>\n>(({ className, ...props }, ref) => {\n return (\n <RadioGroupPrimitive.Root\n className={cn(\"grid gap-2\", className)}\n {...props}\n ref={ref}\n data-slot=\"radio-group\"\n />\n );\n});\n\nRadioGroup.displayName = \"RadioGroup\";\n\n/** @public */\nconst RadioGroupItem = forwardRef<\n ElementRef<typeof RadioGroupPrimitive.Item>,\n ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>\n>(({ className, ...props }, ref) => {\n return (\n <RadioGroupPrimitive.Item\n ref={ref}\n data-slot=\"radio-group-item\"\n className={cn(\n // Unchecked outline uses primary/40 (clearly visible) instead of primary/5\n // (~5% opacity, effectively invisible); hover strengthens above the resting state.\n // Resting border uses border-control-border, NOT border-input. An\n // unchecked radio is only its ring, with nothing else to identify it,\n // so it is held to 1.4.11's 3:1 -- which border-input deliberately no\n // longer meets. The checked state switches to border-primary below.\n // rounded-full is fixed rather than derived from --radius: the circle is\n // what tells the user only one option can be chosen. The thick checked\n // border leaves a background-coloured core, and because the border's\n // inner edge is curved too that core reads as a round dot.\n \"peer h-4 w-4 shrink-0 rounded-full border border-control-border bg-background cursor-pointer transition-all duration-150 focus:border-primary! focus-visible:border-primary! focus:outline-none focus-visible:outline-none aria-invalid:border-destructive aria-invalid:focus:border-destructive! aria-invalid:focus-visible:border-destructive! disabled:cursor-not-allowed disabled:opacity-50 hover:border-primary/70 data-[state=checked]:border-primary data-[state=checked]:border-[5px]\",\n className\n )}\n {...props}\n >\n {/* The indicator carries no marker of its own: the expanded border plus\n the circular background core already render the selected dot. */}\n <RadioGroupPrimitive.Indicator className=\"block size-full rounded-full\" />\n </RadioGroupPrimitive.Item>\n );\n});\n\nRadioGroupItem.displayName = \"RadioGroupItem\";\n\nexport { RadioGroup, RadioGroupItem };\n","\"use client\";\n\nimport {\n Root as SwitchRoot,\n Thumb as SwitchThumb,\n} from \"@radix-ui/react-switch\";\nimport type { ComponentProps } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * A pill track carrying a circular thumb is how a toggle is recognised, so both\n * parts use `rounded-full` and stay outside the `--radius` scale: at any theme\n * radius the switch must still read as a switch and not as a small checkbox.\n * @public\n */\nfunction Switch({ className, ...props }: ComponentProps<typeof SwitchRoot>) {\n return (\n <SwitchRoot\n data-slot=\"switch\"\n className={cn(\n \"peer inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-border transition-all outline-none focus-visible:border-primary aria-invalid:border-destructive aria-invalid:focus-visible:border-destructive! disabled:cursor-not-allowed disabled:opacity-50\",\n \"data-[state=checked]:bg-primary data-[state=checked]:border-primary!\",\n // An unchecked switch is a track and a thumb and nothing else -- no\n // label inside it, no value, no glyph -- so 1.4.11 applies to both the\n // track against the page and the thumb against the track. `bg-input`\n // cannot serve here: it is the FIELD border weight, deliberately below\n // the minimum, and at that value the pill and its thumb both vanish\n // into a light page. The control token is the same answer used for the\n // checkbox and radio boundary, for the same reason.\n // At full strength in both modes. A `/80` here read as a softening of\n // the dark track and was in fact a removal of the guarantee the token\n // carries: composited over the surfaces the switch renders on it\n // measures 3.02 on the page, 2.94 on a card, 2.85 on a popover or the\n // sidebar and 2.65 on muted, so three of the four fall under the 3:1\n // this token exists to hold. Opaque, the same four are 4.23, 4.01,\n // 3.79 and 3.40.\n \"data-[state=unchecked]:bg-control-border data-[state=unchecked]:border-control-border\",\n className\n )}\n {...props}\n >\n <SwitchThumb\n data-slot=\"switch-thumb\"\n className={cn(\n \"bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0\"\n )}\n />\n </SwitchRoot>\n );\n}\n\nexport { Switch };\n","import * as CollapsiblePrimitive from \"@radix-ui/react-collapsible\";\n\n/** @experimental */\nconst Collapsible = CollapsiblePrimitive.Root;\n\n/** @experimental */\nconst CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;\n\n/** @experimental */\nconst CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;\n\nexport { Collapsible, CollapsibleTrigger, CollapsibleContent };\n","\"use client\";\n\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\";\nimport { ChevronDown } from \"lucide-react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport type {\n AccordionItemProps,\n AccordionItemRef,\n AccordionTriggerProps,\n AccordionTriggerRef,\n AccordionContentProps,\n AccordionContentRef,\n} from \"../types/accordion\";\n\n/**\n * Accordion Component - Design System Specification\n *\n * A vertically stacked set of interactive headings that each reveal a section of content.\n * Built on Radix UI primitives with WAI-ARIA compliance.\n *\n * Design Specs:\n * - AccordionItem border: 1px bottom border border-border (border-b)\n * - AccordionTrigger padding: 16px vertical (py-4)\n * - AccordionTrigger font: font-medium (500 weight)\n * - AccordionContent padding: 16px bottom, 0 top (pb-4 pt-0)\n * - Icon size: 16×16px (h-4 w-4)\n * - Icon rotation: 180° when expanded\n * - Transition duration: 150ms (design system standard)\n *\n * Structure:\n * <Accordion type=\"single\" collapsible>\n * <AccordionItem value=\"item-1\">\n * <AccordionTrigger>Is it accessible?</AccordionTrigger>\n * <AccordionContent>\n * Yes. It adheres to the WAI-ARIA design pattern.\n * </AccordionContent>\n * </AccordionItem>\n * </Accordion>\n *\n * Accessibility:\n * - Full keyboard navigation (Arrow keys, Home, End, Space, Enter)\n * - ARIA attributes automatically applied by Radix UI\n * - aria-expanded indicates open/closed state\n * - aria-controls associates trigger with content\n * - aria-labelledby provides context to assistive technologies\n * - role=\"region\" on content panels\n * - Focus indicators visible (Tailwind default focus-visible)\n *\n * Features:\n * - Single mode: Only one item can be open at a time (type=\"single\")\n * - Multiple mode: Multiple items can be open (type=\"multiple\")\n * - Collapsible: Items can be collapsed when clicked again (collapsible prop)\n * - Disabled state support (disabled prop on items)\n * - Controlled/uncontrolled modes (value/defaultValue)\n * - Smooth height animations (data-state animations)\n *\n * Usage Examples:\n *\n * Basic accordion (single mode):\n * ```tsx\n * <Accordion type=\"single\" collapsible>\n * <AccordionItem value=\"item-1\">\n * <AccordionTrigger>Is it accessible?</AccordionTrigger>\n * <AccordionContent>\n * Yes. It adheres to the WAI-ARIA design pattern.\n * </AccordionContent>\n * </AccordionItem>\n * <AccordionItem value=\"item-2\">\n * <AccordionTrigger>Is it styled?</AccordionTrigger>\n * <AccordionContent>\n * Yes. It comes with default styles that match the design system.\n * </AccordionContent>\n * </AccordionItem>\n * </Accordion>\n * ```\n *\n * Multiple items open (multiple mode):\n * ```tsx\n * <Accordion type=\"multiple\">\n * <AccordionItem value=\"item-1\">\n * <AccordionTrigger>Section 1</AccordionTrigger>\n * <AccordionContent>Content 1</AccordionContent>\n * </AccordionItem>\n * <AccordionItem value=\"item-2\">\n * <AccordionTrigger>Section 2</AccordionTrigger>\n * <AccordionContent>Content 2</AccordionContent>\n * </AccordionItem>\n * </Accordion>\n * ```\n *\n * Controlled accordion:\n * ```tsx\n * const [value, setValue] = useState(\"item-1\");\n * <Accordion type=\"single\" value={value} onValueChange={setValue}>\n * <AccordionItem value=\"item-1\">\n * <AccordionTrigger>Item 1</AccordionTrigger>\n * <AccordionContent>Content 1</AccordionContent>\n * </AccordionItem>\n * <AccordionItem value=\"item-2\">\n * <AccordionTrigger>Item 2</AccordionTrigger>\n * <AccordionContent>Content 2</AccordionContent>\n * </AccordionItem>\n * </Accordion>\n * ```\n *\n * @see https://www.radix-ui.com/primitives/docs/components/accordion\n * @experimental\n */\nconst Accordion = AccordionPrimitive.Root;\n\n/**\n * AccordionItem - Container for trigger and content\n *\n * Design Specs:\n * - Border: 1px bottom border border-border (border-b) for visual separation\n * - Each item represents a collapsible section\n *\n * Accessibility:\n * - Each item requires a unique value prop for identification\n * - Disabled state can be set via disabled prop\n * @experimental\n */\nconst AccordionItem = forwardRef<AccordionItemRef, AccordionItemProps>(\n ({ className, ...props }, ref) => (\n <AccordionPrimitive.Item\n ref={ref}\n data-slot=\"accordion-item\"\n className={cn(\"border-b\", className)}\n {...props}\n />\n )\n);\nAccordionItem.displayName = \"AccordionItem\";\n\n/**\n * AccordionTrigger - Clickable header button that toggles content visibility\n *\n * Design Specs:\n * - Padding: 16px vertical (py-4) for adequate touch target\n * - Font: font-medium (500 weight) for emphasis\n * - Hover: underline text on hover for better feedback\n * - Icon: ChevronDown (16×16px) with 180° rotation when expanded\n * - Transition: 150ms (design system standard)\n * - Layout: flex with space-between for trigger text and icon\n *\n * Accessibility:\n * - Button element with proper ARIA attributes\n * - aria-expanded indicates open/closed state\n * - aria-controls associates trigger with content panel\n * - Keyboard: Space/Enter to toggle, Arrow keys to navigate\n * - Focus indicator visible via default focus-visible styles\n *\n * Note:\n * - The ChevronDown icon is included by default\n * - Icon rotates 180° when item is expanded ([data-state=open])\n * - Trigger includes AccordionPrimitive.Header wrapper for proper semantics\n * @experimental\n */\nconst AccordionTrigger = forwardRef<AccordionTriggerRef, AccordionTriggerProps>(\n ({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Header className=\"flex\" data-slot=\"accordion-header\">\n <AccordionPrimitive.Trigger\n ref={ref}\n data-slot=\"accordion-trigger\"\n className={cn(\n \"flex flex-1 items-center justify-between py-4 font-medium transition-all duration-150 hover:underline [&[data-state=open]>svg]:rotate-180\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronDown className=\"h-4 w-4 shrink-0 transition-transform duration-150 will-change-transform\" />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n )\n);\nAccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;\n\n/**\n * AccordionContent - Collapsible content panel\n *\n * Design Specs:\n * - Padding: 16px bottom, 0 top (pb-4 pt-0) for proper spacing\n * - Font: text-sm (14px) for body content\n * - Animation: Smooth height transition via data-state animations\n * - Overflow: hidden during animation for smooth reveal\n *\n * Accessibility:\n * - role=\"region\" for screen reader context\n * - aria-labelledby associates content with trigger\n * - Only visible when item is expanded (data-state=\"open\")\n * - Content is hidden but still in DOM when collapsed\n *\n * Animations:\n * - data-state=\"open\": animate-accordion-down (Tailwind built-in)\n * - data-state=\"closed\": animate-accordion-up (Tailwind built-in)\n * - Height transitions smoothly from 0 to auto\n * @experimental\n */\nconst AccordionContent = forwardRef<AccordionContentRef, AccordionContentProps>(\n ({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Content\n ref={ref}\n data-slot=\"accordion-content\"\n className=\"overflow-hidden text-sm transition-all will-change-[height] transform-[translateZ(0)] data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down\"\n {...props}\n >\n <div className={cn(\"pb-4 pt-0\", className)}>{children}</div>\n </AccordionPrimitive.Content>\n )\n);\n\nAccordionContent.displayName = AccordionPrimitive.Content.displayName;\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\nexport type {\n AccordionProps,\n AccordionItemProps,\n AccordionTriggerProps,\n AccordionContentProps,\n} from \"../types/accordion\";\n","\"use client\";\n\nimport {\n Root as AvatarRoot,\n Image as AvatarImagePrimitive,\n Fallback as AvatarFallbackPrimitive,\n} from \"@radix-ui/react-avatar\";\nimport { cva } from \"class-variance-authority\";\nimport { createContext, forwardRef, useContext } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport type {\n AvatarFallbackProps,\n AvatarImageProps,\n AvatarProps,\n} from \"../types/avatar\";\n\n/**\n * Avatar Component - Design System Specification\n *\n * Displays user avatars with image and fallback support. Built on Radix UI\n * primitives for robust image loading and fallback handling.\n *\n * **Component Structure**:\n * - `Avatar`: Root container with size variants\n * - `AvatarImage`: Image element with src/alt attributes\n * - `AvatarFallback`: Fallback content (typically initials) when image fails\n *\n * **Sizes**:\n * - sm: 32px (h-8 w-8) - For compact layouts, table rows, lists\n * - md: 40px (h-10 w-10) - Default size, general use\n * - lg: 48px (h-12 w-12) - For prominent displays, profile pages\n * - xl: 64px (h-16 w-16) - For large profile displays, user panels\n * - 2xl: 80px (h-20 w-20) - For profile headers, large avatars\n *\n * **Design Specs**:\n * - Border radius: `rounded-full`. A person's avatar is read as a circle, so it\n * sits outside the `--radius` scale and stays circular at any theme radius.\n * Non-identity content (media thumbnails) overrides back to a scale step.\n * - Background: bg-accent (slate-100 light, slate-800 dark)\n * - Text color: text-accent-foreground (slate-900 light, slate-100 dark)\n * - Fallback text scales with avatar size (text-xs to text-2xl)\n *\n * **Accessibility**:\n * - Always provide `alt` text on AvatarImage for screen readers\n * - Use meaningful fallback text (user initials, not decorative)\n * - Built on Radix UI with WAI-ARIA compliance\n * - Image loading handled gracefully with fallback\n *\n * @example\n * // With image\n * <Avatar size=\"md\">\n * <AvatarImage src=\"/user.jpg\" alt=\"John Doe\" />\n * <AvatarFallback>JD</AvatarFallback>\n * </Avatar>\n *\n * @example\n * // Fallback only (no image)\n * <Avatar size=\"lg\">\n * <AvatarFallback>AB</AvatarFallback>\n * </Avatar>\n *\n * @example\n * // Small size for lists\n * <Avatar size=\"sm\">\n * <AvatarImage src=\"/avatar.jpg\" alt=\"User\" />\n * <AvatarFallback>U</AvatarFallback>\n * </Avatar>\n *\n * @example\n * // Extra large for profile headers\n * <Avatar size=\"2xl\">\n * <AvatarImage src=\"/profile.jpg\" alt=\"User Name\" />\n * <AvatarFallback>UN</AvatarFallback>\n * </Avatar>\n *\n * @see {@link https://www.radix-ui.com/primitives/docs/components/avatar Radix UI Avatar}\n * @see {@link https://github.com/nextlyhq/nextly/blob/main/ui-revamp/04-design-system-specification.md Design System Specification}\n * @experimental\n */\nexport const avatarVariants = cva(\n \"relative inline-flex shrink-0 overflow-hidden rounded-full items-center justify-center bg-primary/5 text-muted-foreground\",\n {\n variants: {\n size: {\n sm: \"h-8 w-8\",\n md: \"h-10 w-10\",\n lg: \"h-12 w-12\",\n xl: \"h-16 w-16\",\n \"2xl\": \"h-20 w-20\",\n },\n },\n defaultVariants: {\n size: \"md\",\n },\n }\n);\n\n/**\n * Text size mapping for AvatarFallback based on Avatar size\n * Uses React Context to reliably pass size from Avatar to AvatarFallback\n */\nconst fallbackTextSizeMap = {\n sm: \"text-xs\", // 12px for 32px avatar\n md: \"text-sm\", // 14px for 40px avatar\n lg: \"text-base\", // 16px for 48px avatar\n xl: \"text-lg\", // 18px for 64px avatar\n \"2xl\": \"text-2xl\", // 24px for 80px avatar\n} as const;\n\n/**\n * Context to pass size from Avatar to AvatarFallback\n * This ensures text scaling works reliably regardless of className overrides\n */\nconst AvatarSizeContext = createContext<AvatarProps[\"size\"]>(\"md\");\n\n/**\n * Avatar root component\n *\n * Container element for avatar image and fallback. Provides consistent sizing\n * and styling across the application. Uses React Context to pass size to\n * AvatarFallback for reliable text scaling.\n * @experimental\n */\nconst Avatar = forwardRef<HTMLSpanElement, AvatarProps>(\n ({ className, size = \"md\", ...props }, ref) => {\n return (\n <AvatarSizeContext.Provider value={size}>\n <AvatarRoot\n ref={ref}\n data-slot=\"avatar\"\n className={cn(avatarVariants({ size }), className)}\n {...props}\n />\n </AvatarSizeContext.Provider>\n );\n }\n);\nAvatar.displayName = \"Avatar\";\n\n/**\n * AvatarImage component\n *\n * Displays the user's profile image. Falls back to AvatarFallback if image\n * fails to load or src is not provided.\n *\n * **Best Practices**:\n * - Always provide meaningful `alt` text (user's name, not \"avatar\" or \"profile picture\")\n * - Use optimized images (WebP, AVIF) for better performance\n * - Consider lazy loading for images below the fold\n *\n * @example\n * <AvatarImage src=\"/users/john-doe.jpg\" alt=\"John Doe\" />\n * @experimental\n */\nconst AvatarImage = forwardRef<HTMLImageElement, AvatarImageProps>(\n ({ className, ...props }, ref) => {\n return (\n <AvatarImagePrimitive\n ref={ref}\n data-slot=\"avatar-image\"\n className={cn(\"aspect-square size-full\", className)}\n {...props}\n />\n );\n }\n);\nAvatarImage.displayName = \"AvatarImage\";\n\n/**\n * AvatarFallback component\n *\n * Displays fallback content when image is not available or fails to load.\n * Typically shows user initials (1-2 characters). Text size automatically\n * scales based on the Avatar size using React Context.\n *\n * **Best Practices**:\n * - Use 1-2 uppercase characters (user initials: \"JD\", \"AB\")\n * - Keep text concise and meaningful\n * - Don't use decorative text (\"?\", \"NA\") - use initials or icon instead\n *\n * **Text Sizing** (scales with avatar size via Context):\n * - sm (32px): text-xs (12px)\n * - md (40px): text-sm (14px)\n * - lg (48px): text-base (16px)\n * - xl (64px): text-lg (18px)\n * - 2xl (80px): text-2xl (24px)\n *\n * @example\n * // User initials\n * <AvatarFallback>JD</AvatarFallback>\n *\n * @example\n * // Single character for compact layouts\n * <AvatarFallback>J</AvatarFallback>\n *\n * @example\n * // Custom delay before showing fallback\n * <AvatarFallback delayMs={300}>AB</AvatarFallback>\n * @experimental\n */\nconst AvatarFallback = forwardRef<HTMLSpanElement, AvatarFallbackProps>(\n ({ className, children, ...props }, ref) => {\n const size = useContext(AvatarSizeContext) || \"md\";\n const textSize = fallbackTextSizeMap[size];\n\n return (\n <AvatarFallbackPrimitive\n ref={ref}\n data-slot=\"avatar-fallback\"\n className={cn(\n \"bg-primary/5 text-muted-foreground flex size-full items-center justify-center rounded-full font-medium\",\n textSize,\n className\n )}\n {...props}\n >\n {children}\n </AvatarFallbackPrimitive>\n );\n }\n);\nAvatarFallback.displayName = \"AvatarFallback\";\n\nexport { Avatar, AvatarImage, AvatarFallback };\n","\"use client\";\n\nimport { Root, List, Trigger, Content } from \"@radix-ui/react-tabs\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { forwardRef, type ComponentPropsWithoutRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport type {\n TabsListProps as TabsListBaseProps,\n TabsListRef,\n TabsTriggerProps as TabsTriggerBaseProps,\n TabsTriggerRef,\n TabsContentProps,\n TabsContentRef,\n} from \"../types/tabs\";\n\n/**\n * Tabs Component - Design System Specification\n *\n * A set of layered sections of content—known as tab panels—that are displayed one at a time.\n * Built on Radix UI primitives with WAI-ARIA compliance.\n *\n * Design Specs:\n * - TabsList border-radius: square, independent of `--radius`\n * - TabsTrigger border-radius: square, independent of `--radius`; the active\n * state is a 2px bottom border that has to stay flush with the tab edges\n * - TabsList height: 40px (h-10)\n * - TabsTrigger padding: 12px 24px (px-3 py-1.5)\n * - Transition duration: 150ms (design system standard)\n * - Active state: bg-background with subtle shadow\n *\n * Structure:\n * <Tabs defaultValue=\"tab1\">\n * <TabsList>\n * <TabsTrigger value=\"tab1\">Tab 1</TabsTrigger>\n * <TabsTrigger value=\"tab2\">Tab 2</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"tab1\">Content 1</TabsContent>\n * <TabsContent value=\"tab2\">Content 2</TabsContent>\n * </Tabs>\n *\n * Accessibility:\n * - Full keyboard navigation (Arrow keys, Home, End, Tab)\n * - ARIA attributes automatically applied by Radix UI\n * - Focus indicators with 2px ring (WCAG 2.2 compliant)\n * - Disabled state support\n *\n * Features:\n * - Controlled/uncontrolled modes (value/defaultValue)\n * - Horizontal/vertical orientation support\n * - Automatic/manual activation modes\n * - Keyboard navigation built-in\n *\n * Usage Examples:\n *\n * Basic tabs:\n * ```tsx\n * <Tabs defaultValue=\"overview\">\n * <TabsList>\n * <TabsTrigger value=\"overview\">Overview</TabsTrigger>\n * <TabsTrigger value=\"details\">Details</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"overview\">Overview content</TabsContent>\n * <TabsContent value=\"details\">Details content</TabsContent>\n * </Tabs>\n * ```\n *\n * Controlled tabs:\n * ```tsx\n * const [activeTab, setActiveTab] = useState(\"tab1\");\n * <Tabs value={activeTab} onValueChange={setActiveTab}>\n * <TabsList>\n * <TabsTrigger value=\"tab1\">Tab 1</TabsTrigger>\n * <TabsTrigger value=\"tab2\">Tab 2</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"tab1\">Content 1</TabsContent>\n * <TabsContent value=\"tab2\">Content 2</TabsContent>\n * </Tabs>\n * ```\n *\n * Vertical tabs:\n * ```tsx\n * <Tabs defaultValue=\"tab1\" orientation=\"vertical\">\n * <TabsList>\n * <TabsTrigger value=\"tab1\">Tab 1</TabsTrigger>\n * <TabsTrigger value=\"tab2\">Tab 2</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"tab1\">Content 1</TabsContent>\n * <TabsContent value=\"tab2\">Content 2</TabsContent>\n * </Tabs>\n * ```\n *\n * @see https://www.radix-ui.com/primitives/docs/components/tabs\n * @public\n */\nconst Tabs = Root;\n\n/**\n * The list's own appearance, as variants rather than as classes each caller\n * repeats.\n *\n * `ghost` is the compact, surface-less list used where tabs sit inside another\n * panel and must not draw a bar of their own. It was spelled `h-8 bg-transparent\n * p-0` at one call site and `h-7 bg-transparent p-0` at another; naming it here\n * settles the height rather than leaving two answers in the tree.\n *\n * Only APPEARANCE is promoted. Layout a caller chooses -- `w-full`,\n * `justify-start`, margins -- stays on `className`, because a variant names a\n * decision this component owns and layout is the caller's.\n *\n * Horizontal SCROLLING is the exception, and it moved to the `scrollable` prop\n * for a reason rather than as tidying: a caller putting `overflow-x-auto` on the\n * list makes the list itself the scroll container, which breaks the rail\n * contract this file's other half depends on. See that prop.\n *\n * The arms are a named declaration rather than an object literal inside `cva`,\n * because `cva` does not expose its configuration on the function it returns —\n * so anything checking which arms exist would otherwise have to restate them,\n * and the two drift the moment an arm is added.\n */\nconst TABS_LIST_VARIANTS = {\n default: \"h-10\",\n ghost: \"h-8 bg-transparent\",\n} as const;\n\nconst tabsListVariants = cva(\n // Square corners: underline tabs, so the list never draws a rounded surface.\n // `gap-1` and `p-0` are invariant across the variants, so they belong here —\n // repeating them in each arm gives any future adjustment two sites to change\n // and one to forget.\n //\n // The rail the triggers sit on, and it is load-bearing rather than\n // decoration. Each trigger draws a 2px border on its trailing edge and pulls\n // itself half a step onto this one: with no rail here, that pull put a 2px\n // line onto whatever followed the strip in the document, and above a rounded\n // panel that is the corner curve — a straight bar crossing an 8px arc. The\n // rail also gives an inactive tab somewhere to be inactive, which is what\n // makes the active one read as selected rather than as the only tab.\n //\n // Which edge is the trailing one depends on orientation, so the rail follows\n // it. Radix stamps `data-orientation` on the list and on every trigger, so\n // both halves read the same source and cannot disagree about the axis. A\n // fixed bottom rail draws a horizontal line beneath a vertical list.\n \"inline-flex items-center justify-center gap-1 rounded-none border-b border-border p-0 text-muted-foreground data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch data-[orientation=vertical]:border-b-0 data-[orientation=vertical]:border-r\",\n {\n variants: { variant: TABS_LIST_VARIANTS },\n defaultVariants: { variant: \"default\" },\n }\n);\n\n/**\n * TabsList - Container for tab triggers\n *\n * Design Specs:\n * - Height: 40px (h-10)\n * - Border-radius: none (for underline style)\n * - Background: transparent\n * - Layout: inline-flex (horizontal by default, use orientation=\"vertical\" on Tabs root for vertical)\n * @public\n */\nconst TabsList = forwardRef<\n TabsListRef,\n TabsListBaseProps &\n VariantProps<typeof tabsListVariants> & {\n /**\n * Let a strip too wide for its container scroll sideways.\n *\n * The scroll container is a WRAPPER, never the list, and that is why this\n * prop exists rather than callers reaching for `overflow-x-auto`\n * themselves. Two things go wrong when the list is the scroller, and the\n * second is why the obvious remedy is also wrong:\n *\n * - Per the CSS overflow rules, `visible` computes to `auto` when the\n * other axis is neither `visible` nor `clip`, so `overflow-x` alone\n * always makes the element a VERTICAL scroll container too.\n * - `TabsTrigger` carries `-mb-0.5` so its 2px underline lands ON this\n * list's rail rather than below it. That pull-up puts content past the\n * content-box edge, which the new scroll container reports as vertical\n * overflow — so `overflow-y-hidden` would clip the 2px the underline is\n * made of, silencing a scrollbar by deleting the indicator.\n *\n * With the wrapper scrolling instead, the list keeps its rail and\n * `w-max min-w-full` makes that rail span the full scroll width rather\n * than stopping where the triggers do.\n */\n scrollable?: boolean;\n }\n>(({ className, variant, scrollable = false, ...props }, ref) => {\n const list = (\n <List\n ref={ref}\n data-slot=\"tabs-list\"\n className={cn(\n tabsListVariants({ variant }),\n scrollable && \"w-max min-w-full\",\n className\n )}\n {...props}\n />\n );\n\n if (!scrollable) return list;\n\n return (\n <div data-slot=\"tabs-list-scroller\" className=\"w-full overflow-x-auto\">\n {list}\n </div>\n );\n});\nTabsList.displayName = List.displayName;\n\n/**\n * The trigger's own appearance. `size` carries the type scale only: everything\n * that draws the tab -- the square corners, the 2px underline, the active and\n * hover colours, the focus ring -- is in the base and is not a caller's to\n * choose, which is the property `tabs-contract.test.ts` watches for.\n *\n * Arms declared separately for the same reason as the list's.\n */\nconst TABS_TRIGGER_SIZES = {\n default: \"text-sm\",\n sm: \"text-xs\",\n} as const;\n\nconst tabsTriggerVariants = cva(\n // Square corners: the active state is a 2px border on the trailing edge that\n // has to run the full length of the trigger and stay flush with its ends.\n //\n // The active colour is NOT important-marked. Nothing inside this component\n // competes for it — the inactive arm is mutually exclusive with the active\n // one — so the only thing an `!` could win against is a caller's class, which\n // is precisely what a theme supplies. Marking it made the one line under\n // every selected tab the one line a theme could not restyle, and the failure\n // read as \"the theme did not apply here\" rather than as an opt-out.\n //\n // The trailing edge is the bottom when the strip is horizontal and the right\n // when it is vertical, so the indicator, the half-step pull onto the rail and\n // the active colour all switch axis together off the same `data-orientation`\n // the list reads. Switching only some of them puts the selection affordance\n // on one axis and the line it sits on the other.\n \"inline-flex items-center justify-center whitespace-nowrap rounded-none bg-transparent px-4 py-2 font-medium cursor-pointer transition-all duration-200 border-b-2 relative -mb-0.5 data-[state=active]:border-b-primary data-[state=active]:text-primary data-[state=inactive]:border-transparent data-[state=inactive]:text-muted-foreground hover:text-primary hover:border-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed data-[orientation=vertical]:border-b-0 data-[orientation=vertical]:mb-0 data-[orientation=vertical]:border-r-2 data-[orientation=vertical]:-mr-0.5 data-[orientation=vertical]:data-[state=active]:border-r-primary\",\n {\n variants: { size: TABS_TRIGGER_SIZES },\n defaultVariants: { size: \"default\" },\n }\n);\n\n/**\n * TabsTrigger - Clickable tab button\n *\n * Design Specs:\n * - Border-radius: none (Gmail-style underline tabs)\n * - Padding: 6px 16px (px-4 py-2)\n * - Font: text-sm (14px), font-medium (500)\n * - Transition: 150ms (design system standard)\n * - Active state: the accent colour on the text and on the 2px trailing border\n * - Hover: the same accent, so the target reads before it is chosen\n * - Gmail-inspired clean underline style\n *\n * Accessibility:\n * - Keyboard navigation: Arrow keys, Home, End\n * - Focus ring: 2px with offset (WCAG 2.2 compliant)\n * - Disabled state: pointer-events-none, opacity-50\n * - Data attributes: [data-state=\"active|inactive\"], [data-disabled]\n * @public\n */\nconst TabsTrigger = forwardRef<\n TabsTriggerRef,\n TabsTriggerBaseProps & VariantProps<typeof tabsTriggerVariants>\n>(({ className, size, ...props }, ref) => (\n <Trigger\n ref={ref}\n data-slot=\"tabs-trigger\"\n className={cn(tabsTriggerVariants({ size }), className)}\n {...props}\n />\n));\nTabsTrigger.displayName = Trigger.displayName;\n\n/**\n * TabsContent - Content panel for each tab\n *\n * Design Specs:\n * - Margin top: 8px (mt-2) to separate from TabsList\n * - Focus ring: 2px with offset (for keyboard navigation)\n *\n * Accessibility:\n * - Focus indicator when navigating with Tab key\n * - Data attributes: [data-state=\"active|inactive\"], [data-orientation]\n * - Only active content is visible, inactive content is hidden\n * @public\n */\nconst TabsContent = forwardRef<TabsContentRef, TabsContentProps>(\n ({ className, ...props }, ref) => (\n <Content\n ref={ref}\n data-slot=\"tabs-content\"\n className={cn(\n \"mt-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n className\n )}\n {...props}\n />\n )\n);\nTabsContent.displayName = Content.displayName;\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent };\nexport { tabsListVariants, tabsTriggerVariants };\nexport { TABS_LIST_VARIANTS, TABS_TRIGGER_SIZES };\nexport type { TabsProps, TabsContentProps } from \"../types/tabs\";\n\n/**\n * The public prop types, DERIVED from the components rather than restated.\n *\n * `../types/tabs` describes the Radix props alone, so an alias taken from there\n * rejects `variant` and `size` — and a consumer typing a wrapper around\n * `TabsList` would be told the prop it can see in the signature does not exist.\n * Reading the component's own props keeps the two from drifting: a variant\n * added later reaches every consumer without a second edit.\n */\n/**\n * The list's props, including its `variant`.\n * @public\n */\nexport type TabsListProps = ComponentPropsWithoutRef<typeof TabsList>;\n\n/**\n * The trigger's props, including its `size`.\n * @public\n */\nexport type TabsTriggerProps = ComponentPropsWithoutRef<typeof TabsTrigger>;\n","import * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\n\n/** @experimental */\nconst Popover = PopoverPrimitive.Root;\n\n/** @experimental */\nconst PopoverTrigger = PopoverPrimitive.Trigger;\n\n/** @experimental */\nconst PopoverAnchor = PopoverPrimitive.Anchor;\n\n/** @experimental */\nconst PopoverContent = React.forwardRef<\n React.ElementRef<typeof PopoverPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>\n>(({ className, align = \"center\", sideOffset = 4, ...props }, ref) => {\n const portalContainer = usePortalContainer();\n\n return (\n <PopoverPrimitive.Portal container={portalContainer}>\n <PopoverPrimitive.Content\n ref={ref}\n align={align}\n sideOffset={sideOffset}\n data-slot=\"popover-content\"\n className={cn(\n \"z-[100] w-72 rounded-lg border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out 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 origin-[--radix-popover-content-transform-origin]\",\n className\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n );\n});\nPopoverContent.displayName = PopoverPrimitive.Content.displayName;\n\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };\n","import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { X } from \"lucide-react\";\nimport type {\n ElementRef,\n ComponentPropsWithoutRef,\n HTMLAttributes,\n} from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\n\n/**\n * Dialog (Modal) Component\n *\n * A composable dialog component built on Radix UI primitives for creating modal windows.\n * Supports keyboard navigation, focus trapping, and WCAG 2.2 AA accessibility.\n *\n * @example\n * ```tsx\n * <Dialog open={open} onOpenChange={setOpen}>\n * <DialogTrigger asChild>\n * <Button>Open Dialog</Button>\n * </DialogTrigger>\n * <DialogContent size=\"md\">\n * <DialogHeader>\n * <DialogTitle>Edit Profile</DialogTitle>\n * <DialogDescription>\n * Make changes to your profile here. Click save when you're done.\n * </DialogDescription>\n * </DialogHeader>\n * <div className=\"space-y-4\">\n * Your content here\n * </div>\n * <DialogFooter>\n * <Button variant=\"outline\" onClick={() => setOpen(false)}>Cancel</Button>\n * <Button type=\"submit\">Save Changes</Button>\n * </DialogFooter>\n * </DialogContent>\n * </Dialog>\n * ```\n *\n * @design-spec\n * - Border-radius: `rounded-lg`, the container step of the `--radius` scale\n * - Max-width: 512px (default), responsive sizes available\n * - Backdrop: the `--nx-overlay` scrim with blur effect\n * - Padding: 24px (p-6)\n * - Shadow: xl for prominence (elevation level 4)\n * - Transition: 150ms per design system\n * - Z-index: Overlay at z-50, Content at z-51 (ensures content above overlay)\n *\n * @accessibility\n * - Focus is trapped inside dialog when open\n * - Pressing Escape closes the dialog\n * - Focus returns to trigger element on close\n * - Includes ARIA labels and descriptions\n * - Screen reader announcements via role=\"dialog\"\n * - Close button has sr-only text for screen readers\n * @public\n */\n\nconst Dialog = DialogPrimitive.Root;\n\n/** @experimental */\nconst DialogTrigger = DialogPrimitive.Trigger;\n\n/** @experimental */\nconst DialogPortal = DialogPrimitive.Portal;\n\n/** @experimental */\nconst DialogClose = DialogPrimitive.Close;\n\n/** @experimental */\nexport type DialogOverlayProps = ComponentPropsWithoutRef<\n typeof DialogPrimitive.Overlay\n>;\n\n/**\n * DialogOverlay - The backdrop overlay behind the dialog content.\n * Renders the `--nx-overlay` scrim with a blur effect. The opacity is the\n * token's, not a literal: it differs by mode and a host can retheme it.\n * @experimental\n */\nconst DialogOverlay = forwardRef<\n ElementRef<typeof DialogPrimitive.Overlay>,\n DialogOverlayProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n data-slot=\"dialog-overlay\"\n className={cn(\n // A modal scrim, from the `--nx-overlay` token rather than a surface\n // token. A black wash is the point — painting it from `background` would\n // make it a white veil in light mode — but the alpha still has to differ\n // per mode, because what it composites over is white in one and mid-tone\n // in the other.\n \"fixed inset-0 z-50 bg-overlay backdrop-blur-sm transition-opacity duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className\n )}\n {...props}\n />\n));\nDialogOverlay.displayName = DialogPrimitive.Overlay.displayName;\n\n/**\n * Dialog content size variants using CVA.\n *\n * @variant sm - Small dialog (384px / max-w-sm) - confirmations, alerts\n * @variant md - Medium dialog (512px / max-w-lg) - default, standard forms\n * @variant lg - Large dialog (672px / max-w-2xl) - complex forms, data tables\n * @variant xl - Extra large dialog (896px / max-w-4xl) - content editors, media galleries\n * @variant full - Full width with margin (responsive) - fullscreen on mobile\n * @experimental\n */\nconst dialogContentVariants = cva(\"\", {\n variants: {\n size: {\n sm: \"max-w-sm\",\n md: \"max-w-lg\",\n lg: \"max-w-2xl\",\n xl: \"max-w-4xl\",\n full: \"max-w-[calc(100vw-2rem)] sm:max-w-[calc(100vw-4rem)]\",\n },\n },\n defaultVariants: {\n size: \"md\",\n },\n});\n\n/** @public */\nexport type DialogContentProps = ComponentPropsWithoutRef<\n typeof DialogPrimitive.Content\n> &\n VariantProps<typeof dialogContentVariants>;\n\n/**\n * DialogContent - The main dialog content container.\n *\n * @param size - Size variant (sm, md, lg, xl, full). Default: md (512px)\n *\n * @example\n * ```tsx\n * <DialogContent size=\"lg\">\n * Your content here\n * </DialogContent>\n * ```\n * @public\n */\nconst DialogContent = forwardRef<\n ElementRef<typeof DialogPrimitive.Content>,\n DialogContentProps\n>(({ className, children, size, ...props }, ref) => {\n const portalContainer = usePortalContainer();\n\n return (\n <DialogPortal container={portalContainer}>\n <DialogOverlay />\n <DialogPrimitive.Content\n ref={ref}\n data-slot=\"dialog-content\"\n className={cn(\n \"fixed left-[50%] top-[50%] z-[51] grid w-full translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background p-6 shadow-xl rounded-lg duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out 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%]\",\n dialogContentVariants({ size }),\n className\n )}\n {...props}\n >\n {children}\n <DialogPrimitive.Close\n data-slot=\"dialog-close\"\n className=\"absolute right-4 top-4 rounded-md p-1 text-muted-foreground cursor-pointer transition-colors duration-150 hover-unified focus:outline-none focus:ring-2 focus:ring-ring disabled:pointer-events-none disabled:cursor-not-allowed\"\n >\n <X className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n </DialogPrimitive.Content>\n </DialogPortal>\n );\n});\nDialogContent.displayName = DialogPrimitive.Content.displayName;\n\n/** @public */\nexport type DialogHeaderProps = HTMLAttributes<HTMLDivElement>;\n\n/**\n * DialogHeader - Container for dialog title and description.\n * Provides consistent spacing and alignment (centered on mobile, left-aligned on desktop).\n * @public\n */\nconst DialogHeader = forwardRef<HTMLDivElement, DialogHeaderProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n \"flex flex-col space-y-1.5 text-center sm:text-left\",\n className\n )}\n {...props}\n />\n )\n);\nDialogHeader.displayName = \"DialogHeader\";\n\n/** @public */\nexport type DialogFooterProps = HTMLAttributes<HTMLDivElement>;\n\n/**\n * DialogFooter - Container for dialog action buttons.\n * Provides consistent spacing and alignment (vertical on mobile, horizontal on desktop).\n *\n * @example\n * ```tsx\n * <DialogFooter>\n * <Button variant=\"outline\" onClick={onCancel}>Cancel</Button>\n * <Button type=\"submit\">Save Changes</Button>\n * </DialogFooter>\n * ```\n * @public\n */\nconst DialogFooter = forwardRef<HTMLDivElement, DialogFooterProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\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 )\n);\nDialogFooter.displayName = \"DialogFooter\";\n\n/** @public */\nexport type DialogTitleProps = ComponentPropsWithoutRef<\n typeof DialogPrimitive.Title\n>;\n\n/**\n * DialogTitle - The title of the dialog.\n * Uses text-lg (18px) with semibold weight per design system.\n *\n * @accessibility Required for screen readers. Always include a DialogTitle.\n * @public\n */\nconst DialogTitle = forwardRef<\n ElementRef<typeof DialogPrimitive.Title>,\n DialogTitleProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\n \"text-lg font-semibold leading-none tracking-tight text-foreground\",\n className\n )}\n {...props}\n />\n));\nDialogTitle.displayName = DialogPrimitive.Title.displayName;\n\n/** @public */\nexport type DialogDescriptionProps = ComponentPropsWithoutRef<\n typeof DialogPrimitive.Description\n>;\n\n/**\n * DialogDescription - The description text of the dialog.\n * Uses text-sm (14px) with muted color per design system.\n *\n * @accessibility Provides additional context for screen readers.\n * If not needed visually, you can use sr-only class.\n * @public\n */\nconst DialogDescription = forwardRef<\n ElementRef<typeof DialogPrimitive.Description>,\n DialogDescriptionProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nDialogDescription.displayName = DialogPrimitive.Description.displayName;\n\nexport {\n Dialog,\n DialogPortal,\n DialogOverlay,\n DialogClose,\n DialogTrigger,\n DialogContent,\n DialogHeader,\n DialogFooter,\n DialogTitle,\n DialogDescription,\n dialogContentVariants,\n};\n","/**\n * AlertDialog Component\n *\n * A modal dialog for important confirmations that require user acknowledgment.\n * Built on Radix UI primitives, designed for destructive actions like deletions.\n *\n * @example\n * ```tsx\n * <AlertDialog open={open} onOpenChange={setOpen}>\n * <AlertDialogTrigger asChild>\n * <Button variant=\"destructive\">Delete</Button>\n * </AlertDialogTrigger>\n * <AlertDialogContent>\n * <AlertDialogHeader>\n * <AlertDialogTitle>Are you sure?</AlertDialogTitle>\n * <AlertDialogDescription>\n * This action cannot be undone.\n * </AlertDialogDescription>\n * </AlertDialogHeader>\n * <AlertDialogFooter>\n * <AlertDialogCancel>Cancel</AlertDialogCancel>\n * <AlertDialogAction onClick={handleDelete}>Delete</AlertDialogAction>\n * </AlertDialogFooter>\n * </AlertDialogContent>\n * </AlertDialog>\n * ```\n *\n * @design-spec\n * - Border-radius: `rounded-lg`, the container step of the `--radius` scale\n * - Max-width: 512px (default)\n * - Backdrop: the `--nx-overlay` scrim with blur effect\n * - Padding: 24px (p-6)\n * - Shadow: xl for prominence\n *\n * @accessibility\n * - Focus is trapped inside dialog when open\n * - Pressing Escape closes the dialog\n * - Focus returns to trigger element on close\n * - Screen reader announcements via role=\"alertdialog\"\n */\n\nimport * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\nimport {\n forwardRef,\n type ElementRef,\n type ComponentPropsWithoutRef,\n type HTMLAttributes,\n} from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\n\nimport { buttonVariants } from \"./button\";\n\n/** @experimental */\nconst AlertDialog = AlertDialogPrimitive.Root;\n\n/** @experimental */\nconst AlertDialogTrigger = AlertDialogPrimitive.Trigger;\n\n/** @experimental */\nconst AlertDialogPortal = AlertDialogPrimitive.Portal;\n\n/** @experimental */\nexport type AlertDialogOverlayProps = ComponentPropsWithoutRef<\n typeof AlertDialogPrimitive.Overlay\n>;\n\n/**\n * AlertDialogOverlay - The backdrop overlay behind the dialog content.\n * @experimental\n */\nconst AlertDialogOverlay = forwardRef<\n ElementRef<typeof AlertDialogPrimitive.Overlay>,\n AlertDialogOverlayProps\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Overlay\n ref={ref}\n className={cn(\n // A modal scrim, from the `--nx-overlay` token rather than a surface\n // token. A black wash is the point — painting it from `background` would\n // make it a white veil in light mode — but the alpha still has to differ\n // per mode, because what it composites over is white in one and mid-tone\n // in the other.\n \"fixed inset-0 z-50 bg-overlay backdrop-blur-sm transition-opacity duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className\n )}\n {...props}\n />\n));\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;\n\n/** @experimental */\nexport type AlertDialogContentProps = ComponentPropsWithoutRef<\n typeof AlertDialogPrimitive.Content\n>;\n\n/**\n * AlertDialogContent - The main dialog content container.\n * @experimental\n */\nconst AlertDialogContent = forwardRef<\n ElementRef<typeof AlertDialogPrimitive.Content>,\n AlertDialogContentProps\n>(({ className, ...props }, ref) => {\n const portalContainer = usePortalContainer();\n\n return (\n <AlertDialogPortal container={portalContainer}>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Content\n ref={ref}\n className={cn(\n \"fixed left-[50%] top-[50%] z-[51] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background p-6 shadow-xl rounded-lg duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out 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%]\",\n className\n )}\n {...props}\n />\n </AlertDialogPortal>\n );\n});\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;\n\n/** @experimental */\nexport type AlertDialogHeaderProps = HTMLAttributes<HTMLDivElement>;\n\n/**\n * AlertDialogHeader - Container for dialog title and description.\n * @experimental\n */\nconst AlertDialogHeader = forwardRef<HTMLDivElement, AlertDialogHeaderProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className\n )}\n {...props}\n />\n )\n);\nAlertDialogHeader.displayName = \"AlertDialogHeader\";\n\n/** @experimental */\nexport type AlertDialogFooterProps = HTMLAttributes<HTMLDivElement>;\n\n/**\n * AlertDialogFooter - Container for dialog action buttons.\n * @experimental\n */\nconst AlertDialogFooter = forwardRef<HTMLDivElement, AlertDialogFooterProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\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 )\n);\nAlertDialogFooter.displayName = \"AlertDialogFooter\";\n\n/** @experimental */\nexport type AlertDialogTitleProps = ComponentPropsWithoutRef<\n typeof AlertDialogPrimitive.Title\n>;\n\n/**\n * AlertDialogTitle - The title of the alert dialog.\n * @experimental\n */\nconst AlertDialogTitle = forwardRef<\n ElementRef<typeof AlertDialogPrimitive.Title>,\n AlertDialogTitleProps\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Title\n ref={ref}\n className={cn(\n \"text-lg font-semibold leading-none tracking-tight text-foreground\",\n className\n )}\n {...props}\n />\n));\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;\n\n/** @experimental */\nexport type AlertDialogDescriptionProps = ComponentPropsWithoutRef<\n typeof AlertDialogPrimitive.Description\n>;\n\n/**\n * AlertDialogDescription - The description text of the alert dialog.\n * @experimental\n */\nconst AlertDialogDescription = forwardRef<\n ElementRef<typeof AlertDialogPrimitive.Description>,\n AlertDialogDescriptionProps\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nAlertDialogDescription.displayName =\n AlertDialogPrimitive.Description.displayName;\n\n/** @experimental */\nexport type AlertDialogActionProps = ComponentPropsWithoutRef<\n typeof AlertDialogPrimitive.Action\n>;\n\n/**\n * AlertDialogAction - The primary action button (e.g., \"Delete\", \"Confirm\").\n * Styled as destructive by default.\n * @experimental\n */\nconst AlertDialogAction = forwardRef<\n ElementRef<typeof AlertDialogPrimitive.Action>,\n AlertDialogActionProps\n>(({ className, children, ...props }, ref) => (\n <AlertDialogPrimitive.Action\n ref={ref}\n className={cn(buttonVariants({ variant: \"destructive\" }), className)}\n {...props}\n >\n {children}\n </AlertDialogPrimitive.Action>\n));\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;\n\n/** @experimental */\nexport type AlertDialogCancelProps = ComponentPropsWithoutRef<\n typeof AlertDialogPrimitive.Cancel\n>;\n\n/**\n * AlertDialogCancel - The cancel button.\n * Styled as outline variant.\n * @experimental\n */\nconst AlertDialogCancel = forwardRef<\n ElementRef<typeof AlertDialogPrimitive.Cancel>,\n AlertDialogCancelProps\n>(({ className, children, ...props }, ref) => (\n <AlertDialogPrimitive.Cancel\n ref={ref}\n className={cn(\n buttonVariants({ variant: \"outline\" }),\n \"mt-2 sm:mt-0\",\n className\n )}\n {...props}\n >\n {children}\n </AlertDialogPrimitive.Cancel>\n));\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;\n\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n};\n","/**\n * DropdownMenu Component\n *\n * A composable dropdown menu component built on Radix UI primitives.\n * Provides context menus, action menus, and navigation menus with full keyboard support.\n *\n * **Design Specifications**:\n * - Border-radius: `rounded-lg` for the menu surface, `rounded-sm` for items\n * - Padding: 4px (p-1) - compact spacing for menu items\n * - Shadow: shadow-md - floating element elevation\n * - Z-index: z-50 - above most content, below modals\n * - Min-width: 8rem (128px) - prevents cramped menus\n * - Item padding: 8px horizontal, 6px vertical (px-2 py-1.5)\n * - Font-size: 14px (text-sm)\n * - Transition: Tailwind animate utilities (fade, zoom, slide)\n *\n * **Accessibility**:\n * - Full keyboard navigation (Arrow keys, Enter, Escape, Tab)\n * - ARIA roles and attributes (menu, menuitem, menuitemcheckbox, menuitemradio)\n * - Focus management (focus trap, auto-focus first item)\n * - Screen reader support (labels, descriptions, indicators)\n * - WCAG 2.2 Level AA compliant\n *\n * **Features**:\n * - Portal rendering via PortalProvider for proper z-index stacking\n * - Checkbox and Radio item variants\n * - Sub-menu support (nested menus)\n * - Keyboard shortcuts display\n * - Customizable positioning (side, align, sideOffset)\n * - Disabled state support\n * - Inset support (for items with icons)\n *\n * @example\n * ```tsx\n * // Basic usage\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild>\n * <Button variant=\"outline\">Open Menu</Button>\n * </DropdownMenuTrigger>\n * <DropdownMenuContent>\n * <DropdownMenuItem>Profile</DropdownMenuItem>\n * <DropdownMenuItem>Settings</DropdownMenuItem>\n * <DropdownMenuSeparator />\n * <DropdownMenuItem>Logout</DropdownMenuItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n * ```\n *\n * @example\n * ```tsx\n * // With icons and shortcuts\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild>\n * <Button variant=\"ghost\" size=\"icon\">\n * <MoreHorizontal className=\"h-4 w-4\" />\n * </Button>\n * </DropdownMenuTrigger>\n * <DropdownMenuContent align=\"end\">\n * <DropdownMenuLabel>Actions</DropdownMenuLabel>\n * <DropdownMenuItem>\n * <Edit className=\"h-4 w-4\" />\n * Edit\n * <DropdownMenuShortcut>⌘E</DropdownMenuShortcut>\n * </DropdownMenuItem>\n * <DropdownMenuItem>\n * <Trash2 className=\"h-4 w-4\" />\n * Delete\n * <DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>\n * </DropdownMenuItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n * ```\n *\n * @example\n * ```tsx\n * // With checkbox items\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild>\n * <Button variant=\"outline\">View Options</Button>\n * </DropdownMenuTrigger>\n * <DropdownMenuContent>\n * <DropdownMenuLabel>Display</DropdownMenuLabel>\n * <DropdownMenuSeparator />\n * <DropdownMenuCheckboxItem checked={showPanel} onCheckedChange={setShowPanel}>\n * Show Panel\n * </DropdownMenuCheckboxItem>\n * <DropdownMenuCheckboxItem checked={showToolbar} onCheckedChange={setShowToolbar}>\n * Show Toolbar\n * </DropdownMenuCheckboxItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n * ```\n *\n * @see https://www.radix-ui.com/docs/primitives/components/dropdown-menu - Radix UI DropdownMenu\n */\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { Check, ChevronRight, Circle } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\n\n/** @public */\nconst DropdownMenu = DropdownMenuPrimitive.Root;\n\n/** @public */\nconst DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\n\n/** @experimental */\nconst DropdownMenuGroup = DropdownMenuPrimitive.Group;\n\n/** @experimental */\nconst DropdownMenuPortal = DropdownMenuPrimitive.Portal;\n\n/** @experimental */\nconst DropdownMenuSub = DropdownMenuPrimitive.Sub;\n\n/** @experimental */\nconst DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\n/**\n * Shared treatment for every interactive menu item.\n *\n * Radix sets `data-highlighted` for pointer hover *and* keyboard navigation, so\n * driving the highlight off that one state keeps mouse and keyboard in sync.\n * `bg-muted` is a real surface token: it reads clearly against the popover\n * without the full-contrast flip a solid `bg-primary` produces.\n */\nconst menuItemBase =\n \"cursor-pointer transition-colors data-[highlighted]:bg-muted data-[highlighted]:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\";\n\n/** @experimental */\nconst DropdownMenuSubTrigger = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {\n inset?: boolean;\n }\n>(({ className, inset, children, ...props }, ref) => (\n <DropdownMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n \"flex select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-muted data-[state=open]:text-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n menuItemBase,\n inset && \"pl-8\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto\" />\n </DropdownMenuPrimitive.SubTrigger>\n));\nDropdownMenuSubTrigger.displayName =\n DropdownMenuPrimitive.SubTrigger.displayName;\n\n/** @experimental */\nconst DropdownMenuSubContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.SubContent\n ref={ref}\n className={cn(\n \"z-50 min-w-[8rem] overflow-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out 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 origin-[--radix-dropdown-menu-content-transform-origin]\",\n className\n )}\n {...props}\n />\n));\nDropdownMenuSubContent.displayName =\n DropdownMenuPrimitive.SubContent.displayName;\n\n/** @public */\nconst DropdownMenuContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => {\n const portalContainer = usePortalContainer();\n\n return (\n <DropdownMenuPrimitive.Portal container={portalContainer}>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out 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 origin-[--radix-dropdown-menu-content-transform-origin]\",\n className\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n );\n});\nDropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;\n\n/** @public */\nconst DropdownMenuItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n menuItemBase,\n inset && \"pl-8\",\n className\n )}\n {...props}\n />\n));\nDropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;\n\n/** @public */\nconst DropdownMenuCheckboxItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n ref={ref}\n className={cn(\n \"relative flex select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none\",\n menuItemBase,\n className\n )}\n checked={checked}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Check className=\"h-4 w-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n));\nDropdownMenuCheckboxItem.displayName =\n DropdownMenuPrimitive.CheckboxItem.displayName;\n\n/** @experimental */\nconst DropdownMenuRadioItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"relative flex select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none\",\n menuItemBase,\n className\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Circle className=\"h-2 w-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n));\nDropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;\n\n/** @experimental */\nconst DropdownMenuLabel = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\n \"px-2 py-1.5 text-sm font-semibold\",\n inset && \"pl-8\",\n className\n )}\n {...props}\n />\n));\nDropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;\n\n/** @public */\nconst DropdownMenuSeparator = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-primary/5\", className)}\n {...props}\n />\n));\nDropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;\n\n/** @experimental */\nconst DropdownMenuShortcut = React.forwardRef<\n HTMLSpanElement,\n React.HTMLAttributes<HTMLSpanElement>\n>(({ className, ...props }, ref) => {\n return (\n <span\n ref={ref}\n className={cn(\"ml-auto text-xs tracking-widest opacity-60\", className)}\n {...props}\n />\n );\n});\nDropdownMenuShortcut.displayName = \"DropdownMenuShortcut\";\n\nexport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuGroup,\n DropdownMenuPortal,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuRadioGroup,\n};\n","import * as SelectPrimitive from \"@radix-ui/react-select\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { Check, ChevronDown, ChevronUp } from \"lucide-react\";\nimport type { ComponentProps } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\n\n/**\n * Select Component - Design System Specification\n *\n * Dropdown selection component for choosing from a list of options. Built on\n * Radix UI for robust accessibility and portal rendering.\n *\n * Accessibility:\n * - Full keyboard navigation (Arrow keys, Enter, Escape, Type-ahead)\n * - Proper ARIA attributes provided by Radix UI\n * - Screen reader announcements for selected value\n * - Focus management and keyboard shortcuts\n * - Disabled state support\n *\n * Design Specs:\n * - Height: sm=36px, default=40px, lg=44px (matches Input component)\n * - Padding: Horizontal 12px, vertical varies by size\n * - Border radius: `rounded-md` on the trigger, `rounded-lg` on the panel\n * - Border: 1px solid, changes on focus/error\n * - Transition: 150ms (consistent with design system)\n * - Font size: sm/default=14px (text-sm), lg=16px (text-base)\n *\n * Size Variants:\n * - sm: Height 36px - Compact forms and filters, matching a small Button\n * - default: Height 40px (h-10) - Standard forms\n * - lg: Height 44px (h-11) - Prominent selects\n *\n * Features:\n * - Portal rendering via PortalProvider (avoids overflow issues)\n * - CheckIcon indicator for selected items\n * - Keyboard type-ahead search\n * - Grouping support with labels\n * - Placeholder text support\n * - Error state via aria-invalid\n * @public\n */\nfunction Select({ ...props }: ComponentProps<typeof SelectPrimitive.Root>) {\n return <SelectPrimitive.Root data-slot=\"select\" {...props} />;\n}\n\n/** @experimental */\nfunction SelectGroup({\n ...props\n}: ComponentProps<typeof SelectPrimitive.Group>) {\n return <SelectPrimitive.Group data-slot=\"select-group\" {...props} />;\n}\n\n/** @public */\nfunction SelectValue({\n ...props\n}: ComponentProps<typeof SelectPrimitive.Value>) {\n return <SelectPrimitive.Value data-slot=\"select-value\" {...props} />;\n}\n\n/** @experimental */\nconst selectTriggerVariants = cva(\n // hover:border-primary (full strength) keeps the hover boundary more visible\n // than the resting border-input, not a fainter alpha of it.\n \"flex w-full items-center justify-between gap-2 rounded-md border border-input bg-background px-3 text-sm text-foreground cursor-pointer transition-all duration-150 focus:border-primary! focus-visible:border-primary! focus:outline-none hover:border-primary disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-primary/5 data-[placeholder]:text-muted-foreground aria-[invalid=true]:border-destructive aria-[invalid=true]:focus:border-destructive! [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4\",\n {\n variants: {\n size: {\n // `-md`, matching Button and Input: one height for one size name. A\n // select sitting beside a small button in a filter row is the case that\n // makes a 4px difference visible.\n sm: \"h-[var(--nx-control-height-md)] text-sm\",\n default: \"h-[var(--nx-control-height)] text-sm\",\n lg: \"h-[var(--nx-control-height-lg)] text-base\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n }\n);\n\n/** @public */\nexport interface SelectTriggerProps\n extends ComponentProps<typeof SelectPrimitive.Trigger>,\n VariantProps<typeof selectTriggerVariants> {}\n\n/** @public */\nconst SelectTrigger = forwardRef<\n React.ElementRef<typeof SelectPrimitive.Trigger>,\n SelectTriggerProps\n>(({ className, size, children, ...props }, ref) => {\n return (\n <SelectPrimitive.Trigger\n ref={ref}\n data-slot=\"select-trigger\"\n className={cn(selectTriggerVariants({ size, className }))}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <ChevronDown className=\"size-4 opacity-50\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n );\n});\n\nSelectTrigger.displayName = \"SelectTrigger\";\n\n/** @public */\nfunction SelectContent({\n className,\n children,\n position = \"popper\",\n ...props\n}: ComponentProps<typeof SelectPrimitive.Content>) {\n const portalContainer = usePortalContainer();\n\n return (\n <SelectPrimitive.Portal container={portalContainer}>\n <SelectPrimitive.Content\n data-slot=\"select-content\"\n className={cn(\n \"bg-popover text-popover-foreground border border-border shadow-none rounded-lg z-9999 max-h-(--radix-select-content-available-height) min-w-32 overflow-hidden data-[state=open]:animate-zoom-in-95 data-[state=closed]:animate-zoom-out-95 data-[side=bottom]:animate-slide-in-from-top-2 data-[side=left]:animate-slide-in-from-right-2 data-[side=right]:animate-slide-in-from-left-2 data-[side=top]:animate-slide-in-from-bottom-2\",\n position === \"popper\" &&\n \"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1\",\n className\n )}\n position={position}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n \"p-1\",\n position === \"popper\" &&\n \"h-(--radix-select-trigger-height) w-full min-w-(--radix-select-trigger-width) scroll-my-1\"\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n );\n}\n\n/** @experimental */\nfunction SelectLabel({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.Label>) {\n return (\n <SelectPrimitive.Label\n data-slot=\"select-label\"\n className={cn(\"text-muted-foreground px-2 py-1.5 text-xs\", className)}\n {...props}\n />\n );\n}\n\n/** @public */\nfunction SelectItem({\n className,\n children,\n ...props\n}: ComponentProps<typeof SelectPrimitive.Item>) {\n return (\n <SelectPrimitive.Item\n data-slot=\"select-item\"\n className={cn(\n \"relative flex w-full cursor-pointer items-center gap-2 rounded-sm py-2 pr-8 pl-2 text-sm text-foreground outline-none select-none transition-colors hover-unified focus:bg-primary/5 focus:text-primary data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4\",\n className\n )}\n {...props}\n >\n <span className=\"absolute right-2 flex size-3.5 items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <Check className=\"size-4\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n );\n}\n\n/** @experimental */\nfunction SelectSeparator({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.Separator>) {\n return (\n <SelectPrimitive.Separator\n data-slot=\"select-separator\"\n className={cn(\"bg-border pointer-events-none -mx-1 my-1 h-px\", className)}\n {...props}\n />\n );\n}\n\n/** @experimental */\nfunction SelectScrollUpButton({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {\n return (\n <SelectPrimitive.ScrollUpButton\n data-slot=\"select-scroll-up-button\"\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n {...props}\n >\n <ChevronUp className=\"size-4\" />\n </SelectPrimitive.ScrollUpButton>\n );\n}\n\n/** @experimental */\nfunction SelectScrollDownButton({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {\n return (\n <SelectPrimitive.ScrollDownButton\n data-slot=\"select-scroll-down-button\"\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n {...props}\n >\n <ChevronDown className=\"size-4\" />\n </SelectPrimitive.ScrollDownButton>\n );\n}\n\nexport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectScrollDownButton,\n SelectScrollUpButton,\n SelectSeparator,\n SelectTrigger,\n selectTriggerVariants,\n SelectValue,\n};\n","\"use client\";\n\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\nimport type { SheetProps } from \"../types/sheet\";\n\n/**\n * Whether the enclosing sheet is modal, published to its own parts.\n *\n * Radix takes `modal` at the root and uses it to decide focus trapping and\n * whether the rest of the page is withdrawn from the accessibility tree. The\n * scrim is that same decision expressed visually, and it is rendered a level\n * down in `SheetContent`. Passing the root's answer down — rather than giving\n * the content a second prop of its own — keeps one answer to one question: a\n * caller cannot ask for a non-modal sheet and still get a scrim over the page\n * it deliberately left interactive.\n *\n * Declared above the component doc blocks on purpose. The bundler attaches a\n * doc comment to the declaration that follows it, so anything inserted between\n * a tagged comment and its declaration silently steals the tag.\n */\nconst SheetModalContext = React.createContext(true);\n\n// Note: the close icon is not rendered by default here. Consumers should import and render their preferred icon with `SheetClose`.\n\n/**\n * Sheet Component\n *\n * A dialog variant that slides in from the edges of the screen. Used for mobile\n * navigation drawers, side panels, and contextual overlays.\n *\n * Built on Radix UI Dialog with slide-in animations and overlay backdrop.\n *\n * ## Design Specifications\n *\n * - **Width**: 320px (sm), 400px (default), 512px (lg), 672px (xl), 100% (full)\n * - **Animation**: Slide-in from side (150ms duration)\n * - **Backdrop**: the `--nx-overlay` scrim, with backdrop blur\n * - **z-index**: 50 (both overlay and content - content renders on top via DOM order)\n * - **Border-radius**: 0 (full-screen edges)\n *\n * ## Accessibility\n *\n * - **Focus Trapping**: Focus is trapped within the sheet when open\n * - **Escape Key**: Closes sheet on Escape key press\n * - **Overlay Click**: Closes sheet when clicking outside\n * - **ARIA**: Proper dialog role and ARIA attributes\n * - **Keyboard Navigation**: Tab/Shift+Tab to navigate, Enter to activate\n *\n * ## Usage Examples\n *\n * ### Basic Mobile Navigation Drawer\n *\n * ```tsx\n * import { Sheet, SheetContent, SheetTrigger } from '@nextlyhq/ui';\n * import { Menu } from 'lucide-react';\n *\n * function MobileNav() {\n * return (\n * <Sheet>\n * <SheetTrigger asChild>\n * <button className=\"h-11 w-11 md:hidden\">\n * <Menu />\n * </button>\n * </SheetTrigger>\n * <SheetContent side=\"left\" className=\"w-72\">\n * <nav>\n * <a href=\"/dashboard\">Dashboard</a>\n * <a href=\"/users\">Users</a>\n * </nav>\n * </SheetContent>\n * </Sheet>\n * );\n * }\n * ```\n *\n * @see https://www.radix-ui.com/primitives/docs/components/dialog\n * @public\n */\nconst Sheet = ({ modal = true, children, ...props }: SheetProps) => (\n <SheetModalContext.Provider value={modal}>\n <DialogPrimitive.Root modal={modal} {...props}>\n {children}\n </DialogPrimitive.Root>\n </SheetModalContext.Provider>\n);\nSheet.displayName = \"Sheet\";\n\n/** @experimental */\nconst SheetTrigger = DialogPrimitive.Trigger;\n\n/** @experimental */\nconst SheetClose = DialogPrimitive.Close;\n\n/** @experimental */\nconst SheetPortal = DialogPrimitive.Portal;\n\n/**\n * SheetOverlay\n *\n * Semi-transparent backdrop that appears behind the sheet.\n *\n * - **Background**: the `--nx-overlay` scrim + backdrop blur\n * - **Animation**: Fade in/out (150ms)\n * - **z-index**: 50\n * @experimental\n */\nconst SheetOverlay = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n data-slot=\"sheet-overlay\"\n className={cn(\n // A modal scrim, from the `--nx-overlay` token rather than a surface\n // token. A black wash is the point — painting it from `background` would\n // make it a white veil in light mode — but the alpha still has to differ\n // per mode, because what it composites over is white in one and mid-tone\n // in the other.\n \"fixed inset-0 z-50 bg-overlay backdrop-blur-sm\",\n \"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className\n )}\n {...props}\n ref={ref}\n />\n));\nSheetOverlay.displayName = DialogPrimitive.Overlay.displayName;\n\n/**\n * Sheet Content Variants\n *\n * Defines slide-in animations for each side and size options.\n * @experimental\n */\nconst sheetVariants = cva(\n \"fixed z-50 gap-4 bg-background p-6 shadow-lg will-change-transform transition ease-in-out data-[state=closed]:duration-150 data-[state=open]:duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out\",\n {\n variants: {\n side: {\n top: \"inset-x-0 top-0 border-b border-border data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top\",\n bottom:\n \"inset-x-0 bottom-0 border-t border-border data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom\",\n left: \"inset-y-0 left-0 h-full w-3/4 border-r border-border data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm\",\n right:\n \"inset-y-0 right-0 h-full w-3/4 border-l border-border data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm\",\n },\n },\n defaultVariants: {\n side: \"right\",\n },\n }\n);\n\n/** @public */\nexport interface SheetContentProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>,\n VariantProps<typeof sheetVariants> {}\n\n/**\n * SheetContent\n *\n * Main content container for the sheet.\n *\n * - **Position**: Fixed to screen edge (side prop)\n * - **Width**: Responsive (w-3/4 on mobile, max-w-sm on sm+)\n * - **Padding**: 24px (p-6)\n * - **Border**: On appropriate edge based on side\n * - **Close Button**: Positioned in top-right corner (16px from edges)\n *\n * @param side - Which edge to slide in from: \"left\", \"right\", \"top\", \"bottom\"\n * @public\n */\nconst SheetContent = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Content>,\n SheetContentProps\n>(({ side = \"right\", className, children, ...props }, ref) => {\n const portalContainer = usePortalContainer();\n // Taken from the root rather than from a prop here: the scrim and Radix's\n // inerting are the same decision, and two places to state it would let a\n // sheet scrim a page it had left interactive.\n const modal = React.useContext(SheetModalContext);\n\n return (\n <SheetPortal container={portalContainer}>\n {modal ? <SheetOverlay /> : null}\n <DialogPrimitive.Content\n ref={ref}\n data-slot=\"sheet-content\"\n className={cn(sheetVariants({ side }), className)}\n {...props}\n >\n {children}\n </DialogPrimitive.Content>\n </SheetPortal>\n );\n});\nSheetContent.displayName = DialogPrimitive.Content.displayName;\n\n/**\n * SheetHeader\n *\n * Header section for sheet title and description.\n *\n * - **Layout**: Flex column with 6px gap\n * - **Text Alignment**: Left (default) or center\n * @public\n */\nconst SheetHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className\n )}\n {...props}\n />\n);\nSheetHeader.displayName = \"SheetHeader\";\n\n/**\n * SheetFooter\n *\n * Footer section for sheet actions (buttons, etc.).\n *\n * - **Layout**: Flex row on desktop, column on mobile\n * - **Alignment**: Right-aligned on desktop, stretched on mobile\n * @experimental\n */\nconst SheetFooter = ({\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);\nSheetFooter.displayName = \"SheetFooter\";\n\n/**\n * SheetTitle\n *\n * Title heading for the sheet (h2).\n *\n * - **Font**: text-lg font-semibold\n * - **Color**: text-foreground\n * - **Required**: For accessibility (screen readers)\n * @public\n */\nconst SheetTitle = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\"text-lg font-semibold text-foreground\", className)}\n {...props}\n />\n));\nSheetTitle.displayName = DialogPrimitive.Title.displayName;\n\n/**\n * SheetDescription\n *\n * Description text for the sheet.\n *\n * - **Font**: text-sm\n * - **Color**: text-muted-foreground\n * - **Purpose**: Provide context for screen readers\n * @public\n */\nconst SheetDescription = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nSheetDescription.displayName = DialogPrimitive.Description.displayName;\n\nexport {\n Sheet,\n SheetPortal,\n SheetOverlay,\n SheetTrigger,\n SheetClose,\n SheetContent,\n SheetHeader,\n SheetFooter,\n SheetTitle,\n SheetDescription,\n sheetVariants,\n};\n","\"use client\";\n\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport {\n Command as CommandPrimitive,\n defaultFilter,\n useCommandState as useCommandStatePrimitive,\n} from \"cmdk\";\nimport { Search } from \"lucide-react\";\nimport type {\n ElementRef,\n ComponentPropsWithoutRef,\n HTMLAttributes,\n} from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\n\n/**\n * Command Component\n *\n * A command palette component built on cmdk for fast, keyboard-driven navigation and actions.\n * Supports fuzzy search, keyboard navigation, and WCAG 2.2 AA accessibility.\n *\n * @example\n * ```tsx\n * <Command>\n * <CommandInput placeholder=\"Type a command or search...\" />\n * <CommandList>\n * <CommandEmpty>No results found.</CommandEmpty>\n * <CommandGroup heading=\"Navigation\">\n * <CommandItem>\n * <Home className=\"mr-2 h-4 w-4\" />\n * Dashboard\n * </CommandItem>\n * </CommandGroup>\n * </CommandList>\n * </Command>\n * ```\n *\n * @design-spec\n * - Input height: 48px (h-12) - larger for prominence\n * - Item height: 36px (h-9) desktop, 44px (h-11) mobile for touch\n * - Border radius: `rounded-lg` for the panel, `rounded-sm` for items\n * - Max list height: 400px (max-h-[400px])\n * - Transition: 150ms per design system\n *\n * @accessibility\n * - Full keyboard navigation (Arrow keys, Enter, Escape, Home, End)\n * - ARIA attributes (role=\"combobox\", role=\"listbox\", role=\"option\")\n * - Screen reader announcements for results\n * - Focus management and visual focus indicators\n * - WCAG 2.2 AA compliant (verified contrast ratios)\n * @experimental\n */\n\nexport type CommandProps = ComponentPropsWithoutRef<typeof CommandPrimitive>;\n\n/**\n * Command - Root container for the command palette.\n * Handles filtering, keyboard navigation, and accessibility.\n * @experimental\n */\nconst Command = forwardRef<ElementRef<typeof CommandPrimitive>, CommandProps>(\n ({ className, ...props }, ref) => (\n <CommandPrimitive\n ref={ref}\n className={cn(\n \"flex h-full w-full flex-col overflow-hidden rounded-lg bg-background text-foreground\",\n className\n )}\n {...props}\n />\n )\n);\nCommand.displayName = \"Command\";\n\n/** @experimental */\nexport interface CommandDialogProps extends DialogPrimitive.DialogProps {\n /**\n * Passed to the command root this dialog renders internally.\n *\n * A seam rather than a list of forwarded props, because the settings a caller needs from the\n * root are the ones this component happens not to have thought of: `label`, which supplies the\n * search input's accessible name (cmdk renders an EMPTY hidden label without it, and an empty\n * `aria-labelledby` reference is worse than none — it stops the placeholder naming the field);\n * `filter` and `shouldFilter`, which decide match order; and `vimBindings`, which claims Ctrl+K\n * and Ctrl+N inside the list.\n *\n * `children` is excluded because this component owns the dialog's contents.\n */\n commandProps?: Omit<ComponentPropsWithoutRef<typeof Command>, \"children\">;\n /**\n * Passed to the dialog content this component renders internally.\n *\n * The seam that matters here is `onCloseAutoFocus`: this dialog has no trigger, so Radix has\n * nothing to hand focus back to, and it fires this at the point focus is actually being\n * returned — after the exit animation, which a timer set at close time cannot know the length\n * of. `className` is excluded because this component owns the dialog's own layout.\n */\n contentProps?: Omit<\n ComponentPropsWithoutRef<typeof DialogPrimitive.Content>,\n \"children\" | \"className\"\n >;\n}\n\n/**\n * CommandDialogOverlay - Custom overlay for CommandDialog with proper z-index.\n * Uses z-[99] to stay below CommandDialog content (z-[100]) but above regular dialogs.\n */\nconst CommandDialogOverlay = forwardRef<\n ElementRef<typeof DialogPrimitive.Overlay>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\n // A modal scrim, from the `--nx-overlay` token rather than a surface\n // token. A black wash is the point — painting it from `background` would\n // make it a white veil in light mode — but the alpha still has to differ\n // per mode, because what it composites over is white in one and mid-tone\n // in the other.\n \"fixed inset-0 z-[99] bg-overlay backdrop-blur-sm\",\n \"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n \"transition-opacity duration-200\",\n className\n )}\n {...props}\n />\n));\nCommandDialogOverlay.displayName = \"CommandDialogOverlay\";\n\n/**\n * CommandDialog - Command palette in a modal dialog.\n * Use this variant for Cmd+K keyboard shortcut pattern.\n *\n * @example\n * ```tsx\n * const [open, setOpen] = useState(false)\n *\n * useEffect(() => {\n * const down = (e: KeyboardEvent) => {\n * if (e.key === \"k\" && (e.metaKey || e.ctrlKey)) {\n * e.preventDefault()\n * setOpen((open) => !open)\n * }\n * }\n * document.addEventListener(\"keydown\", down)\n * return () => document.removeEventListener(\"keydown\", down)\n * }, [])\n *\n * return (\n * <CommandDialog open={open} onOpenChange={setOpen}>\n * <CommandInput placeholder=\"Type a command...\" />\n * <CommandList>...</CommandList>\n * </CommandDialog>\n * )\n * ```\n * @experimental\n */\nconst CommandDialog = ({\n children,\n commandProps,\n contentProps,\n ...props\n}: CommandDialogProps) => {\n const portalContainer = usePortalContainer();\n\n return (\n <DialogPrimitive.Root {...props}>\n <DialogPrimitive.Portal container={portalContainer}>\n <CommandDialogOverlay />\n <DialogPrimitive.Content\n {...contentProps}\n data-slot=\"command-content\"\n className={cn(\n // Position\n \"fixed left-[50%] top-[50%] z-[100] translate-x-[-50%] translate-y-[-50%]\",\n // Size - responsive\n \"w-full max-w-lg\",\n \"max-h-[85vh]\", // Slightly shorter than design spec to ensure safe area\n // Mobile adjustments\n \"sm:max-w-lg\", // 512px on desktop\n \"max-w-full\", // Full width on mobile\n // Spacing\n \"m-4 sm:m-0\", // 16px margin on mobile, no margin on desktop\n // Visual\n \"overflow-hidden rounded-lg border border-border bg-background shadow-xl\",\n // Animation\n \"duration-200\",\n \"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n \"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n \"data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-top-[48%]\"\n )}\n >\n <Command\n {...commandProps}\n className={cn(\n \"[&_[cmdk-group-heading]]:px-3 [&_[cmdk-group-heading]]:py-2 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-wide [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:mb-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-3 [&_[cmdk-item]]:py-2 [&_[cmdk-item]_svg]:h-4 [&_[cmdk-item]_svg]:w-4\",\n // Merged rather than overridden: a caller passing `className` for its own reason\n // would otherwise silently drop every layout rule this dialog depends on.\n commandProps?.className\n )}\n >\n {children}\n </Command>\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n </DialogPrimitive.Root>\n );\n};\n\n/** @experimental */\nexport type CommandInputProps = ComponentPropsWithoutRef<\n typeof CommandPrimitive.Input\n>;\n\n/**\n * CommandInput - Search input field for filtering commands.\n * Includes search icon and styled per design system.\n * @experimental\n */\nconst CommandInput = forwardRef<\n ElementRef<typeof CommandPrimitive.Input>,\n CommandInputProps\n>(({ className, ...props }, ref) => (\n <div\n className=\"flex items-center border-b border-border px-4\"\n // cmdk-input-wrapper is the attribute the cmdk library targets\n // in its built-in stylesheet to scope wrapper-level styles.\n // Required by the library; not a typo.\n // eslint-disable-next-line react/no-unknown-property\n cmdk-input-wrapper=\"\"\n >\n <Search className=\"mr-3 h-5 w-5 shrink-0 text-muted-foreground\" />\n <CommandPrimitive.Input\n ref={ref}\n className={cn(\n // Size\n \"flex h-12 w-full\",\n // Visual\n \"bg-transparent text-base\",\n \"outline-none\",\n // Typography\n \"placeholder:text-muted-foreground\",\n // States\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n // Prevent iOS zoom on focus\n \"text-base md:text-sm\",\n className\n )}\n {...props}\n />\n </div>\n));\nCommandInput.displayName = \"CommandInput\";\n\n/** @experimental */\nexport type CommandListProps = ComponentPropsWithoutRef<\n typeof CommandPrimitive.List\n>;\n\n/**\n * CommandList - Scrollable container for command results.\n * Max height 400px per design spec to prevent tall dialogs.\n * @experimental\n */\nconst CommandList = forwardRef<\n ElementRef<typeof CommandPrimitive.List>,\n CommandListProps\n>(({ className, ...props }, ref) => (\n <CommandPrimitive.List\n ref={ref}\n className={cn(\n // Scroll\n \"max-h-[400px] overflow-y-auto overflow-x-hidden\",\n // Spacing\n \"p-2\",\n className\n )}\n {...props}\n />\n));\nCommandList.displayName = \"CommandList\";\n\n/** @experimental */\nexport type CommandEmptyProps = ComponentPropsWithoutRef<\n typeof CommandPrimitive.Empty\n>;\n\n/**\n * CommandEmpty - Empty state message when no results found.\n * Centered text with muted color per design spec.\n * @experimental\n */\nconst CommandEmpty = forwardRef<\n ElementRef<typeof CommandPrimitive.Empty>,\n CommandEmptyProps\n>((props, ref) => (\n <CommandPrimitive.Empty\n ref={ref}\n className=\"py-8 px-4 text-center text-sm text-muted-foreground\"\n {...props}\n />\n));\nCommandEmpty.displayName = \"CommandEmpty\";\n\n/** @experimental */\nexport type CommandGroupProps = ComponentPropsWithoutRef<\n typeof CommandPrimitive.Group\n>;\n\n/**\n * CommandGroup - Grouped section of commands with optional heading.\n * Heading styled as uppercase, small, semibold per design spec.\n * @experimental\n */\nconst CommandGroup = forwardRef<\n ElementRef<typeof CommandPrimitive.Group>,\n CommandGroupProps\n>(({ className, ...props }, ref) => (\n <CommandPrimitive.Group\n ref={ref}\n className={cn(\n // Spacing\n \"space-y-1 mb-2\",\n // Heading styling applied via parent Command className\n \"[&_[cmdk-group-heading]]:px-3 [&_[cmdk-group-heading]]:py-2 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-wide\",\n className\n )}\n {...props}\n />\n));\nCommandGroup.displayName = \"CommandGroup\";\n\n/** @experimental */\nexport type CommandSeparatorProps = ComponentPropsWithoutRef<\n typeof CommandPrimitive.Separator\n>;\n\n/**\n * CommandSeparator - Visual divider between command groups.\n * 1px line with border border-border color, 8px margin top/bottom.\n * @experimental\n */\nconst CommandSeparator = forwardRef<\n ElementRef<typeof CommandPrimitive.Separator>,\n CommandSeparatorProps\n>(({ className, ...props }, ref) => (\n <CommandPrimitive.Separator\n ref={ref}\n className={cn(\"h-px bg-border my-2\", className)}\n {...props}\n />\n));\nCommandSeparator.displayName = \"CommandSeparator\";\n\n/** @experimental */\nexport type CommandItemProps = ComponentPropsWithoutRef<\n typeof CommandPrimitive.Item\n>;\n\n/**\n * CommandItem - Individual selectable command item.\n * Height: 36px desktop, 44px mobile per design spec.\n * Includes hover, focus, and selected states.\n * @experimental\n */\nconst CommandItem = forwardRef<\n ElementRef<typeof CommandPrimitive.Item>,\n CommandItemProps\n>(({ className, ...props }, ref) => (\n <CommandPrimitive.Item\n ref={ref}\n className={cn(\n // Layout\n \"relative flex cursor-pointer select-none items-center gap-3\",\n // Size\n \"min-h-[44px] sm:min-h-[36px]\", // Flexible height with minimal touch targets\n // Spacing\n \"px-3 py-2.5\",\n // Visual\n \"rounded-sm text-base sm:text-sm outline-none\",\n // Transitions\n \"transition-all duration-200 ease-(--ease-premium)\",\n // Hover state - shared dashboard hover treatment\n \"hover-unified\",\n // Selected/focused state (keyboard navigation)\n \"aria-selected:bg-primary/5 aria-selected:text-primary\",\n \"data-[selected=true]:bg-primary/5 data-[selected=true]:text-primary\",\n // Disabled state\n \"data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50\",\n className\n )}\n {...props}\n />\n));\nCommandItem.displayName = \"CommandItem\";\n\n/** @experimental */\nexport type CommandShortcutProps = HTMLAttributes<HTMLSpanElement>;\n\n/**\n * CommandShortcut - Keyboard shortcut display (e.g., \"⌘K\", \"↵ Enter\").\n * Monospace font, subtle background, right-aligned per design spec.\n * @experimental\n */\nconst CommandShortcut = forwardRef<HTMLSpanElement, CommandShortcutProps>(\n ({ className, ...props }, ref) => {\n return (\n <span\n ref={ref}\n className={cn(\n // Position\n \"ml-auto\",\n // Typography\n \"text-xs font-mono\",\n // Visual\n \"text-muted-foreground bg-primary/5\",\n \"border border-border rounded-md\",\n // Spacing\n \"px-1.5 py-0.5\",\n className\n )}\n {...props}\n />\n );\n }\n);\nCommandShortcut.displayName = \"CommandShortcut\";\n\nexport {\n Command,\n CommandDialog,\n CommandInput,\n CommandList,\n CommandEmpty,\n CommandGroup,\n CommandItem,\n CommandSeparator,\n CommandShortcut,\n};\n\n/**\n * The command palette's default match scorer, re-exported.\n *\n * A caller that overrides `filter` — to keep an opaque item value out of the scoring, say — still\n * wants the ranking that comes for free, and reaching for `cmdk` directly is not open to every\n * package here.\n *\n * Bound to a declaration rather than re-exported with `export { x as y }`: the bundler keeps a doc\n * comment attached to a declaration and drops one attached to an export statement, so the release\n * tag would not reach the published types.\n *\n * @experimental\n */\nexport const commandDefaultFilter = defaultFilter;\n\n/**\n * The value of the item the palette has HIGHLIGHTED, from a component inside\n * it.\n *\n * The palette owns which item is highlighted, and it moves that highlight for\n * reasons a caller never sees: a pointer crossing an item, an arrow key, and a\n * filter that removes the item the highlight was on. Anything outside wanting\n * to follow it — a preview pane, a description strip, a status line — needs to\n * read that rather than keep a copy.\n *\n * Reading beats mirroring here for a specific reason rather than on principle.\n * The palette's controlled `value` sets which item is MARKED, and does not move\n * the internal cursor that `aria-activedescendant` and the scroll follow. So a\n * caller that writes the value to steer the highlight desynchronises the two:\n * the item drawn as current and the option announced as current stop agreeing,\n * and after a filter the announcement can name an element that has been\n * removed. A read leaves one owner and takes a derived view.\n *\n * NARROWED to the one field deliberately. The underlying library exposes its\n * whole store through a selector — the raw search text, its internal item and\n * group maps, the id it uses for `aria-activedescendant` — and publishing that\n * selector would make every one of those part of this kit's public API and its\n * generated declarations. A dependency upgrade could then reshape what callers\n * can reach without any export changing name, which is exactly what the\n * surface snapshot cannot see. This returns a string.\n *\n * Empty string means nothing is highlighted, which is the library's own\n * spelling and a different answer from \"an item whose value is unknown\".\n *\n * Must be called from inside the palette, since that is where the state lives.\n *\n * Bound to a declaration rather than re-exported with `export { x as y }`: the\n * bundler keeps a doc comment attached to a declaration and drops one attached\n * to an export statement, so the release tag would not reach the published\n * types.\n *\n * @experimental\n */\nexport const useCommandHighlight = (): string =>\n useCommandStatePrimitive(state => state.value);\n","import { cva, type VariantProps } from \"class-variance-authority\";\nimport { Loader2, type LucideProps } from \"lucide-react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * Spinner Component - Design System Specification\n *\n * Loading indicator for short wait times (300ms - 1s). Uses the Loader2 icon from\n * lucide-react with a smooth rotation animation.\n *\n * **Usage Guidelines** (from UX Strategy):\n * - ✅ Use for buttons and small components (loading states)\n * - ✅ Use for short waits (300ms - 1s)\n * - ❌ Don't use for page content (use Skeleton instead)\n * - ❌ Don't use for waits > 3s (use Progress bar instead)\n *\n * **Sizes**:\n * - sm: 16px (h-4 w-4) - For small buttons, inline text\n * - md: 20px (h-5 w-5) - Default size, for regular buttons\n * - lg: 24px (h-6 w-6) - For large buttons, prominent loading states\n *\n * **Accessibility**:\n * - Uses `role=\"status\"` for screen reader announcements\n * - Uses `aria-label=\"Loading\"` for accessible name\n * - Respects `prefers-reduced-motion` (animation stops automatically via Tailwind)\n * - Non-focusable (not interactive)\n *\n * **Animation**:\n * - Uses Tailwind's `animate-spin` utility (1s linear infinite)\n * - Automatically respects user's motion preferences (WCAG 2.3.3)\n *\n * @example\n * // Button loading state\n * <Button disabled>\n * <Spinner size=\"sm\" className=\"mr-2\" />\n * Saving...\n * </Button>\n *\n * @example\n * // Standalone loading indicator\n * <div className=\"flex items-center justify-center p-8\">\n * <Spinner size=\"lg\" />\n * </div>\n *\n * @example\n * // Custom color\n * <Spinner className=\"text-primary\" />\n * @experimental\n */\nconst spinnerVariants = cva(\"animate-spin motion-reduce:animate-none\", {\n variants: {\n size: {\n sm: \"h-4 w-4\",\n md: \"h-5 w-5\",\n lg: \"h-6 w-6\",\n },\n },\n defaultVariants: {\n size: \"md\",\n },\n});\n\n/**\n * Spinner component props\n *\n * Extends LucideProps to support all standard SVG attributes (data-*, id, etc.)\n * while providing size variants and accessibility features.\n * @experimental\n */\nexport type SpinnerProps = Omit<LucideProps, \"size\"> &\n VariantProps<typeof spinnerVariants> & {\n /**\n * Accessible label for screen readers\n * @default \"Loading\"\n */\n \"aria-label\"?: string;\n };\n\n/**\n * Spinner component for loading states\n * @experimental\n */\nconst Spinner = forwardRef<SVGSVGElement, SpinnerProps>(\n (\n { size = \"md\", className, \"aria-label\": ariaLabel = \"Loading\", ...props },\n ref\n ) => {\n return (\n <Loader2\n ref={ref}\n role=\"status\"\n aria-label={ariaLabel}\n className={cn(spinnerVariants({ size }), className)}\n {...props}\n />\n );\n }\n);\n\nSpinner.displayName = \"Spinner\";\n\nexport { Spinner, spinnerVariants };\n","\"use client\";\n\nimport {\n CheckCircle2,\n AlertCircle,\n AlertTriangle,\n XCircle,\n Loader2,\n} from \"lucide-react\";\nimport { toast, Toaster as Sonner, type ToasterProps } from \"sonner\";\n\n// Re-export toast function for convenient usage\nexport { toast };\n\n/**\n * Toaster Component - Toast Notification System\n *\n * A wrapper around Sonner (opinionated toast component for React) with\n * custom icons. Provides a consistent notification system across the application.\n *\n * Features:\n * - Theme support via `theme` prop (light/dark/system)\n * - Custom icons from lucide-react matching design system\n * - 6 toast types: default, success, info, warning, error, loading (promise-based)\n * - Action button support (Undo, Retry, etc.)\n * - Configurable positioning (default: bottom-right)\n * - Automatic stacking and dismissal\n * - WCAG 2.2 AA compliant colors via CSS variables\n *\n * Setup:\n * 1. Add <Toaster /> to your root layout (once per app)\n * 2. Import toast from '@nextlyhq/ui' to trigger notifications\n *\n * Usage Examples:\n *\n * // Default toast\n * import { toast } from '@nextlyhq/ui';\n * toast(\"Event has been created\");\n *\n * // Success toast\n * toast.success(\"User created successfully!\");\n *\n * // Error toast\n * toast.error(\"Failed to save changes. Please try again.\");\n *\n * // Warning toast\n * toast.warning(\"This action cannot be undone.\");\n *\n * // Info toast\n * toast.info(\"Be at the area 10 minutes before the event time\");\n *\n * // Toast with action button\n * toast(\"Event deleted\", {\n * description: \"You can undo this action\",\n * action: {\n * label: \"Undo\",\n * onClick: () => console.log(\"Undo clicked\"),\n * },\n * });\n *\n * // Promise-based toast (loading → success/error)\n * toast.promise(\n * fetchData(),\n * {\n * loading: \"Loading...\",\n * success: (data) => `${data.name} has been created`,\n * error: \"Failed to load data\",\n * }\n * );\n *\n * Positioning Options:\n * <Toaster position=\"top-right\" />\n * <Toaster position=\"top-center\" />\n * <Toaster position=\"bottom-left\" />\n * <Toaster position=\"bottom-center\" />\n * <Toaster position=\"bottom-right\" /> (default)\n *\n * Customization:\n * All styling uses CSS variables from the design system:\n * - --normal-bg: Background color (uses --nx-popover with fallback)\n * - --normal-text: Text color (uses --nx-popover-foreground with fallback)\n * - --normal-border: Border color (uses --nx-border with fallback)\n * - --border-radius: Border radius (uses --radius with fallback)\n *\n * Security:\n * ⚠️ IMPORTANT: Toast content is not automatically sanitized. When displaying\n * user-generated content or data from external sources, ensure you sanitize\n * the content to prevent XSS attacks. Use plain text strings when possible,\n * or sanitize HTML/JSX content before passing to toast functions.\n *\n * Safe: toast.success(`User ${username} created`) // Template literals with plain text\n * Unsafe: toast.success(<div dangerouslySetInnerHTML={{__html: userInput}} />) // XSS risk\n * Safe: toast.success(<div>{sanitizeHtml(userInput)}</div>) // Sanitized content\n *\n * Accessibility:\n * - Screen reader announcements for all toast types\n * - Keyboard dismissible (Escape key)\n * - Focus management for action buttons\n * - ARIA labels automatically applied\n * - WCAG 2.2 AA color contrast\n *\n * @see https://sonner.emilkowal.ski/ - Sonner documentation\n * @see https://ui.shadcn.com/docs/components/sonner - shadcn/ui integration guide\n * @experimental\n */\nexport function Toaster({ theme = \"system\", ...props }: ToasterProps) {\n return (\n <Sonner\n theme={theme}\n className=\"toaster group bg-transparent! overflow-visible! z-[9999]!\"\n data-slot=\"toaster\"\n toastOptions={{\n classNames: {\n description: \"text-muted-foreground\",\n },\n }}\n icons={{\n success: <CheckCircle2 className=\"h-4 w-4\" />,\n info: <AlertCircle className=\"h-4 w-4\" />,\n warning: <AlertTriangle className=\"h-4 w-4\" />,\n error: <XCircle className=\"h-4 w-4\" />,\n loading: <Loader2 className=\"h-4 w-4 animate-spin\" />,\n }}\n style={\n {\n \"--normal-bg\": \"var(--nx-popover)\",\n \"--normal-text\": \"var(--nx-popover-foreground)\",\n \"--normal-border\": \"var(--nx-border)\",\n \"--border-radius\": \"0px\",\n } as React.CSSProperties\n }\n {...props}\n />\n );\n}\n","import * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** @experimental */\nconst Table = React.forwardRef<\n HTMLTableElement,\n React.HTMLAttributes<HTMLTableElement>\n>(({ className, ...props }, ref) => (\n <div className=\"relative w-full overflow-auto\">\n <table\n ref={ref}\n className={cn(\"w-full caption-bottom text-sm\", className)}\n {...props}\n />\n </div>\n));\nTable.displayName = \"Table\";\n\n/** @experimental */\nconst TableHeader = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <thead\n ref={ref}\n className={cn(\"[&_tr]:border-b border-border\", className)}\n {...props}\n />\n));\nTableHeader.displayName = \"TableHeader\";\n\n/** @experimental */\nconst TableBody = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tbody\n ref={ref}\n className={cn(\"[&_tr:last-child]:border-0\", className)}\n {...props}\n />\n));\nTableBody.displayName = \"TableBody\";\n\n/** @experimental */\nconst TableFooter = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tfoot\n ref={ref}\n className={cn(\n \"border-t border-border font-medium [&>tr]:last:border-b-0\",\n className\n )}\n {...props}\n />\n));\nTableFooter.displayName = \"TableFooter\";\n\n/** @experimental */\nconst TableRow = React.forwardRef<\n HTMLTableRowElement,\n React.HTMLAttributes<HTMLTableRowElement>\n>(({ className, ...props }, ref) => (\n <tr\n ref={ref}\n className={cn(\n \"border-b border-border transition-colors data-[state=selected]:bg-primary/5\",\n className\n )}\n {...props}\n />\n));\nTableRow.displayName = \"TableRow\";\n\n/** @experimental */\nconst TableHead = React.forwardRef<\n HTMLTableCellElement,\n React.ThHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <th\n ref={ref}\n className={cn(\n \"h-11 px-4 text-left align-middle font-semibold text-xs text-foreground uppercase tracking-wider [&:has([role=checkbox])]:pr-0\",\n className\n )}\n {...props}\n />\n));\nTableHead.displayName = \"TableHead\";\n\n/** @experimental */\nconst TableCell = React.forwardRef<\n HTMLTableCellElement,\n React.TdHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <td\n ref={ref}\n className={cn(\n \"px-4 py-3 align-middle [&:has([role=checkbox])]:pr-0\",\n className\n )}\n {...props}\n />\n));\nTableCell.displayName = \"TableCell\";\n\n/** @experimental */\nconst TableCaption = React.forwardRef<\n HTMLTableCaptionElement,\n React.HTMLAttributes<HTMLTableCaptionElement>\n>(({ className, ...props }, ref) => (\n <caption\n ref={ref}\n className={cn(\"mt-4 text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nTableCaption.displayName = \"TableCaption\";\n\nexport {\n Table,\n TableHeader,\n TableBody,\n TableFooter,\n TableHead,\n TableRow,\n TableCell,\n TableCaption,\n};\n","import { Search, Loader2, X } from \"lucide-react\";\n\n/**\n * Props for TableSearch component\n * @experimental\n */\nexport interface TableSearchProps {\n /** Current search value */\n value: string;\n /** Callback when search value changes */\n onChange: (value: string) => void;\n /** Callback when clear button is clicked */\n onClear: () => void;\n /** Placeholder text for search input */\n placeholder?: string;\n /** Whether data is currently loading */\n isLoading?: boolean;\n /** Ref to the input element */\n inputRef?: React.RefObject<HTMLInputElement | null>;\n}\n\n/**\n * Search input component for tables\n *\n * Features:\n * - Search icon\n * - Clear button (when value is present)\n * - Loading spinner (when isLoading is true)\n * - Accessible with aria-busy attribute\n *\n * @example\n * ```tsx\n * <TableSearch\n * value={searchInput}\n * onChange={handleSearchChange}\n * onClear={handleClearSearch}\n * placeholder=\"Search users...\"\n * isLoading={loading}\n * />\n * ```\n * @experimental\n */\nexport function TableSearch({\n value,\n onChange,\n onClear,\n placeholder = \"Filter records...\",\n isLoading = false,\n inputRef,\n}: TableSearchProps) {\n return (\n <div className=\"relative w-full max-w-lg\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground\" />\n {/* The edge uses border-input, the identifying-boundary token, rather\n than the decorative border-border: an empty field has nothing else to\n identify it. Matches Input, Textarea, Checkbox and RadioGroup.\n border-input no longer meets 1.4.11's 3:1 minimum in light mode; see\n contrast/accepted.ts. The distinction it draws is still the right one\n to follow, but it is a statement of role, not of ratio. */}\n <input\n ref={inputRef}\n type=\"text\"\n placeholder={placeholder}\n value={value}\n onChange={e => onChange(e.target.value)}\n aria-busy={isLoading}\n className=\"h-10 w-full rounded-md border border-input bg-background pl-10 pr-10 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 transition-all\"\n />\n {(value || isLoading) && (\n <div className=\"absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-2\">\n {isLoading && (\n <Loader2 className=\"w-3.5 h-3.5 text-primary animate-spin\" />\n )}\n {value && (\n <button\n type=\"button\"\n onClick={onClear}\n className=\"text-muted-foreground hover:text-foreground transition-colors p-0.5 rounded-md hover:bg-primary/5\"\n aria-label=\"Clear search\"\n >\n <X className=\"w-3.5 h-3.5\" />\n </button>\n )}\n </div>\n )}\n </div>\n );\n}\n","import { AlertCircle, Loader2, FileQuestion } from \"lucide-react\";\n\n/**\n * Props for TableError component\n * @experimental\n */\nexport interface TableErrorProps {\n /** Error message to display */\n message?: string;\n}\n\n/**\n * Error state component for tables\n * @experimental\n */\nexport function TableError({\n message = \"An error occurred. Please try again.\",\n}: TableErrorProps) {\n return (\n <div className=\"flex items-center gap-2\">\n <AlertCircle className=\"w-4 h-4 shrink-0\" />\n <span>{message}</span>\n </div>\n );\n}\n\n/**\n * Loading state component for tables\n * @experimental\n */\nexport function TableLoading() {\n return (\n <div className=\"flex flex-col items-center justify-center gap-4 p-12 text-muted-foreground\">\n <Loader2 className=\"w-8 h-8 animate-spin text-primary/80\" />\n <span className=\"text-sm font-medium\">Loading data...</span>\n </div>\n );\n}\n\n/**\n * Props for TableEmpty component\n * @experimental\n */\nexport interface TableEmptyProps {\n /** Custom message to display when no data */\n message?: string;\n}\n\n/**\n * Empty state component for tables\n * @experimental\n */\nexport function TableEmpty({ message = \"No records found\" }: TableEmptyProps) {\n return (\n <div className=\"flex flex-col items-center justify-center gap-4 p-16 text-center text-muted-foreground\">\n <div className=\"flex h-12 w-12 items-center justify-center rounded-md bg-primary/5\">\n <FileQuestion className=\"h-6 w-6\" />\n </div>\n <span className=\"text-sm font-medium\">{message}</span>\n </div>\n );\n}\n","/**\n * TableSkeleton Component\n *\n * Generic loading skeleton for data tables.\n * Renders header, body, and footer skeleton bars inside a card.\n * Unified with EntryTable skeleton pattern for consistency across all tables.\n */\n\nimport type * as React from \"react\";\n\nimport { Skeleton } from \"./skeleton\";\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"./table\";\n\n/** Shared animated gray bar — Unified with design system Skeleton */\nconst GrayBar = ({ className }: { className?: string }) => (\n <Skeleton className={className} />\n);\n\n/** @experimental */\nexport interface TableSkeletonProps {\n columns?: number;\n rowCount?: number;\n hideWrapper?: boolean;\n hideFooter?: boolean;\n}\n\n/** @experimental */\nexport const TableSkeleton: React.FC<TableSkeletonProps> = ({\n columns = 5,\n rowCount = 8,\n hideWrapper = false,\n hideFooter = false,\n}) => {\n const content = (\n <>\n {/* Square corners: this fills the bordered table wrapper edge to edge. */}\n <div className=\"border-0 rounded-none shadow-none\">\n <Table>\n {/* Header Skeleton */}\n <TableHeader>\n <TableRow>\n {Array.from({ length: columns }).map((_, colIdx) => (\n <TableHead key={`skeleton-header-${colIdx}`} className=\"py-3\">\n {colIdx === 0 ? (\n <GrayBar className=\"h-4 w-4\" />\n ) : colIdx === columns - 1 ? (\n <div className=\"flex justify-center\">\n <Skeleton className=\"h-4 w-4 rounded-sm\" />\n </div>\n ) : colIdx === 1 ? (\n <GrayBar className=\"h-4 w-[70%] max-w-[180px]\" />\n ) : (\n <GrayBar className=\"h-4 w-[60%] max-w-[120px]\" />\n )}\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n\n {/* Body Skeleton */}\n <TableBody>\n {Array.from({ length: rowCount }).map((_, rowIdx) => (\n <TableRow key={rowIdx} className=\"border-b border-border\">\n {Array.from({ length: columns }).map((_, colIdx) => (\n <TableCell key={colIdx} className=\"py-3\">\n {colIdx === 0 ? (\n <GrayBar className=\"h-4 w-4\" />\n ) : colIdx === columns - 1 ? (\n <div className=\"flex justify-center\">\n <Skeleton className=\"h-8 w-8 rounded-md\" />\n </div>\n ) : colIdx === 1 ? (\n <div className=\"flex items-center gap-3\">\n <Skeleton className=\"w-9 rounded-md shrink-0\" />\n <div className=\"space-y-1.5 flex-1\">\n <Skeleton className=\"h-4 w-[120px]\" />\n <Skeleton className=\"h-3 w-[80px]\" />\n </div>\n </div>\n ) : (\n <GrayBar className=\"h-4 w-[60%] max-w-[120px]\" />\n )}\n </TableCell>\n ))}\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n\n {/* Footer Skeleton */}\n {!hideFooter && (\n <div className=\"table-footer border-t border-border\">\n {/* Axis utilities rather than the `p-4` shorthand: Tailwind emits `.px-2`\n and `.py-4` AFTER `.p-4`, so at equal specificity the shorthand loses\n both axes and contributes nothing. The footer is deliberately tighter\n horizontally than vertically. */}\n <div className=\"flex items-center justify-between px-2 py-4\">\n <div className=\"flex items-center gap-2 text-sm\">\n <GrayBar className=\"h-4 w-[120px]\" />\n </div>\n <div className=\"flex items-center gap-6\">\n <div className=\"flex items-center gap-2\">\n <GrayBar className=\"h-4 w-20\" />\n <GrayBar className=\"h-8 w-[70px]\" />\n </div>\n <div className=\"flex items-center gap-1\">\n <GrayBar className=\"h-8 w-8\" />\n <GrayBar className=\"h-8 w-8\" />\n <GrayBar className=\"h-8 w-8\" />\n <GrayBar className=\"h-8 w-8\" />\n <GrayBar className=\"h-8 w-8\" />\n </div>\n <GrayBar className=\"h-4 w-[120px]\" />\n </div>\n </div>\n </div>\n )}\n </>\n );\n\n if (hideWrapper) {\n return content;\n }\n\n return (\n <div className=\"table-wrapper rounded-md border border-border bg-card overflow-hidden\">\n {content}\n </div>\n );\n};\n\nTableSkeleton.displayName = \"TableSkeleton\";\n","\"use client\";\n\nimport { Pipette } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport type { Rgba } from \"../lib/color\";\nimport {\n hsvToRgb,\n hueAt,\n hueSliderValue,\n parseHex,\n pointOnSurface,\n rgbToHsv,\n saturationValueAt,\n surfacePointFor,\n toHex,\n} from \"../lib/color\";\nimport { useIsomorphicLayoutEffect } from \"../lib/isomorphic-layout-effect\";\nimport { cn } from \"../lib/utils\";\n\nimport { Button } from \"./button\";\nimport { Input } from \"./input\";\n\n/**\n * One preset a host offers.\n *\n * `color` is what the swatch is PAINTED with. `value` is what `onSwatchSelect`\n * hands back, unread by this component — a host storing design tokens puts its\n * own token reference there and receives it unchanged, so choosing a swatch\n * never resolves a token into the colour it currently happens to be. Without\n * that, re-theming stops moving the values that pointed at it.\n *\n * @experimental\n */\nexport interface ColorSwatch<TValue = string> {\n id: string;\n label: string;\n color: string;\n value?: TValue;\n}\n\n/**\n * Props for ColorPicker.\n * @experimental\n */\nexport interface ColorPickerProps<TValue = string> {\n /** The colour shown on the surface, as hex. */\n color: string;\n /** A colour was chosen by editing — surface, hue, alpha or the hex field. */\n onColorChange: (color: string) => void;\n /** Presets. Painted from `color`, returned by `value`. */\n swatches?: ColorSwatch<TValue>[];\n /**\n * A preset was chosen. Separate from `onColorChange` because only the host\n * can say what a swatch MEANS: the two are different events, and collapsing\n * them is what loses a token reference.\n */\n onSwatchSelect?: (swatch: ColorSwatch<TValue>) => void;\n /**\n * Recently used colours. Owned by the host, never by this component — the\n * admin scopes them per user, and a component writing `localStorage` at\n * render is unusable on a server and untestable without a DOM.\n */\n recentColors?: string[];\n /** Alpha channel. Off by default: most call sites want an opaque colour. */\n showAlpha?: boolean;\n className?: string;\n}\n\n/** The picker's own working state, kept in HSV so a drag does not lose hue. */\ninterface Hsva {\n h: number;\n s: number;\n v: number;\n a: number;\n}\n\nfunction toHsva(hex: string): Hsva {\n const parsed = parseHex(hex);\n if (!parsed) return { h: 0, s: 0, v: 0, a: 1 };\n const { r, g, b, alpha } = parsed;\n return { ...rgbToHsv({ r, g, b }), a: alpha };\n}\n\nfunction toHexString(hsva: Hsva, withAlpha: boolean): string {\n return toHex(hsvToRgb(hsva), withAlpha ? hsva.a : 1);\n}\n\n/** The last step of the hue strip. Kept beside the input it sizes. */\nconst HUE_MAX = 359;\n\n/**\n * A parsed colour as picker state, keeping the hue the surface already sits on\n * when the new colour has none of its own.\n *\n * Grey and black carry no hue, so `rgbToHsv` reports its documented fallback of\n * 0. Storing that discards where the user was: typing black while editing a\n * blue and then raising saturation returns RED. While saturation is 0 the\n * retained hue is invisible, so keeping it costs nothing and is the only thing\n * that makes the surface recoverable.\n */\nfunction hsvaFrom(color: Rgba, alpha: number, currentHue: number): Hsva {\n const hsv = rgbToHsv(color);\n return { ...hsv, h: hsv.s === 0 ? currentHue : hsv.h, a: alpha };\n}\n\n/**\n * A range input drawn by this component rather than by the browser.\n *\n * `appearance-none` removes the platform track, so every slider carrying it\n * owes a background of its own — one that does not is not a subtle styling\n * miss, it is an invisible control.\n */\nconst SLIDER = \"h-3 w-full cursor-pointer appearance-none rounded-full\";\n\n/**\n * The grey chequerboard that makes transparency legible.\n *\n * Fixed greys, deliberately, where the rest of this package uses theme tokens:\n * this is the standard rendering of \"nothing here\", and a chequerboard that\n * changed colour with the theme would read as part of the colour being edited.\n *\n * design-lint-ok: fixed greys are the point here; see above.\n */\nconst CHECKERBOARD = \"repeating-conic-gradient(#c8c8c8 0% 25%, #ffffff 0% 50%)\";\n\n/** Whether this browser can sample a colour from the screen. */\nfunction eyeDropperSupported(): boolean {\n // Chromium only. Feature-detected rather than assumed: constructing it where\n // it does not exist throws, and a picker that throws on click is worse than\n // one without the button.\n return typeof window !== \"undefined\" && \"EyeDropper\" in window;\n}\n\ninterface EyeDropperLike {\n open: () => Promise<{ sRGBHex: string }>;\n}\n\n/**\n * Whether an event target is a node in ANY document.\n *\n * `instanceof Node` cannot answer this: it is bound to one JavaScript realm, so\n * a target from an iframe or a pop-out fails it while being a perfectly good\n * node. Probing for the property the DOM guarantees is realm-independent, and\n * `Partial<Node>` is the honest shape to probe through — the value is not known\n * to be a node until this returns.\n */\nfunction isNode(value: EventTarget | null): value is Node {\n return (\n value !== null && typeof (value as Partial<Node>).nodeType === \"number\"\n );\n}\n\n/**\n * A colour control: a saturation square, a hue strip, optional alpha, a hex\n * field, and any presets the host supplies.\n *\n * Deliberately knows nothing about design tokens. A swatch carries an opaque\n * `value` this component never reads and hands back untouched, so a host can\n * store a token reference and keep it. That is what lets one component serve\n * both a plain colour field and a token-aware surface without either learning\n * about the other.\n *\n * @experimental\n *\n * @example\n * ```tsx\n * <ColorPicker\n * color={color}\n * onColorChange={setColor}\n * swatches={tokens.map(t => ({ id: t.name, label: t.name, color: t.value, value: { $token: t.name } }))}\n * onSwatchSelect={s => store(s.value)}\n * />\n * ```\n */\nexport function ColorPicker<TValue = string>({\n color,\n onColorChange,\n swatches = [],\n onSwatchSelect,\n recentColors = [],\n showAlpha = false,\n className,\n}: ColorPickerProps<TValue>) {\n const fieldId = React.useId();\n /** The picker's own subtree, for telling a press inside it from a dismissal. */\n const rootRef = React.useRef<HTMLDivElement>(null);\n /**\n * Whether a press that began INSIDE this picker is still in progress, so a\n * blur carrying no destination can be told from focus genuinely leaving.\n */\n const insidePress = React.useRef(false);\n /**\n * Whether a finish was DEFERRED rather than declined: a blur carrying no\n * destination arrived during an inside press, so the press's own action was\n * given the chance to supersede the draft instead.\n */\n const owedFinish = React.useRef(false);\n /** Undoes a touch press that is waiting to see whether it becomes a tap. */\n const pendingTap = React.useRef<(() => void) | null>(null);\n /**\n * The current way to finish a draft, for a deferred tap whose wait may span a\n * render. Refreshed where the listeners are registered, at layout timing, so\n * it is settled before any later native event can read it.\n */\n const latestCommit = React.useRef<() => void>(() => undefined);\n /**\n * The saturation area, whose BOX is what turns a pointer position into a\n * saturation and brightness pair — the mapping needs the rectangle, not the\n * element.\n */\n const surfaceRef = React.useRef<HTMLDivElement>(null);\n const [hsva, setHsva] = React.useState<Hsva>(() => toHsva(color));\n // What the hex field shows while it is being typed into. A half-typed value\n // is not a colour, and reformatting it on every keystroke moves the caret.\n const [draftHex, setDraftHex] = React.useState<string | null>(null);\n /*\n * The same draft, held where a SECOND finish in the same dispatch can see it.\n *\n * `setDraftHex(null)` is queued, not applied, so two paths that both finish —\n * an outside press moving focus, and the blur that press produces — can each\n * read a still-non-null draft and report the colour twice. React renders\n * between them only if something flushes, which is what makes a test\n * dispatching the events separately miss it entirely.\n */\n const draftRef = React.useRef<string | null>(null);\n\n // Re-seeded when the host supplies a colour this picker did not produce.\n // Comparing the RENDERED hex rather than the prop avoids a loop: the same\n // colour has several spellings, and `#FFF` arriving back as `#ffffff` would\n // otherwise reset the surface on every change.\n const rendered = toHexString(hsva, showAlpha);\n /*\n * At LAYOUT timing, matching the listener below. A passive effect leaves the\n * stale draft readable for a moment the native capture listener is already\n * refreshed for, so an outside press arriving in between publishes the old\n * text over the colour the host has just supplied.\n */\n useIsomorphicLayoutEffect(() => {\n const incoming = parseHex(color);\n if (\n incoming &&\n toHex(incoming, showAlpha ? incoming.alpha : 1) !== rendered\n ) {\n // Same hue retention as the other entry points: a host that pushes a grey\n // in must not silently move the surface's hue to red. Read from the\n // updater rather than from `hsva`, so the effect does not re-run on a\n // hue change it is not interested in.\n /*\n * The DRAFT goes with it. A colour arriving from the host — an undo, an\n * edit made elsewhere — replaces what is stored, so text typed against\n * the old value is stale: left in place, the next blur would publish it\n * back over the value that just arrived.\n */\n dropDraft();\n setHsva(prev => hsvaFrom(incoming, incoming.alpha, prev.h));\n }\n }, [color, rendered, showAlpha]);\n\n /*\n * A typed colour is reported when the author FINISHES it, never per\n * keystroke.\n *\n * `parseHex` accepts 3, 4, 6 and 8 digits, so a PREFIX of a valid colour is\n * itself a valid colour: typing `#123456` passes through `#123` and `#1234`\n * on the way. Reporting each of those made the last one stick whenever the\n * author paused or the surface went away — `#12345` left the host holding\n * `#11223344`, a colour nobody typed, silently replacing the stored one.\n *\n * So the field holds a draft and this is the only thing that publishes it:\n * Enter, and leaving the field. Dragging is untouched and still reports\n * continuously, which is what its coalescing exists for — a drag has no\n * finish to wait for, and typing does.\n *\n * DISMISSAL IS NOT A FINISH, deliberately. Escape means cancel, so a draft\n * dying with the surface is the conventional answer rather than a loss; and\n * clicking away moves focus out of the field first, so that path commits\n * through the blur below. Reporting from an unmount instead would arrive\n * after a host that coalesces a gesture on close has already decided what to\n * write, which is a value published into nothing.\n */\n /*\n * Forget the draft without reporting it, for everything that SUPERSEDES one:\n * a preset, a recent colour, a drag, or the host pushing a new colour in. The\n * ref and the state move together, and the ref moves synchronously, because a\n * blur that has already been queued will read it before React renders.\n */\n const dropDraft = (): void => {\n owedFinish.current = false;\n draftRef.current = null;\n setDraftHex(null);\n };\n\n const commitDraft = (): void => {\n owedFinish.current = false;\n const text = draftRef.current;\n // Taken BEFORE anything else, so a second caller in this same dispatch\n // finds nothing to report rather than the value this one is publishing.\n draftRef.current = null;\n // NOTHING TYPED, nothing to report. Reading the field's value instead would\n // publish the colour already on screen every time focus merely passed\n // through — a save for an edit nobody made, and a second one for an edit\n // already reported by Enter.\n if (text === null) return;\n setDraftHex(null);\n const parsed = parseHex(text);\n // An unfinishable draft is DISCARDED rather than reported. The field\n // returns to the colour that is actually stored, so what is shown and what\n // is saved agree — which they did not when a stale intermediate stood in\n // for the text on screen.\n if (!parsed) return;\n setHsva(prev => hsvaFrom(parsed, parsed.alpha, prev.h));\n onColorChange(toHex(parsed, showAlpha ? parsed.alpha : 1));\n };\n\n /*\n * A press OUTSIDE is a finish, and it is the one a blur cannot catch.\n *\n * Measured rather than assumed: a dismissable layer runs from the outside\n * `pointerdown` and unmounts this content there, so the focus change that\n * would have produced a blur never happens and a complete typed colour was\n * lost with no report at all. A test driving `blur` directly cannot see that\n * — the blur is the thing in question — so the case that proves it presses\n * outside for real.\n *\n * CAPTURE, because the ordering is the whole point: a capture listener on the\n * document runs before the dismiss layer's own, so the value is reported\n * while this is still mounted. Reporting from an unmount instead was tried\n * and removed — a host that coalesces a picker gesture on close has already\n * decided what to write by then.\n *\n * RE-REGISTERED every render, with no dependency list, and at LAYOUT timing.\n * A passive effect leaves the previous listener installed until its cleanup\n * runs, so a native press arriving after a render that changed `showAlpha` or\n * `onColorChange` would reach the closure from the render before it — an old\n * alpha, or a consumer that is no longer the current one.\n * The obvious alternative keeps the handler in a ref refreshed by an effect,\n * and that ref is not guaranteed fresh when a NATIVE listener fires: a\n * passive effect runs after the commit, and this listener is outside React's\n * event system, so an outside press arriving in between would call the\n * previous closure and discard the draft it was holding. Swapping one\n * listener per render costs nothing measurable and has no such window.\n *\n * Escape is untouched and still cancels: it dismisses without a pointer, so\n * nothing here runs and the draft dies with the surface, which is what a\n * cancel means.\n */\n useIsomorphicLayoutEffect(() => {\n const root = rootRef.current;\n if (root === null) return;\n latestCommit.current = commitDraft;\n const onPointerDown = (event: Event): void => {\n /*\n * Any new press ENDS whatever the last one was waiting for. A touch that\n * became a scroll produces no click, so its pending completion would\n * otherwise sit installed and be finished by the next unrelated click\n * anywhere — including a press on the hex field to move the caret, which\n * would publish text still being edited.\n */\n pendingTap.current?.();\n pendingTap.current = null;\n /*\n * A press INSIDE is not a dismissal — a swatch, a slider, the field\n * itself — and committing there would report a draft the press is about\n * to replace.\n *\n * Recognised through the COMPOSED PATH first, because a composed event\n * crossing a shadow boundary is retargeted to the host by the time it\n * reaches this document: `root` does not contain that host, so a press on\n * the hex field itself would read as outside and publish a half-typed\n * prefix — clicking to move the caret after `#123` would store `#112233`.\n *\n * The containment test behind it covers the ordinary case and is written\n * WITHOUT `instanceof`, which is realm-bound: in an iframe or a pop-out\n * the target belongs to that document's own JavaScript realm and is not\n * an instance of this one's `Node`. `contains` is a tree operation and\n * does not care which realm a node came from.\n */\n const path =\n typeof event.composedPath === \"function\" ? event.composedPath() : [];\n const inside =\n path.includes(root) ||\n (isNode(event.target) && root.contains(event.target));\n /*\n * RECORDED, because a blur cannot always tell where focus went. Some\n * engines do not focus a button on press, so the field's `focusout`\n * arrives with a null `relatedTarget` and reads as focus leaving the\n * picker entirely — finishing the draft before the swatch or eyedropper\n * click can supersede it, which is the double report this all exists to\n * avoid. Cleared when the press ends.\n */\n insidePress.current = true;\n // A press inside decides NOTHING about the draft. Whether it becomes a\n // replacement is not knowable here — the eyedropper's button is inside\n // and its sampling can be cancelled, leaving nothing to replace with —\n // so each path that actually replaces the value drops the draft as part\n // of doing so, and the blur below declines to report one while focus is\n // moving within this picker.\n if (inside) return;\n /*\n * A TOUCH press is not yet a tap. It may become a scroll or a long press,\n * and a dismissable layer waits for the resulting click before dismissing\n * for exactly that reason — so finishing here would publish a draft while\n * the picker stays open and the field is still being edited. The click\n * that follows a completed tap is what finishes it; a scroll produces\n * none, and the listener is discarded with the effect.\n */\n /*\n * Read off the event rather than narrowed by `instanceof PointerEvent`,\n * which is realm-bound for the same reason the node test above avoids it.\n * A listener registered for `pointerdown` receives a pointer event; the\n * property is absent only where the environment does not implement them,\n * and an absent type is not a touch.\n */\n const pointerType = (event as Partial<PointerEvent>).pointerType;\n if (pointerType === \"touch\") {\n const onClick = (): void => {\n owner.removeEventListener(\"click\", onClick, true);\n pendingTap.current = null;\n // The CURRENT commit, not this render's: a wait that spans a rerender\n // would otherwise report through the closure it was created in — an\n // old alpha, or a consumer no longer current. The ref is refreshed in\n // the same layout effect that registers these listeners, so it is\n // settled before any later native event.\n latestCommit.current();\n };\n owner.addEventListener(\"click\", onClick, true);\n pendingTap.current = () => {\n owner.removeEventListener(\"click\", onClick, true);\n };\n return;\n }\n commitDraft();\n };\n /*\n * The picker's OWN document, not the global one. Rendered into an iframe or\n * a pop-out window this component's presses happen in a different document\n * entirely, and a listener on the parent global would never see them —\n * which is the case where a dismiss layer unmounts the picker and the draft\n * goes with it.\n */\n const owner = root.ownerDocument;\n /*\n * A cancelled gesture ends the wait too, and is the signal the platform\n * gives when a press becomes a scroll rather than a tap.\n */\n const onPointerCancel = (): void => {\n insidePress.current = false;\n pendingTap.current?.();\n pendingTap.current = null;\n };\n // The press ENDING is what releases the blur above, whether or not it\n // became a click.\n const onPointerUp = (): void => {\n insidePress.current = false;\n };\n /*\n * The finish a null-destination blur DEFERRED rather than cancelled.\n *\n * On engines that do not focus a button when it is pressed, the field's\n * blur is skipped so the press's own action can supersede the draft. Where\n * that action replaces nothing — a swatch with no handler, a cancelled\n * sample — the draft would otherwise sit pending with focus already outside\n * the picker, and no further blur is coming to finish it.\n *\n * BUBBLE phase, so the action has already run: a swatch that did replace\n * the value has dropped the draft by now and there is nothing left to\n * report. Only a draft that survived its own press, with focus outside,\n * finishes here.\n */\n const onClickResolve = (): void => {\n // Only a finish that was actually deferred. Reading focus alone would\n // finish on any click that happens to land while focus is elsewhere,\n // including one this picker had no part in.\n if (!owedFinish.current) return;\n latestCommit.current();\n };\n owner.addEventListener(\"pointerdown\", onPointerDown, true);\n owner.addEventListener(\"pointercancel\", onPointerCancel, true);\n owner.addEventListener(\"pointerup\", onPointerUp, true);\n owner.addEventListener(\"click\", onClickResolve, false);\n return () => {\n owner.removeEventListener(\"pointerdown\", onPointerDown, true);\n owner.removeEventListener(\"pointercancel\", onPointerCancel, true);\n owner.removeEventListener(\"pointerup\", onPointerUp, true);\n owner.removeEventListener(\"click\", onClickResolve, false);\n };\n });\n\n /*\n * A pending tap outlives an ordinary RERENDER and dies with the component.\n *\n * The effect above re-runs on every render so its closures stay current, and\n * ending the wait in its cleanup killed a legitimate one: an outside target\n * that sets state from its own `pointerdown` rerenders this picker before the\n * click arrives, so the completion was removed and a finished colour never\n * reached the host. What ends a wait is a new press, a cancelled gesture, or\n * this component going away — never a render.\n */\n useIsomorphicLayoutEffect(\n () => () => {\n pendingTap.current?.();\n pendingTap.current = null;\n },\n []\n );\n\n const commit = (next: Hsva): void => {\n setHsva(next);\n dropDraft();\n onColorChange(toHexString(next, showAlpha));\n };\n\n const trackPointer = (event: React.PointerEvent<HTMLDivElement>): void => {\n const rect = surfaceRef.current?.getBoundingClientRect();\n if (!rect) return;\n const { s, v } = saturationValueAt(\n pointOnSurface(event.clientX, event.clientY, rect)\n );\n commit({ ...hsva, s, v });\n };\n\n // Routed through the surface mapping instead of clamping here, so the keys\n // and the pointer cannot disagree about where the edges are.\n const nudge = (ds: number, dv: number): void => {\n const { s, v } = saturationValueAt(\n surfacePointFor(hsva.s + ds, hsva.v + dv)\n );\n commit({ ...hsva, s, v });\n };\n\n const handleSurfaceKey = (event: React.KeyboardEvent<HTMLDivElement>) => {\n // Shift takes the coarse step, matching what the arrow keys do on the\n // sliders beside it.\n const step = event.shiftKey ? 0.1 : 0.01;\n const moves: Record<string, [number, number]> = {\n ArrowLeft: [-step, 0],\n ArrowRight: [step, 0],\n ArrowUp: [0, step],\n ArrowDown: [0, -step],\n };\n const move = moves[event.key];\n if (!move) return;\n // Arrow keys would otherwise scroll the page under the control.\n event.preventDefault();\n nudge(move[0], move[1]);\n };\n\n // Resolved after mount, never during render. Reading `window` while rendering\n // makes the server omit this button and the first client render add it, which\n // React 19 treats as a hydration failure and repairs by discarding the whole\n // picker subtree.\n const [canPickFromScreen, setCanPickFromScreen] = React.useState(false);\n React.useEffect(() => {\n setCanPickFromScreen(eyeDropperSupported());\n }, []);\n\n const handle = surfacePointFor(hsva.s, hsva.v);\n const hueOnly = toHex(hsvToRgb({ h: hsva.h, s: 1, v: 1 }));\n\n const pickFromScreen = async (): Promise<void> => {\n const ctor = (window as unknown as Record<string, unknown>).EyeDropper as\n | (new () => EyeDropperLike)\n | undefined;\n if (!ctor) return;\n /*\n * This press OWNS whatever finish its own blur deferred. Sampling either\n * replaces the draft or is cancelled, and both answers arrive later than\n * the click — so leaving the deferral to be settled on that click reports\n * the typed colour first and the sampled one after it, two edits for the\n * one the author made.\n *\n * Claimed synchronously, before the first await, because the click that\n * would otherwise settle it is already on its way.\n */\n const owed = owedFinish.current;\n owedFinish.current = false;\n let sampled: string;\n try {\n sampled = (await new ctor().open()).sRGBHex;\n } catch {\n /*\n * Dismissed, so nothing replaces the draft and the finish its own blur\n * deferred is now due: focus has already left the field, and no further\n * blur is coming to carry it.\n */\n if (owed) commitDraft();\n // The user dismissed the picker. Not an error, and nothing to report.\n // Scoped to `open()` alone: with the commit inside this block, a host\n // whose `onColorChange` throws — a failing save, a rejected validation —\n // was reported as a dismissal and swallowed, while the picker had\n // already moved. Every other edit path lets that reach the host, and so\n // does this one now.\n return;\n }\n const parsed = parseHex(sampled);\n // The screen's alpha is not meaningful, so the picker keeps its own.\n if (parsed) commit(hsvaFrom(parsed, hsva.a, hsva.h));\n };\n\n return (\n <div\n ref={rootRef}\n className={cn(\"w-64 space-y-3\", className)}\n /*\n * The finish that focus can express, watched at the PICKER rather than at\n * the field. `onBlur` is delivered from the bubbling `focusout`, so this\n * sees focus leaving any descendant.\n *\n * At the field alone it missed the keyboard route entirely: tab from the\n * field to a preset and then out without activating it, and the field's\n * own blur was declined — focus had moved to something inside — while\n * nothing watched the boundary the focus actually crossed. The pointer\n * listener cannot cover it either, since no pointer was involved.\n *\n * `relatedTarget` names where focus is going, and is null when it leaves\n * the document entirely, which is also a finish.\n */\n onBlur={event => {\n const next = event.relatedTarget;\n const root = rootRef.current;\n if (root !== null && isNode(next) && root.contains(next)) return;\n // A blur with NO destination during a press that began inside is that\n // press, not a departure: some engines do not focus a button when it is\n // pressed, and finishing here would beat the click that supersedes it.\n if (next === null && insidePress.current) {\n owedFinish.current = true;\n return;\n }\n commitDraft();\n }}\n >\n <div\n ref={surfaceRef}\n role=\"application\"\n tabIndex={0}\n // The values are in the name because `role=\"application\"` carries no\n // value semantics of its own, and without them a screen reader\n // announces a region that can be driven but never says where it is.\n aria-label={`Saturation and brightness: ${Math.round(hsva.s * 100)}% saturation, ${Math.round(hsva.v * 100)}% brightness. Arrow keys adjust.`}\n className=\"ring-offset-background focus-visible:ring-ring relative h-40 w-full cursor-crosshair touch-none rounded-md focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none\"\n style={{\n backgroundColor: hueOnly,\n // Value on TOP of saturation. CSS paints the first layer nearest the\n // viewer, so the reverse order lets the opaque white end of the\n // saturation ramp cover the black end of the value ramp: the\n // bottom-left corner displays white while selecting black.\n backgroundImage:\n \"linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, transparent)\",\n }}\n onKeyDown={handleSurfaceKey}\n onPointerDown={event => {\n event.currentTarget.setPointerCapture(event.pointerId);\n trackPointer(event);\n }}\n onPointerMove={event => {\n if (event.buttons === 1) trackPointer(event);\n }}\n >\n <span\n aria-hidden=\"true\"\n // A fixed white ring inside a black one, not theme tokens: this\n // handle sits on an arbitrary colour the user is choosing, not on a\n // themed surface, so it has to stay visible against both ends of the\n // square. `border-background` resolved to black in dark mode and\n // vanished against the square's own black lower edge.\n className=\"pointer-events-none absolute size-3 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow-sm ring-1 ring-black/60\"\n style={{ left: `${handle.x * 100}%`, top: `${handle.y * 100}%` }}\n />\n </div>\n\n <label className=\"sr-only\" htmlFor={`${fieldId}-hue`}>\n Hue\n </label>\n <input\n id={`${fieldId}-hue`}\n type=\"range\"\n min={0}\n max={HUE_MAX}\n step={1}\n value={hueSliderValue(hsva.h, HUE_MAX)}\n onChange={event =>\n commit({ ...hsva, h: hueAt(+event.target.value / (HUE_MAX + 1)) })\n }\n className={SLIDER}\n // design-lint-ok: the hue strip renders the colour wheel itself, so its\n // stops are the control's data rather than theming.\n style={{\n backgroundImage:\n \"linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00)\",\n }}\n />\n\n {showAlpha && (\n <>\n <label className=\"sr-only\" htmlFor={`${fieldId}-alpha`}>\n Opacity\n </label>\n <input\n id={`${fieldId}-alpha`}\n type=\"range\"\n min={0}\n max={100}\n step={1}\n value={Math.round(hsva.a * 100)}\n onChange={event =>\n commit({ ...hsva, a: +event.target.value / 100 })\n }\n className={SLIDER}\n style={{\n // The ramp runs to the colour being edited, over a chequerboard,\n // so the track shows what the slider actually controls. Without\n // any background this rendered as a blank 12px strip whose only\n // label was screen-reader-only.\n backgroundImage: `linear-gradient(to right, transparent, ${toHexString({ ...hsva, a: 1 }, false)}), ${CHECKERBOARD}`,\n backgroundSize: \"100% 100%, 8px 8px\",\n }}\n />\n </>\n )}\n\n <div className=\"flex items-center gap-2\">\n <label className=\"sr-only\" htmlFor={`${fieldId}-hex`}>\n Hex colour\n </label>\n <Input\n id={`${fieldId}-hex`}\n className=\"font-mono\"\n value={draftHex ?? rendered}\n /*\n * A keystroke moves the DRAFT and nothing else — not the surface, not\n * the host. Moving the surface here would also fight the re-seeding\n * effect above, which compares the rendered hex against the host's\n * prop and would pull a half-typed value straight back.\n */\n onChange={event => {\n draftRef.current = event.target.value;\n setDraftHex(event.target.value);\n }}\n onKeyDown={event => {\n if (event.key !== \"Enter\") return;\n /*\n * An Enter that ACCEPTS AN IME CANDIDATE is not a finish. Consuming\n * it blocks the acceptance and reports whatever was in the field\n * before the composition resolved. Both signals are read because\n * older engines report the composition only as `keyCode` 229, and\n * this repository's other IME guards check the pair for that\n * reason.\n */\n if (event.nativeEvent.isComposing || event.keyCode === 229) return;\n // Kept off the surrounding form, which may have a submit of its own:\n // finishing a colour is not submitting whatever contains it.\n event.preventDefault();\n commitDraft();\n }}\n />\n {canPickFromScreen && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n aria-label=\"Pick a colour from the screen\"\n onClick={() => void pickFromScreen()}\n >\n <Pipette className=\"size-4\" />\n </Button>\n )}\n </div>\n\n {swatches.length > 0 && (\n <div>\n <p className=\"text-muted-foreground mb-1 text-xs\">Presets</p>\n <div className=\"flex flex-wrap gap-1\">\n {swatches.map(swatch => (\n <button\n key={swatch.id}\n type=\"button\"\n title={swatch.label}\n aria-label={swatch.label}\n className=\"size-6 rounded border shadow-sm\"\n style={{ backgroundColor: swatch.color }}\n onClick={() => {\n /*\n * The swatch REPLACES what was being typed, so the draft goes\n * with it — but only where the host can actually perform the\n * replacement. `onSwatchSelect` is optional and the type\n * permits swatches without it, and dropping a draft for a\n * callback that does nothing loses the typed colour and puts\n * nothing in its place.\n *\n * The other replacement paths drop it inside `commit`; this\n * one reports through the host and has to say so itself.\n */\n if (onSwatchSelect === undefined) return;\n dropDraft();\n onSwatchSelect(swatch);\n }}\n />\n ))}\n </div>\n </div>\n )}\n\n {recentColors.length > 0 && (\n <div>\n <p className=\"text-muted-foreground mb-1 text-xs\">Recent</p>\n <div className=\"flex flex-wrap gap-1\">\n {recentColors.map(recent => (\n <button\n key={recent}\n type=\"button\"\n title={recent}\n aria-label={recent}\n className=\"size-6 rounded border shadow-sm\"\n style={{ backgroundColor: recent }}\n onClick={() => {\n const parsed = parseHex(recent);\n if (parsed) commit(hsvaFrom(parsed, parsed.alpha, hsva.h));\n }}\n />\n ))}\n </div>\n </div>\n )}\n </div>\n );\n}\n","/**\n * Conversions between the colour models an editing surface needs.\n *\n * ## Why each model is here\n *\n * - **sRGB** is what a screen displays and what `#rrggbb` encodes. Everything ends here.\n * - **HSV** is what a colour picker is: a square of saturation against value, beside a hue\n * strip. No other model puts those three controls in the shape people expect.\n * - **OKLCH** is what this product's own theme is written in — every token in `theme.css` is an\n * `oklch()` value. A picker that cannot read it cannot edit the theme.\n *\n * ## Why the maths is here rather than in a library\n *\n * These are fixed, published transforms: the sRGB transfer function and the OKLab matrices are\n * specified in CSS Color 4 and do not change. The package ships no runtime colour dependency, and\n * this module keeps it that way. `culori` remains a DEV dependency used as a test oracle — the\n * conversions here are cross-checked against it rather than trusted on their own.\n *\n * ## The part that is genuinely hard\n *\n * OKLCH describes more colours than a screen can show. Converting one that falls outside sRGB has\n * no correct answer, only choices, and the naive choice — clamp each channel independently — is\n * the wrong one: it shifts hue, because clipping red without clipping green changes the ratio\n * between them. {@link oklchToRgb} reduces chroma instead, holding lightness and hue, which is the\n * approach CSS Color 4 describes for gamut mapping.\n *\n * @module lib/color/convert\n */\n\n/**\n * An sRGB colour with channels in [0, 1]. Alpha is carried separately.\n *\n * @experimental\n */\nexport interface Rgb {\n r: number;\n g: number;\n b: number;\n}\n\n/**\n * Hue in [0, 360), saturation and value in [0, 1].\n *\n * @experimental\n */\nexport interface Hsv {\n h: number;\n s: number;\n v: number;\n}\n\n/**\n * Perceptual lightness in [0, 1], chroma from 0, hue in [0, 360).\n *\n * @experimental\n */\nexport interface Oklch {\n l: number;\n c: number;\n h: number;\n}\n\nconst clamp01 = (n: number): number => (n < 0 ? 0 : n > 1 ? 1 : n);\n\n/**\n * A chroma no displayable sRGB colour exceeds.\n *\n * The most saturated sRGB primaries sit near 0.37 in OKLCH; this leaves headroom above that and\n * gives the gamut search a fixed bracket, so its error is absolute rather than proportional to\n * whatever the caller asked for.\n */\nconst MAX_SRGB_CHROMA = 0.5;\n\n/**\n * Wrap a hue into [0, 360), so -30 and 330 are the same angle.\n *\n * @experimental\n */\nexport function normalizeHue(hue: number): number {\n if (!Number.isFinite(hue)) return 0;\n const wrapped = hue % 360;\n return wrapped < 0 ? wrapped + 360 : wrapped;\n}\n\n/**\n * HSV to sRGB.\n * Saturation and value are clamped rather than rejected: a picker drags them, and a drag that\n * overshoots by a rounding error should saturate rather than throw.\n *\n * @experimental\n */\nexport function hsvToRgb({ h, s, v }: Hsv): Rgb {\n const hue = normalizeHue(h);\n const sat = clamp01(s);\n const val = clamp01(v);\n\n const sector = hue / 60;\n const chroma = val * sat;\n // The second-largest component, which falls as the hue moves away from a primary.\n const x = chroma * (1 - Math.abs((sector % 2) - 1));\n const base = val - chroma;\n\n let rgb: [number, number, number];\n if (sector < 1) rgb = [chroma, x, 0];\n else if (sector < 2) rgb = [x, chroma, 0];\n else if (sector < 3) rgb = [0, chroma, x];\n else if (sector < 4) rgb = [0, x, chroma];\n else if (sector < 5) rgb = [x, 0, chroma];\n else rgb = [chroma, 0, x];\n\n return { r: rgb[0] + base, g: rgb[1] + base, b: rgb[2] + base };\n}\n\n/**\n * sRGB to HSV.\n * Hue is UNDEFINED for a grey and value is undefined for black, and this returns 0 for both. A\n * picker must not take that 0 as the user's hue: it is the absence of one. Holding hue across a\n * drag to zero saturation is the caller's job, which is why a picker keeps HSV as its state\n * rather than deriving it from the colour each render.\n *\n * @experimental\n */\nexport function rgbToHsv({ r, g, b }: Rgb): Hsv {\n const red = clamp01(r);\n const green = clamp01(g);\n const blue = clamp01(b);\n\n const max = Math.max(red, green, blue);\n const min = Math.min(red, green, blue);\n const chroma = max - min;\n\n let hue = 0;\n if (chroma !== 0) {\n if (max === red) hue = ((green - blue) / chroma) % 6;\n else if (max === green) hue = (blue - red) / chroma + 2;\n else hue = (red - green) / chroma + 4;\n hue *= 60;\n }\n\n return {\n h: normalizeHue(hue),\n s: max === 0 ? 0 : chroma / max,\n v: max,\n };\n}\n\n/** The sRGB transfer function, gamma-encoded to linear light. */\nfunction toLinear(channel: number): number {\n return channel <= 0.04045\n ? channel / 12.92\n : Math.pow((channel + 0.055) / 1.055, 2.4);\n}\n\n/** The inverse transfer function, linear light back to gamma-encoded. */\nfunction toGamma(channel: number): number {\n return channel <= 0.0031308\n ? channel * 12.92\n : 1.055 * Math.pow(channel, 1 / 2.4) - 0.055;\n}\n\n/**\n * Linear sRGB to OKLab.\n *\n * The two matrices and the cube root between them are the definition of OKLab, given in CSS\n * Color 4. They are transcribed rather than derived.\n */\nfunction linearRgbToOklab(\n r: number,\n g: number,\n b: number\n): [number, number, number] {\n const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;\n const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;\n const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;\n\n const l_ = Math.cbrt(l);\n const m_ = Math.cbrt(m);\n const s_ = Math.cbrt(s);\n\n return [\n 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_,\n 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_,\n 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_,\n ];\n}\n\n/** OKLab back to linear sRGB, the inverse of {@link linearRgbToOklab}. */\nfunction oklabToLinearRgb(\n L: number,\n a: number,\n b: number\n): [number, number, number] {\n const l_ = L + 0.3963377774 * a + 0.2158037573 * b;\n const m_ = L - 0.1055613458 * a - 0.0638541728 * b;\n const s_ = L - 0.0894841775 * a - 1.291485548 * b;\n\n const l = l_ * l_ * l_;\n const m = m_ * m_ * m_;\n const s = s_ * s_ * s_;\n\n return [\n 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,\n -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,\n -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s,\n ];\n}\n\n/**\n * sRGB to OKLCH.\n *\n * @experimental\n */\nexport function rgbToOklch({ r, g, b }: Rgb): Oklch {\n const [L, A, B] = linearRgbToOklab(\n toLinear(clamp01(r)),\n toLinear(clamp01(g)),\n toLinear(clamp01(b))\n );\n const chroma = Math.sqrt(A * A + B * B);\n // Below this the hue angle is numerical noise rather than a colour, so it is reported as 0\n // instead of whatever direction the rounding happened to point.\n const hue =\n chroma < 1e-6 ? 0 : normalizeHue((Math.atan2(B, A) * 180) / Math.PI);\n return { l: L, c: chroma, h: hue };\n}\n\n/** Whether every channel of a linear triple lies within the displayable range. */\nfunction inGamut([r, g, b]: [number, number, number]): boolean {\n // No tolerance at all: the point must be GENUINELY inside the gamut.\n //\n // Any fixed tolerance is eventually comparable to the channel values themselves, because those\n // shrink without bound as lightness falls — 1e-6 broke the hue at l=0.01, and 1e-12 still broke\n // it at l=0.0001. A tolerance exists to absorb the cube roots' error for a colour sitting\n // exactly ON the boundary, and the cost of not absorbing it is that such a colour comes back\n // with its chroma reduced by less than one part in a million, which nothing can display. The\n // cost of absorbing it is a channel that must then be clamped, and clamping is precisely what\n // moves the hue this function promises to keep.\n const epsilon = 0;\n return (\n r >= -epsilon &&\n r <= 1 + epsilon &&\n g >= -epsilon &&\n g <= 1 + epsilon &&\n b >= -epsilon &&\n b <= 1 + epsilon\n );\n}\n\n/**\n * OKLCH to sRGB, reducing chroma until the colour fits on screen.\n * OKLCH can name colours a display cannot show. Clamping the channels independently is the\n * obvious response and the wrong one: clipping red without clipping green changes the ratio\n * between them, so the colour that appears is a DIFFERENT HUE from the one asked for. Lightness\n * and hue are what a person chose; chroma is the part they will not miss, so chroma is what is\n * given up.\n * The search is a bisection on chroma, which converges to well under a perceptible step in the\n * fixed number of rounds below — no loop that might not terminate.\n *\n * **The gamut is not always monotonic along this ray, and that is a deliberate trade.** At some\n * lightness and hue pairs the boundary is crossed more than once: at `l = 0.2, h = 264.1` the ray\n * is inside up to c ≈ 0.1192, outside until c ≈ 0.1368, briefly inside again to c ≈ 0.1386. A\n * bisection therefore finds the FIRST boundary rather than the outermost reachable chroma.\n *\n * That is the intended behaviour rather than a limitation. Those islands span roughly a tenth of\n * a degree of hue, so preferring the outermost value would make chroma jump by about 0.021\n * between h = 264.05 and h = 264.10 — a visible step while dragging a hue slider, over a change\n * no one can aim at. Taking the first boundary gives 0.1160, 0.1175, 0.1192, 0.1255, 0.1383\n * across the same sweep: continuous, and one step less saturated at worst. It is also what the\n * CSS Color 4 gamut-mapping algorithm does.\n *\n * @experimental\n */\nexport function oklchToRgb({ l, c, h }: Oklch): Rgb {\n const lightness = clamp01(l);\n const hueRadians = (normalizeHue(h) * Math.PI) / 180;\n\n const at = (chroma: number): [number, number, number] =>\n oklabToLinearRgb(\n lightness,\n chroma * Math.cos(hueRadians),\n chroma * Math.sin(hueRadians)\n );\n\n const requested = Math.max(0, c);\n let fitting = at(requested);\n\n if (!inGamut(fitting)) {\n let low = 0;\n // Bracketed against an ABSOLUTE ceiling rather than the requested chroma. Halving an\n // unbounded input a fixed number of times converges on a fraction OF THAT INPUT, so a\n // sufficiently large chroma leaves the interval far above the gamut and the search returns\n // zero — discarding the hue entirely and answering grey for a colour that has one. No sRGB\n // colour exceeds a chroma of roughly 0.37, so this ceiling cannot exclude a reachable one.\n let high = Math.min(requested, MAX_SRGB_CHROMA);\n // Halvings of a fixed interval, so the remaining error is absolute: 0.5 / 2^20 is far below\n // anything a screen or an eye resolves.\n for (let i = 0; i < 20; i++) {\n const mid = (low + high) / 2;\n if (inGamut(at(mid))) low = mid;\n else high = mid;\n }\n fitting = at(low);\n }\n\n return {\n r: clamp01(toGamma(fitting[0])),\n g: clamp01(toGamma(fitting[1])),\n b: clamp01(toGamma(fitting[2])),\n };\n}\n","/**\n * Hex is the notation people type, so it is the picker's front door.\n *\n * It lives beside the conversions rather than in the component that reads it, for the same reason\n * they do: parsing `#3b82f6` is arithmetic on a string, a server rendering a token swatch needs it\n * as much as an editing surface does, and pulling it into client code would put it behind the\n * `\"use client\"` boundary for no benefit.\n *\n * @module lib/color/hex\n */\n\nimport type { Rgb } from \"./convert\";\n\n/**\n * An sRGB colour with its alpha, which is what a hex string can carry and {@link Rgb} cannot.\n *\n * `alpha` is in [0, 1] like the channels, rather than 0-255, so it composes with the conversions\n * without a second unit in play.\n *\n * @experimental\n */\nexport interface Rgba extends Rgb {\n alpha: number;\n}\n\n/** `#rgb`, `#rgba`, `#rrggbb` or `#rrggbbaa`, with the hash optional and case ignored. */\nconst HEX = /^#?(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;\n\nconst clamp01 = (n: number): number => (n < 0 ? 0 : n > 1 ? 1 : n);\n\n/** A channel byte as a two-digit lowercase pair. */\nfunction pair(channel: number): string {\n // A non-finite channel becomes 0 rather than passing through. `clamp01(NaN)` is NaN, because\n // both of its comparisons are false, and formatting that yields the three characters \"NaN\" —\n // producing `#NaN0000`, which is exactly the string this module documents itself as never\n // returning.\n const value = Number.isFinite(channel) ? clamp01(channel) : 0;\n return Math.round(value * 255)\n .toString(16)\n .padStart(2, \"0\");\n}\n\n/**\n * Read a hex colour, or `null` if the input is not one.\n *\n * Returns `null` rather than throwing or substituting black: this reads what someone is part-way\n * through typing, where \"not a colour yet\" is the ordinary case and neither an exception nor a\n * silent black is a useful answer. A caller decides whether to hold the last good value, show a\n * message, or wait.\n *\n * Both short forms are accepted because both are what people paste. `#abc` expands by REPEATING\n * each digit rather than padding with zero — `#abc` is `#aabbcc`, not `#a0b0c0` — which is what CSS\n * does and the only expansion under which `#fff` is white.\n *\n * @experimental\n */\nexport function parseHex(input: string): Rgba | null {\n const text = input.trim();\n if (!HEX.test(text)) return null;\n\n const digits = text.replace(\"#\", \"\");\n const short = digits.length < 6;\n const size = short ? 1 : 2;\n const channel = (index: number): number => {\n const slice = digits.slice(index * size, index * size + size);\n return parseInt(short ? slice + slice : slice, 16) / 255;\n };\n\n const hasAlpha = digits.length === 4 || digits.length === 8;\n return {\n r: channel(0),\n g: channel(1),\n b: channel(2),\n alpha: hasAlpha ? channel(3) : 1,\n };\n}\n\n/**\n * Write a colour as `#rrggbb`, or `#rrggbbaa` when it is not fully opaque.\n *\n * The alpha pair is omitted at 1 rather than always written, because `#3b82f6ff` is the same colour\n * and the shorter form is what someone expects to see in a field they typed `#3b82f6` into.\n *\n * Channels outside [0, 1] are clamped, so the result is always a valid six- or eight-digit hex\n * string whatever a caller passes. Not for floating-point drift, which rounds to the right byte on\n * its own: it is for a value that is wrong by a lot — a channel still in 0-255, or a computation\n * that overshot — where the alternative is emitting `#17f00-80`, a string nothing downstream can\n * parse and no error explains.\n *\n * @experimental\n */\nexport function toHex(color: Rgb, alpha = 1): string {\n // A non-finite alpha falls back to 1, not to 0 as a channel does. Both are \"nothing was\n // specified\", and for alpha that is this parameter's own default — where treating it as 0 would\n // turn a colour invisible on a stray NaN, silently and with no way to tell from the output.\n const opacity = Number.isFinite(alpha) ? clamp01(alpha) : 1;\n const opaque = `#${pair(color.r)}${pair(color.g)}${pair(color.b)}`;\n return opacity === 1 ? opaque : `${opaque}${pair(opacity)}`;\n}\n","/**\n * The mapping between a pointer on a picker surface and a colour.\n *\n * Kept apart from the component for two reasons. It is arithmetic on numbers,\n * so it belongs on the server-safe side with the rest of `@nextlyhq/ui/color`;\n * and a saturation square is the one part of a picker that cannot be checked by\n * rendering it — jsdom reports every element as zero-sized, so a component test\n * measures nothing and passes. Measured here instead, against known corners.\n *\n * @module lib/color/picker-geometry\n */\n\n/** A position on a surface, each axis in [0, 1] from the top-left. */\nexport interface SurfacePoint {\n x: number;\n y: number;\n}\n\nconst clamp01 = (n: number): number => (n < 0 ? 0 : n > 1 ? 1 : n);\n\n/**\n * A pointer position as a fraction of a surface.\n *\n * Clamped, because a drag that begins inside the surface continues to report\n * while the pointer leaves it — which is the interaction people actually use to\n * reach full saturation, and without clamping it produces values outside the\n * colour space rather than the corner they are aiming at.\n *\n * A zero-sized surface answers the top-left rather than dividing by zero. That\n * happens in a test environment and on the first frame before layout.\n *\n * @experimental\n */\nexport function pointOnSurface(\n clientX: number,\n clientY: number,\n rect: { left: number; top: number; width: number; height: number }\n): SurfacePoint {\n return {\n x: rect.width === 0 ? 0 : clamp01((clientX - rect.left) / rect.width),\n y: rect.height === 0 ? 0 : clamp01((clientY - rect.top) / rect.height),\n };\n}\n\n/**\n * The saturation and value a point on the square stands for.\n *\n * Value runs UPWARD while a surface's y runs downward, so the vertical axis is\n * inverted here. Getting that wrong produces a picker that looks correct and\n * selects the colour vertically mirrored from the one under the cursor.\n *\n * @experimental\n */\nexport function saturationValueAt(point: SurfacePoint): {\n s: number;\n v: number;\n} {\n return { s: clamp01(point.x), v: 1 - clamp01(point.y) };\n}\n\n/**\n * Where the handle sits for a given saturation and value — the inverse of\n * {@link saturationValueAt}.\n *\n * Derived from that function's own inversion rather than written independently,\n * so the two cannot disagree about which way the axis runs.\n *\n * @experimental\n */\nexport function surfacePointFor(s: number, v: number): SurfacePoint {\n return { x: clamp01(s), y: 1 - clamp01(v) };\n}\n\n/**\n * The hue a horizontal position stands for, in [0, 360).\n *\n * The upper bound is exclusive: 360 and 0 are the same hue, and returning 360\n * lets a handle at the far end read back as a position outside the strip.\n *\n * @experimental\n */\nexport function hueAt(fraction: number): number {\n const hue = clamp01(fraction) * 360;\n return hue >= 360 ? 0 : hue;\n}\n\n/** Where the hue handle sits, as a fraction of the strip. @experimental */\nexport function huePosition(hue: number): number {\n const wrapped = ((hue % 360) + 360) % 360;\n return wrapped / 360;\n}\n\n/**\n * The integer step a hue occupies on a strip whose last step is `max`.\n *\n * Rounding is what makes this more than a multiplication. A hue just below 360\n * — `#ff0001` is about 359.76 — rounds UP to a step past the end of the strip,\n * and the obvious repair of wrapping it with a modulo sends it to 0: the far\n * LEFT, the opposite end from where that colour belongs. The handle then sits\n * on the wrong side and any keyboard adjustment starts from there. Held at the\n * last step instead, which is where it visually belongs.\n *\n * @experimental\n */\nexport function hueSliderValue(hue: number, max: number): number {\n const step = Math.round(huePosition(hue) * (max + 1));\n return step > max ? max : step;\n}\n","import * as React from \"react\";\n\n/**\n * A layout effect in the browser, a plain effect where there is no DOM.\n *\n * These components are client code, but a consumer may still PRERENDER them,\n * and React warns that `useLayoutEffect` does nothing on the server. Layout\n * timing is what the browser needs wherever an effect has to be settled before\n * anything else can observe it — a registration that must exist before the\n * first frame, or a native listener that must be the current one before the\n * next event reaches it. Neither effect runs during a server render, so\n * choosing between them by environment loses nothing and silences a warning\n * that reports no real problem.\n *\n * Published rather than kept beside its first caller, because a second one\n * arrived: two spellings of this choice would drift the first time either\n * learned something about a new environment. A third now lives in another\n * package, which is why it leaves this one through the barrel.\n *\n * @experimental\n */\nexport const useIsomorphicLayoutEffect =\n typeof document === \"undefined\" ? React.useEffect : React.useLayoutEffect;\n","/**\n * ContextMenu Component\n *\n * A right-click menu built on Radix UI primitives. Same surface, items and keyboard model as\n * `DropdownMenu`; what differs is how it opens — a pointer's secondary button, a long press on\n * touch, or the platform's context-menu key — and that it opens AT the pointer rather than\n * anchored to a trigger element.\n *\n * **Why a separate component rather than a `DropdownMenu` with a different trigger**: the two\n * have different anchoring (a virtual point versus an element), different open semantics, and\n * different ARIA. Radix models them separately for that reason, and collapsing them would mean\n * reimplementing one of the two behaviours by hand.\n *\n * **Design specifications** (shared with `DropdownMenu`, so a right-click menu and a button menu\n * cannot drift apart):\n * - Border-radius: `rounded-lg` for the surface, `rounded-sm` for items\n * - Padding: 4px (p-1); item padding 8px horizontal, 6px vertical\n * - Shadow: `shadow-md`; z-index `z-50`; min-width 8rem\n * - Highlight: `bg-muted`, driven off `data-[highlighted]` so pointer and keyboard agree\n *\n * **Accessibility**:\n * - Opens on the context-menu event, so the keyboard route (Shift+F10, or the menu key) reaches\n * it — but only once the trigger can hold focus. Radix wires the event handlers onto whatever\n * `asChild` is given and does not make it focusable, so a plain `div` trigger is reachable by\n * pointer only. Use an already-focusable element, or give it `tabIndex` and a role, as the\n * example below does\n * - Full keyboard navigation (arrows, Enter, Escape, Home/End, typeahead)\n * - ARIA roles from Radix: `menu`, `menuitem`, `menuitemcheckbox`, `menuitemradio`\n * - Focus returns to the element that opened the menu on close\n *\n * **Portalling**: content renders into the container from `PortalProvider`, like every other\n * overlay in this kit. The scoped stylesheet only reaches inside `.nextly-ui`, and an overlay\n * portalled to `document.body` is outside it, so the provider is what keeps it styled.\n *\n * @example\n * ```tsx\n * <ContextMenu>\n * <ContextMenuTrigger asChild>\n * <div className=\"p-8\" tabIndex={0} role=\"group\" aria-label=\"Canvas\">\n * Right-click anywhere in here\n * </div>\n * </ContextMenuTrigger>\n * <ContextMenuContent>\n * <ContextMenuItem onSelect={duplicate}>Duplicate</ContextMenuItem>\n * <ContextMenuItem onSelect={remove}>Delete</ContextMenuItem>\n * <ContextMenuSeparator />\n * <ContextMenuCheckboxItem checked={locked} onCheckedChange={setLocked}>\n * Locked\n * </ContextMenuCheckboxItem>\n * </ContextMenuContent>\n * </ContextMenu>\n * ```\n *\n * @module\n */\n\n\"use client\";\n\nimport * as ContextMenuPrimitive from \"@radix-ui/react-context-menu\";\nimport { Check, ChevronRight, Circle } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\nimport { usePortalContainer } from \"../providers/portal-provider\";\n\n/**\n * The item highlight, taken from the same reasoning as `DropdownMenu`: Radix sets\n * `data-highlighted` for both pointer hover and keyboard focus, so driving the highlight off\n * that one state keeps the two in sync, and `bg-muted` reads against the popover surface\n * without the full-contrast flip a solid `bg-primary` produces.\n */\nconst menuItemBase =\n \"cursor-pointer transition-colors data-[highlighted]:bg-muted data-[highlighted]:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\";\n\n/**\n * The popover surface, shared by the root menu and every submenu.\n *\n * Shared rather than repeated because the two drifted once already: the submenu was written with\n * `overflow-hidden` and no height bound, so a long one near the edge of the viewport clipped with\n * nothing to scroll. A submenu opens beside its parent item, further down the screen with less\n * room left than the menu that spawned it, so it needs the bound at least as much.\n *\n * The available-height variable is what supplies that bound: Radix measures the space the surface\n * actually has and publishes it, so the menu scrolls instead of overflowing the viewport.\n */\nconst menuSurface =\n \"z-50 max-h-[var(--radix-context-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 origin-[--radix-context-menu-content-transform-origin]\";\n\n/** @experimental */\nconst ContextMenu = ContextMenuPrimitive.Root;\n\n/** @experimental */\nconst ContextMenuTrigger = ContextMenuPrimitive.Trigger;\n\n/** @experimental */\nconst ContextMenuGroup = ContextMenuPrimitive.Group;\n\n/** @experimental */\nconst ContextMenuSub = ContextMenuPrimitive.Sub;\n\n/** @experimental */\nconst ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;\n\n/** @experimental */\nconst ContextMenuSubTrigger = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {\n inset?: boolean;\n }\n>(({ className, inset, children, ...props }, ref) => (\n <ContextMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n \"flex select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-muted [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n menuItemBase,\n inset && \"pl-8\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto\" />\n </ContextMenuPrimitive.SubTrigger>\n));\nContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;\n\n/** @experimental */\nconst ContextMenuSubContent = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => {\n const portalContainer = usePortalContainer();\n\n return (\n <ContextMenuPrimitive.Portal container={portalContainer}>\n <ContextMenuPrimitive.SubContent\n ref={ref}\n className={cn(menuSurface, className)}\n {...props}\n />\n </ContextMenuPrimitive.Portal>\n );\n});\nContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;\n\n/** @experimental */\nconst ContextMenuContent = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>\n>(({ className, ...props }, ref) => {\n const portalContainer = usePortalContainer();\n\n return (\n <ContextMenuPrimitive.Portal container={portalContainer}>\n <ContextMenuPrimitive.Content\n ref={ref}\n className={cn(menuSurface, className)}\n {...props}\n />\n </ContextMenuPrimitive.Portal>\n );\n});\nContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;\n\n/** @experimental */\nconst ContextMenuItem = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <ContextMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n menuItemBase,\n inset && \"pl-8\",\n className\n )}\n {...props}\n />\n));\nContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;\n\n/** @experimental */\nconst ContextMenuCheckboxItem = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <ContextMenuPrimitive.CheckboxItem\n ref={ref}\n className={cn(\n \"relative flex select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none\",\n menuItemBase,\n className\n )}\n checked={checked}\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));\nContextMenuCheckboxItem.displayName =\n ContextMenuPrimitive.CheckboxItem.displayName;\n\n/** @experimental */\nconst ContextMenuRadioItem = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <ContextMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"relative flex select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none\",\n menuItemBase,\n className\n )}\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));\nContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;\n\n/** @experimental */\nconst ContextMenuLabel = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <ContextMenuPrimitive.Label\n ref={ref}\n className={cn(\n \"px-2 py-1.5 text-sm font-semibold text-foreground\",\n inset && \"pl-8\",\n className\n )}\n {...props}\n />\n));\nContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;\n\n/** @experimental */\nconst ContextMenuSeparator = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <ContextMenuPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-border\", className)}\n {...props}\n />\n));\nContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;\n\n/**\n * A keyboard shortcut hint, right-aligned in the item.\n *\n * @experimental\n */\nconst ContextMenuShortcut = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => (\n <span\n className={cn(\n \"ml-auto text-xs tracking-widest text-muted-foreground\",\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 ContextMenuRadioGroup,\n ContextMenuRadioItem,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n};\n","/**\n * Resizable panel group\n *\n * Side-by-side or stacked regions whose sizes the user can drag, built on `react-resizable-panels`.\n * An editor shell is exactly this: a rail, a canvas and an inspector, each of which someone will\n * want wider than we chose for them.\n *\n * **Why a library rather than a drag handler**: the hard parts of a splitter are not the drag.\n * They are the keyboard model (the APG window-splitter pattern — arrows resize, Home and End go\n * to the extremes), collapse-and-restore, minimum sizes that survive a window resize, and nested\n * groups. `react-resizable-panels` implements all of them, and is the library the wider React\n * ecosystem settled on for this control.\n *\n * **Sizes are relative, not pixels.** A layout stored in pixels is wrong on the next monitor; one\n * stored proportionally survives a window resize. Persisting a shell layout is the caller's to\n * store wherever it already keeps preferences — this kit does not reach for browser storage on\n * their behalf.\n *\n * The two size props are not the same shape, which is easy to get wrong in both directions:\n * `defaultLayout` is a map of panel id to a **number** (a flex-grow weight, conventionally read as\n * a percentage by making them sum to 100), while per-panel bounds such as `minSize` take a CSS\n * **string** like `\"15%\"`. Handing `defaultLayout` strings is a type error, and a JavaScript\n * caller who does it stores a layout the library cannot restore.\n *\n * Persist from **`onLayoutChanged`**, not `onLayoutChange`: the first fires once the drag has\n * settled, the second fires continuously while the pointer moves. Writing on every frame of a\n * drag thrashes whatever is behind it, which for a remote preference store means a request per\n * frame.\n *\n * **Design specifications**:\n * - Handle: 1px visible line in `bg-border`, with a larger invisible hit area around it\n * - Grip: optional 3x4 handle in `bg-border`, `rounded-sm`, for discoverability\n * - Focus: `focus-visible` ring in the focus token, because a splitter is keyboard-operable\n *\n * **Accessibility**:\n * - The handle is a `separator` with `aria-valuenow`/`aria-valuemin`/`aria-valuemax`, supplied by\n * the library, so a screen reader announces the split as a percentage\n * - Its accessible NAME is required by the type, because the library supplies everything except\n * that: a focusable separator with a position and no name announces \"74\" and leaves a keyboard\n * user to guess what is at 74. Only the caller knows what the two panels hold\n * - Arrow keys resize, Home/End collapse and expand, Enter toggles a collapsible panel\n * - The hit area is larger than the visible line, so the target is reachable without precision\n * pointing (WCAG 2.5.8 Target Size)\n *\n * @example\n * ```tsx\n * <ResizablePanelGroup\n * orientation=\"horizontal\"\n * defaultLayout={{ layers: 20, canvas: 55, inspector: 25 }}\n * onLayoutChanged={saveLayout}\n * >\n * <ResizablePanel id=\"layers\" minSize=\"15%\" collapsible>\n * <LayersPanel />\n * </ResizablePanel>\n * <ResizableHandle withGrip aria-label=\"Layers and canvas\" />\n * <ResizablePanel id=\"canvas\">\n * <Canvas />\n * </ResizablePanel>\n * <ResizableHandle withGrip aria-label=\"Canvas and inspector\" />\n * <ResizablePanel id=\"inspector\" minSize=\"20%\">\n * <Inspector />\n * </ResizablePanel>\n * </ResizablePanelGroup>\n * ```\n *\n * @module\n */\n\n\"use client\";\n\nimport { GripVertical } from \"lucide-react\";\nimport type * as React from \"react\";\nimport * as ResizablePrimitive from \"react-resizable-panels\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * A splitter's accessible name, which the caller must supply one way or the\n * other.\n *\n * REQUIRED rather than documented, because the handle is focusable: a keyboard\n * user lands on it whether or not anyone remembered, and an unnamed separator\n * announces its position — \"74\" — with nothing saying what is at 74. The\n * caller is the only one who can name it, since only the caller knows what the\n * two panels hold, so the type is the only place the requirement can live.\n *\n * Either attribute satisfies it and neither may be paired with the other: two\n * names on one element is not a stronger label, it is an ambiguity resolved by\n * precedence rules nobody writing the call site is thinking about.\n */\ntype SplitterName =\n | { \"aria-label\": string; \"aria-labelledby\"?: never }\n | { \"aria-labelledby\": string; \"aria-label\"?: never };\n\n/**\n * A group of resizable panels, laid out horizontally or vertically.\n *\n * @experimental\n */\nconst ResizablePanelGroup = ({\n className,\n ...props\n}: React.ComponentProps<typeof ResizablePrimitive.Group>) => (\n <ResizablePrimitive.Group\n className={cn(\"h-full w-full\", className)}\n {...props}\n />\n);\n\n/**\n * One region of a panel group.\n *\n * @experimental\n */\nconst ResizablePanel = ResizablePrimitive.Panel;\n\n/**\n * The draggable divider between two panels.\n *\n * The visible line is 1px; the element around it is wider and transparent, so the pointer target\n * is comfortably larger than the line it appears to grab. `withGrip` adds a visible handle, which\n * is worth it on a divider people are meant to discover rather than one they already expect.\n *\n * @experimental\n */\nconst ResizableHandle = ({\n withGrip,\n className,\n children,\n ...props\n}: Omit<\n React.ComponentProps<typeof ResizablePrimitive.Separator>,\n \"aria-label\" | \"aria-labelledby\"\n> &\n SplitterName & {\n withGrip?: boolean;\n }) => (\n <ResizablePrimitive.Separator\n className={cn(\n // The drawn line is 1px; the element around it is wider and transparent, so the pointer\n // target is comfortably larger than what it appears to grab (WCAG 2.5.8).\n \"relative flex items-center justify-center bg-border\",\n // Keyed off `aria-orientation`, which is what the separator actually carries, and read as\n // the ARIA spec defines it: the attribute describes the SEPARATOR, not the group. A\n // horizontal group puts its panels side by side, so its separator is a vertical line.\n \"aria-[orientation=vertical]:w-px aria-[orientation=horizontal]:h-px\",\n \"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background\",\n // Reachable without precision pointing, without drawing a heavier divider: the hit area\n // grows across the line, so a vertical line widens and a horizontal one deepens.\n \"after:absolute after:inset-0\",\n \"aria-[orientation=vertical]:after:-inset-x-1 aria-[orientation=horizontal]:after:-inset-y-1\",\n className\n )}\n {...props}\n >\n {withGrip ? (\n <div className=\"z-10 flex h-4 w-3 items-center justify-center rounded-sm border border-border bg-border\">\n <GripVertical className=\"h-2.5 w-2.5 text-muted-foreground\" />\n </div>\n ) : null}\n {children}\n </ResizablePrimitive.Separator>\n);\n\nexport { ResizableHandle, ResizablePanel, ResizablePanelGroup };\n","/**\n * TreeView\n *\n * A keyboard-operable, virtualized tree. The layers panel of an editor is this control: a\n * hierarchy that can hold thousands of nodes, that someone navigates with arrow keys as much as\n * with a pointer, and that has to stay responsive while they do.\n *\n * **Why virtualized, and why that decides the markup.** A document of a few thousand blocks\n * renders a few thousand rows, and the cost is not the React work — it is layout and paint on\n * every expand, scroll and selection. Only the visible window is rendered here.\n *\n * That has a consequence the accessibility notes below depend on: with only a window in the DOM,\n * the nested `role=\"group\"` markup the tree pattern usually uses **cannot be built**, because an\n * item's children may not be rendered at all. The APG covers this exact case by allowing a FLAT\n * set of `treeitem`s that describe the hierarchy through `aria-level`, `aria-setsize` and\n * `aria-posinset` instead of through nesting. A screen reader reads depth and position from those\n * attributes, so they are not decoration — without them a virtualized tree announces itself as a\n * flat list of whatever happens to be on screen.\n *\n * **Why a headless virtualizer.** The markup above is the requirement, so anything that owns the\n * DOM is unusable. `@tanstack/react-virtual` computes offsets and renders nothing.\n *\n * **State is controllable, not controlled.** `expandedIds`/`selectedId` may be passed with their\n * `onChange` partners to drive the tree from a store — which an editor will do, since selection is\n * shared with the canvas and the inspector — or omitted entirely, in which case the tree keeps its\n * own. Requiring a store for a tree in a settings dialog would be a poor trade.\n *\n * **Design specifications**:\n * - Row height: fixed 28px (`--tree-row`), so the virtualizer needs no measurement pass\n * - Indent: 12px per level, applied as padding so the whole row stays a hit target\n * - Selection: `bg-muted`, matching the menu highlight rather than a full-contrast flip\n * - Focus: `focus-visible` ring in the focus token\n *\n * **Accessibility**:\n * - `role=\"tree\"` with flat `role=\"treeitem\"` children carrying `aria-level`, `aria-setsize`,\n * `aria-posinset`, and `aria-expanded` on anything with children\n * - Roving tabindex: exactly one row is in the tab order, so Tab enters and leaves the tree once\n * rather than walking every node\n * - Arrow keys move and expand, per the APG tree pattern: Right expands then descends, Left\n * collapses then ascends, Home/End jump to the ends, `*` expands every sibling\n * - Typeahead focuses the next row whose label starts with what was typed\n * - Moving focus scrolls the row into view, which virtualization would otherwise prevent: a row\n * outside the window has no element to focus\n *\n * @example\n * ```tsx\n * <TreeView\n * nodes={layers}\n * aria-label=\"Layers\"\n * selectedId={selected}\n * onSelectedChange={setSelected}\n * className=\"h-full\"\n * />\n * ```\n *\n * @module\n */\n\n\"use client\";\n\nimport { useVirtualizer } from \"@tanstack/react-virtual\";\nimport { ChevronRight } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/**\n * One node of the tree. Children are omitted or empty for a leaf.\n *\n * @experimental\n */\nexport interface TreeNode {\n /** Stable identity. What selection and expansion are keyed by. */\n id: string;\n /** What the row shows. A string also feeds typeahead; anything else needs `textValue`. */\n label: React.ReactNode;\n /**\n * The text typeahead matches on, when `label` is not a string.\n *\n * Without it a row rendered as markup cannot be typed to, and a keyboard user loses the fastest\n * way through a long tree.\n */\n textValue?: string;\n /** Children, if any. An empty array still marks the node as a parent. */\n children?: readonly TreeNode[];\n /** Shown before the label, after the twisty. */\n icon?: React.ReactNode;\n /** Skipped by every keyboard move and not selectable. */\n disabled?: boolean;\n}\n\n/** A node flattened into a row, carrying what the ARIA attributes need. */\ninterface TreeRow {\n node: TreeNode;\n /** Depth from the root, zero-based. `aria-level` is this plus one. */\n level: number;\n /** How many siblings share this position, for `aria-setsize`. */\n setSize: number;\n /** Position among those siblings, zero-based. `aria-posinset` is this plus one. */\n posInSet: number;\n /** The parent row's id, for the Left-arrow move. */\n parentId?: string;\n hasChildren: boolean;\n}\n\nconst ROW_HEIGHT = 28;\nconst INDENT_PER_LEVEL = 12;\n\n/** The text a row can be typed to, falling back to a string label. */\nfunction textOf(node: TreeNode): string {\n if (typeof node.textValue === \"string\") return node.textValue;\n return typeof node.label === \"string\" ? node.label : \"\";\n}\n\n/**\n * The visible rows, in the order they are shown.\n *\n * Only expanded branches are walked, so a collapsed subtree of ten thousand nodes costs nothing —\n * which is the other half of why this scales, and the half virtualization does not give you.\n */\nfunction flatten(\n nodes: readonly TreeNode[],\n expanded: ReadonlySet<string>\n): TreeRow[] {\n const rows: TreeRow[] = [];\n // An explicit stack rather than recursion, so depth costs heap instead of call frames. A\n // document that is one long expanded chain would otherwise overflow the JavaScript stack before\n // the virtualizer ever got to window it — this control failing on the one shape virtualization\n // does not already help with.\n const pending: {\n list: readonly TreeNode[];\n index: number;\n level: number;\n parentId?: string;\n }[] = [{ list: nodes, index: 0, level: 0 }];\n\n while (pending.length > 0) {\n const frame = pending[pending.length - 1];\n if (frame === undefined || frame.index >= frame.list.length) {\n pending.pop();\n continue;\n }\n const node = frame.list[frame.index];\n const posInSet = frame.index;\n frame.index += 1;\n if (node === undefined) continue;\n // Any declared children array marks a branch, empty or not. A folder that is empty, or\n // whose contents have not loaded, is still something to expand — and the exported contract\n // says so, so reading length here would quietly contradict it.\n const hasChildren = node.children !== undefined;\n rows.push({\n node,\n level: frame.level,\n setSize: frame.list.length,\n posInSet,\n parentId: frame.parentId,\n hasChildren,\n });\n if (hasChildren && expanded.has(node.id)) {\n pending.push({\n list: node.children ?? [],\n index: 0,\n level: frame.level + 1,\n parentId: node.id,\n });\n }\n }\n return rows;\n}\n\n/**\n * State the caller may own, or may leave to the component.\n *\n * Which of the two it is has to be decided once and kept: a prop that starts defined and later\n * goes undefined releases control, and the internal state behind it is still at its initial\n * value, so expansion or selection jumps back to the default. Mirroring the controlled value into\n * the internal one on every render would fix the jump and cost a render loop for an array prop\n * built inline, which is the normal way to pass one.\n *\n * So switching is unsupported, the way React treats a controlled input that loses its value.\n * Being explicit about that beats a mechanism that works until the render it does not.\n */\nfunction useControllable<T>(\n controlled: T | undefined,\n fallback: T\n): [T, React.Dispatch<React.SetStateAction<T>>] {\n const [uncontrolled, setUncontrolled] = React.useState(fallback);\n return [\n controlled === undefined ? uncontrolled : controlled,\n setUncontrolled,\n ];\n}\n\n/**\n * Which gesture a row's modifiers meant.\n *\n * Named by the same three words the rest of the system uses, so a caller maps\n * them onto its own selection rules without translating. Both Meta and Control\n * mean toggle: a Mac author presses Command and a Windows author presses\n * Control, and neither ever presses the other's.\n *\n * Shift outranks the toggle modifier — a shift+mod click is a slip rather than\n * a fourth gesture, and extending is the one whose result is visible and undone\n * by a plain click.\n *\n * @experimental\n */\nexport type TreeSelectionMode = \"replace\" | \"toggle\" | \"extend\";\n\n/**\n * Read the gesture from the event that carried it.\n *\n * @experimental\n */\nexport function treeSelectionMode(modifiers: {\n shiftKey: boolean;\n metaKey: boolean;\n ctrlKey: boolean;\n}): TreeSelectionMode {\n if (modifiers.shiftKey) return \"extend\";\n if (modifiers.metaKey || modifiers.ctrlKey) return \"toggle\";\n return \"replace\";\n}\n\n/**\n * Whether a row is in the selection at all.\n *\n * A helper rather than an expression inside the render, so the multi-select\n * branch is one call there instead of a condition — a small edit to a large\n * function is what pushes it across a complexity threshold.\n *\n * `selectedIds` when the caller owns a set, the single id otherwise, so a\n * caller that has not adopted the set keeps exactly the behaviour it had.\n *\n * @experimental\n */\nexport function isRowSelected(\n id: string,\n primary: string | null | undefined,\n selectedIds: readonly string[] | undefined\n): boolean {\n return selectedIds === undefined ? primary === id : selectedIds.includes(id);\n}\n\n/** @experimental */\nexport interface TreeViewProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, \"onSelect\"> {\n /** The roots of the tree. */\n nodes: readonly TreeNode[];\n /** Expanded node ids, if the caller owns them. */\n expandedIds?: readonly string[];\n /** Which ids start expanded when the caller does not own expansion. */\n defaultExpandedIds?: readonly string[];\n /** Called with the full next set whenever a branch opens or closes. */\n onExpandedChange?: (ids: string[]) => void;\n /**\n * The selected node id, if the caller owns it.\n *\n * With `selectedIds` also supplied this is the PRIMARY — the row a detail\n * panel answers for. Drawn at a heavier weight so a reader can tell which\n * member of a multi-row selection the rest of the screen describes.\n */\n selectedId?: string | null;\n /**\n * Every selected id, when the caller holds more than one.\n *\n * Additive: omit it and the tree behaves exactly as it did. Supplying it also\n * makes the tree announce itself as `aria-multiselectable`, which is why it\n * is a separate prop rather than inferred — a single-select tree claiming to\n * be multi-selectable is wrong in a way a screen-reader user acts on.\n */\n selectedIds?: readonly string[];\n /** Which id starts selected when the caller does not own selection. */\n defaultSelectedId?: string | null;\n /** Called when a row is chosen, by pointer or by Enter. */\n onSelectedChange?: (id: string, mode: TreeSelectionMode) => void;\n /**\n * Names the tree for a screen reader. One of this or `aria-labelledby` is required: a tree\n * announced only as \"tree\" tells a user nothing about which one they are in.\n */\n \"aria-label\"?: string;\n}\n\n/**\n * A virtualized tree.\n *\n * @experimental\n */\nconst TreeView = React.forwardRef<HTMLDivElement, TreeViewProps>(\n (\n {\n nodes,\n expandedIds,\n defaultExpandedIds,\n onExpandedChange,\n selectedId,\n selectedIds,\n defaultSelectedId,\n onSelectedChange,\n className,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n ...props\n },\n forwardedRef\n ) => {\n const scrollRef = React.useRef<HTMLDivElement | null>(null);\n // The forwarded ref goes to the SCROLL container, not to the element carrying the role. That\n // is the one a caller measures or calls `scrollTo` on; the inner element is a sized spacer\n // and scrolling it does nothing.\n const attachScroll = React.useCallback(\n (node: HTMLDivElement | null) => {\n scrollRef.current = node;\n if (typeof forwardedRef === \"function\") forwardedRef(node);\n else if (forwardedRef !== null && forwardedRef !== undefined) {\n forwardedRef.current = node;\n }\n },\n [forwardedRef]\n );\n const [expandedState, setExpandedState] = useControllable(\n expandedIds === undefined ? undefined : [...expandedIds],\n [...(defaultExpandedIds ?? [])]\n );\n const expanded = React.useMemo(\n () => new Set(expandedIds ?? expandedState),\n [expandedIds, expandedState]\n );\n const [selected, setSelected] = useControllable(\n selectedId === undefined ? undefined : selectedId,\n defaultSelectedId ?? null\n );\n\n const rows = React.useMemo(\n () => flatten(nodes, expanded),\n [nodes, expanded]\n );\n\n // Which row holds the tab stop. Kept as an id rather than an index so that expanding a branch\n // above it does not silently move the tab stop to a different node.\n const [activeId, setActiveId] = React.useState<string | null>(null);\n const activeIndex = Math.max(\n 0,\n rows.findIndex(row => row.node.id === (activeId ?? selected))\n );\n\n const virtualizer = useVirtualizer({\n count: rows.length,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => ROW_HEIGHT,\n overscan: 8,\n });\n\n const commitExpanded = (next: Set<string>): void => {\n const ids = [...next];\n if (expandedIds === undefined) setExpandedState(ids);\n onExpandedChange?.(ids);\n };\n\n const setExpansion = (id: string, open: boolean): void => {\n const next = new Set(expanded);\n if (open) next.add(id);\n else next.delete(id);\n commitExpanded(next);\n };\n\n const choose = (id: string, mode: TreeSelectionMode = \"replace\"): void => {\n // The uncontrolled fallback tracks the PRIMARY only. A caller wanting a\n // set owns it; inventing a default set here would give an uncontrolled\n // tree a selection its caller never sees.\n if (selectedId === undefined) setSelected(id);\n onSelectedChange?.(id, mode);\n };\n\n /**\n * Move the tab stop, and bring the row into view.\n *\n * The scroll is not a nicety: a row outside the rendered window has no element, so focusing it\n * would do nothing at all and the arrow key would appear dead.\n */\n const focusRow = (index: number): void => {\n const row = rows[index];\n if (row === undefined) return;\n setActiveId(row.node.id);\n virtualizer.scrollToIndex(index, { align: \"auto\" });\n // After the scroll the row may have only just been rendered, so the element is looked up on\n // the next frame rather than now.\n requestAnimationFrame(() => {\n const element = scrollRef.current?.querySelector<HTMLElement>(\n `[data-tree-index=\"${index}\"]`\n );\n element?.focus();\n });\n };\n\n /** The next row that is not disabled, in the given direction. */\n const step = (from: number, delta: number): number => {\n for (\n let index = from + delta;\n index >= 0 && index < rows.length;\n index += delta\n ) {\n if (rows[index]?.node.disabled !== true) return index;\n }\n return from;\n };\n\n const typeahead = React.useRef({ query: \"\", at: 0 });\n\n const onKeyDown = (event: React.KeyboardEvent<HTMLDivElement>): void => {\n const index = activeIndex;\n const row = rows[index];\n if (row === undefined) return;\n\n /*\n * Alt belongs to the HOST, so nothing here claims it.\n *\n * The tree pattern uses bare arrows to move, Shift to extend and Ctrl to\n * toggle; Alt appears nowhere in it, which leaves the chord free for\n * whatever embeds the tree. A host that binds one — `alt+ArrowUp` to\n * reorder, say — otherwise loses it exactly where the author is most\n * likely to press it, because the switch below reads `event.key` and\n * `ArrowUp` is `ArrowUp` whatever modifiers are down. The row then takes\n * focus, calls `preventDefault`, and the host's binding never fires.\n *\n * Returning WITHOUT `preventDefault` is the whole point: the event has to\n * go on bubbling for the host to see it.\n */\n if (event.altKey) return;\n\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n focusRow(step(index, 1));\n return;\n case \"ArrowUp\":\n event.preventDefault();\n focusRow(step(index, -1));\n return;\n case \"ArrowRight\":\n event.preventDefault();\n // Expand first, descend second. Pressing Right twice on a closed branch opens it and\n // then enters it, which is what the pattern asks for and what people expect.\n if (row.hasChildren && !expanded.has(row.node.id)) {\n setExpansion(row.node.id, true);\n } else if (row.hasChildren) {\n // Bounded to this row's own children. `step` searches the whole flattened tree, so an\n // expanded branch that is empty — or holds only disabled rows — would send focus to\n // whatever came next in the document instead of staying put.\n for (\n let child = index + 1;\n child < rows.length && (rows[child]?.level ?? 0) > row.level;\n child += 1\n ) {\n if (\n rows[child]?.parentId === row.node.id &&\n rows[child]?.node.disabled !== true\n ) {\n focusRow(child);\n break;\n }\n }\n }\n return;\n case \"ArrowLeft\":\n event.preventDefault();\n if (row.hasChildren && expanded.has(row.node.id)) {\n setExpansion(row.node.id, false);\n } else if (row.parentId !== undefined) {\n // Climb past a disabled ancestor. A disabled branch can still be expanded and hold\n // enabled children, and every other keyboard move refuses to land on one — so\n // stopping here would be the single way to focus a row the rest of the control skips.\n let ancestor: string | undefined = row.parentId;\n while (ancestor !== undefined) {\n const at: number = rows.findIndex(\n candidate => candidate.node.id === ancestor\n );\n if (at < 0) break;\n if (rows[at]?.node.disabled !== true) {\n focusRow(at);\n break;\n }\n ancestor = rows[at]?.parentId;\n }\n }\n return;\n case \"Home\":\n event.preventDefault();\n focusRow(rows[0]?.node.disabled === true ? step(0, 1) : 0);\n return;\n case \"End\": {\n event.preventDefault();\n const last = rows.length - 1;\n focusRow(rows[last]?.node.disabled === true ? step(last, -1) : last);\n return;\n }\n case \"Enter\":\n case \" \":\n event.preventDefault();\n /*\n * The same three gestures the pointer has, so multi-select is not a\n * mouse-only capability. WCAG 2.2 SC 2.1.1 asks that everything\n * reachable by pointer be reachable from a keyboard, and the APG's\n * multi-select tree pattern names Ctrl+Space for toggle and Shift for\n * extend — which is what these modifiers resolve to.\n */\n if (row.node.disabled !== true) {\n choose(row.node.id, treeSelectionMode(event));\n }\n return;\n case \"*\": {\n event.preventDefault();\n // Every sibling at this level, which is the pattern's shortcut for \"show me this whole\n // layer\" without walking it.\n const next = new Set(expanded);\n for (const sibling of rows) {\n if (sibling.parentId === row.parentId && sibling.hasChildren) {\n next.add(sibling.node.id);\n }\n }\n commitExpanded(next);\n return;\n }\n default:\n break;\n }\n\n // Typeahead. A single printable character extends the query rather than replacing it, so\n // typing \"he\" reaches \"header\" instead of stopping at every row beginning with \"e\".\n if (\n event.key.length !== 1 ||\n event.metaKey ||\n event.ctrlKey ||\n event.altKey\n ) {\n return;\n }\n event.preventDefault();\n const now = Date.now();\n const state = typeahead.current;\n state.query = now - state.at > 500 ? event.key : state.query + event.key;\n state.at = now;\n const query = state.query.toLowerCase();\n for (let offset = 1; offset <= rows.length; offset += 1) {\n const candidate = rows[(index + offset) % rows.length];\n if (candidate === undefined || candidate.node.disabled === true)\n continue;\n if (textOf(candidate.node).toLowerCase().startsWith(query)) {\n focusRow(rows.indexOf(candidate));\n return;\n }\n }\n };\n\n // The roving tab stop has to be on a row that EXISTS and that keyboard navigation would\n // accept. Neither is guaranteed by the active index: a selection outside the first window is\n // not rendered at scrollTop 0, so every rendered row would compare false and the tree would\n // have no tab stop at all — unreachable by Tab until something else scrolled it. And a\n // disabled row is skipped by pointer and by every arrow key, so landing on it by Tab\n // contradicts the rest of the control.\n const virtualItems = virtualizer.getVirtualItems();\n const usable = (index: number): boolean =>\n rows[index]?.node.disabled !== true;\n const tabStopIndex =\n virtualItems.some(item => item.index === activeIndex) &&\n usable(activeIndex)\n ? activeIndex\n : (virtualItems.find(item => usable(item.index))?.index ?? -1);\n\n return (\n <div\n ref={attachScroll}\n className={cn(\"overflow-auto\", className)}\n {...props}\n >\n <div\n role=\"tree\"\n // The naming attributes go on the element that carries the role, not on the scroll\n // container around it. Left outside, a caller who names the tree with\n // `aria-labelledby` gets a tree with no accessible name at all — the label sits on a\n // plain div and the role element is announced as an unlabelled tree.\n // Only when the caller actually holds a set — see `selectedIds`.\n aria-multiselectable={selectedIds === undefined ? undefined : true}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={ariaDescribedBy}\n onKeyDown={onKeyDown}\n style={{ height: virtualizer.getTotalSize(), position: \"relative\" }}\n >\n {virtualItems.map(item => {\n const row = rows[item.index];\n if (row === undefined) return null;\n const isSelected = isRowSelected(\n row.node.id,\n selected,\n selectedIds\n );\n // Which member the rest of the screen answers for. With no set\n // supplied every selected row is the primary, so nothing changes.\n const isPrimary = selected === row.node.id;\n return (\n <div\n key={row.node.id}\n data-tree-index={item.index}\n role=\"treeitem\"\n aria-level={row.level + 1}\n aria-setsize={row.setSize}\n aria-posinset={row.posInSet + 1}\n aria-selected={isSelected}\n aria-expanded={\n row.hasChildren ? expanded.has(row.node.id) : undefined\n }\n aria-disabled={row.node.disabled === true ? true : undefined}\n // Roving tabindex: one row in the tab order, so Tab crosses the tree once rather\n // than stopping at every node in it.\n tabIndex={item.index === tabStopIndex ? 0 : -1}\n onFocus={() => setActiveId(row.node.id)}\n onClick={event => {\n if (row.node.disabled === true) return;\n setActiveId(row.node.id);\n choose(row.node.id, treeSelectionMode(event));\n }}\n className={cn(\n \"absolute left-0 flex w-full select-none items-center gap-1 rounded-sm pr-2 text-sm outline-none\",\n \"focus-visible:ring-1 focus-visible:ring-ring\",\n row.node.disabled === true\n ? \"pointer-events-none opacity-50\"\n : \"cursor-pointer\",\n isSelected ? \"bg-muted text-foreground\" : \"hover:bg-muted/50\",\n // WEIGHT, not a second colour. Every row here is selected and\n // an action applies to all of them; what a reader needs is\n // which one the detail panel describes, and a second colour\n // would have to mean a second kind of selected.\n isSelected && isPrimary && \"font-medium\"\n )}\n style={{\n height: item.size,\n transform: `translateY(${item.start}px)`,\n paddingLeft: 4 + row.level * INDENT_PER_LEVEL,\n }}\n >\n <span\n // A separate hit target from the row: opening a branch and selecting it are\n // different intents, and collapsing a folder should not also select it.\n aria-hidden=\"true\"\n className=\"flex size-4 shrink-0 items-center justify-center\"\n onClick={event => {\n if (!row.hasChildren) return;\n event.stopPropagation();\n setExpansion(row.node.id, !expanded.has(row.node.id));\n }}\n >\n {row.hasChildren ? (\n <ChevronRight\n className={cn(\n \"size-3.5 text-muted-foreground transition-transform\",\n expanded.has(row.node.id) && \"rotate-90\"\n )}\n />\n ) : null}\n </span>\n {row.node.icon !== undefined ? (\n <span className=\"flex size-4 shrink-0 items-center justify-center text-muted-foreground\">\n {row.node.icon}\n </span>\n ) : null}\n <span className=\"truncate\">{row.node.label}</span>\n </div>\n );\n })}\n </div>\n </div>\n );\n }\n);\nTreeView.displayName = \"TreeView\";\n\nexport { TreeView };\n","/**\n * Slider\n *\n * A value chosen by dragging along a track, built on `@radix-ui/react-slider`. An inspector is\n * full of bounded numeric properties — opacity, blur radius, letter spacing, a colour's alpha —\n * and each one is a value where the useful question is \"more or less?\" rather than \"what number?\".\n *\n * **Why a library rather than a range input**: `<input type=\"range\">` is keyboard-accessible and\n * nearly unstyleable, and it cannot express two thumbs. The parts that are genuinely hard are the\n * ones a hand-rolled version gets wrong quietly — pointer capture that survives the cursor leaving\n * the element, step rounding that does not accumulate floating-point drift, right-to-left\n * direction, and the ARIA slider pattern for each thumb independently. Radix implements all of\n * them and is already this kit's primitive vendor, so it adds no new dependency shape.\n *\n * **A slider is for magnitude, not precision.** Anything a person needs to type exactly wants a\n * number input beside it; the slider is the coarse control and the input is the fine one. Pairing\n * them is the caller's composition, deliberately: this kit does not decide that every slider earns\n * a spinbox next to it.\n *\n * **Controlled and uncontrolled both work**, following Radix: pass `value` with `onValueChange` to\n * control it, or `defaultValue` to let it own its state. `value` is an ARRAY even for a single\n * thumb — that is what makes a range slider the same component rather than a second one, and it is\n * the most common thing to get wrong on first use.\n *\n * **Commit on `onValueCommit`, not `onValueChange`**, whenever the write is expensive. The first\n * fires once the drag settles; the second fires continuously while the pointer moves. Recompiling\n * a stylesheet or writing to a server on every frame of a drag is the same mistake\n * `ResizablePanelGroup` documents for layout persistence.\n *\n * **Design specifications**:\n * - Track: 1.5 units thick, `bg-secondary`, fully rounded\n * - Range: the filled portion, `bg-primary`\n * - Thumb: 4x4, `border-primary` on `bg-background`, so it reads against both track halves\n * - Focus: `focus-visible` ring on the thumb, which is the focusable element\n * - Disabled: 50% opacity and `pointer-events-none`, matching the kit's other inputs\n *\n * **Accessibility**:\n * - Each thumb is a `slider` with `aria-valuenow`/`aria-valuemin`/`aria-valuemax` from Radix\n * - Arrow keys step, PageUp/PageDown jump, Home/End go to the bounds\n * - A name is REQUIRED and not defaulted: an unlabelled slider announces only a number, and\n * this kit cannot invent a name that would be honest. The name lands on the THUMB, which is\n * what takes focus — `aria-label` on the root is inherited by nothing\n * - A RANGE needs `thumbs`, one entry per thumb: two thumbs sharing the root's name are\n * announced identically, so nothing says which end is held\n * - `aria-valuetext` and `aria-describedby` belong on `thumbs` too — like the name, they are\n * read from the thumb and inherited from nothing\n * - The root is padded so the target clears the 24px minimum (WCAG 2.5.8); the 16px thumb on a\n * 6px track does not on its own\n * - An empty name does not count as a name: `aria-label=\"\"` is reported the same as a missing one,\n * because the accessible name computes to nothing either way\n *\n * **An empty value array renders nothing.** A slider over no values is not a state this control\n * can represent: an empty `defaultValue` falls back to `min`, and an empty `value` — which a\n * controlled caller owns and this component must not overwrite — renders no control at all,\n * rather than a thumb that carries no value and cannot be moved.\n *\n * **Sizing**: a horizontal slider fills its container's width. A VERTICAL one carries a default\n * height instead of filling, because `height: 100%` inside an auto-height parent collapses to a\n * track with no length. Override it with an ordinary `className` — `h-64` for a longer control,\n * `h-full` for the fill-the-parent behaviour.\n *\n * @example\n * ```tsx\n * // Single value, controlled, committing only when the drag settles\n * <Slider\n * aria-label=\"Opacity\"\n * value={[opacity]}\n * min={0}\n * max={100}\n * step={1}\n * onValueChange={([next]) => setPreview(next)}\n * onValueCommit={([next]) => save(next)}\n * // The number alone does not say what it means; this is what gets spoken.\n * thumbs={[{ \"aria-valuetext\": `${opacity} percent` }]}\n * />\n * ```\n *\n * @example\n * ```tsx\n * // Two thumbs: the same component, because `value` was always an array.\n * // A range needs `thumbLabels` — the root's name is not inherited, and two\n * // thumbs sharing one name are announced identically.\n * <Slider\n * defaultValue={[25, 75]}\n * thumbs={[\n * { \"aria-label\": \"Minimum size\" },\n * { \"aria-label\": \"Maximum size\" },\n * ]}\n * />\n * ```\n *\n * @module components/slider\n */\n\"use client\";\n\nimport * as SliderPrimitive from \"@radix-ui/react-slider\";\nimport * as React from \"react\";\n\nimport { devWarnOnce } from \"../lib/dev-warn\";\nimport { cn } from \"../lib/utils\";\n\n/**\n * The assistive-technology attributes a single thumb can carry.\n *\n * @experimental\n */\nexport interface SliderThumbProps {\n /** The thumb's accessible name. */\n \"aria-label\"?: string;\n /** An element naming the thumb, when the name is already on screen. */\n \"aria-labelledby\"?: string;\n /**\n * What the value MEANS, when the number alone does not say it — \"40\n * percent\", \"Medium\". Announced in place of the raw number.\n */\n \"aria-valuetext\"?: string;\n /** An element carrying help text for this thumb. */\n \"aria-describedby\"?: string;\n}\n\n/**\n * The slider's props, mirroring the Radix root.\n *\n * @experimental\n */\nexport type SliderProps = Omit<\n React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>,\n // The wrapper always supplies a track and at least one thumb, and Radix's\n // Slot accepts exactly one composable child — so `asChild` here throws at\n // render. Excluded from the type rather than left to fail at runtime.\n \"asChild\"\n> & {\n /**\n * Assistive-technology attributes per thumb, in value order.\n *\n * The reason this exists at all: the focusable element with the `slider`\n * role is the THUMB, and none of these attributes are inherited from the\n * root. Anything a caller puts on the root is therefore announced by\n * nothing, and the thumbs are generated internally so they cannot be\n * reached any other way.\n *\n * Deliberately a curated set rather than the thumb's full prop type. This\n * is the surface assistive technology reads; opening it to arbitrary props\n * would let a caller replace the class names or the role the control\n * depends on, and every escape hatch in a design system eventually gets\n * used that way.\n *\n * Required for a RANGE: two thumbs sharing one name are announced\n * identically, so nothing says which end is held. A single thumb falls back\n * to the root's `aria-label`/`aria-labelledby`, so the one-thumb API stays\n * as documented.\n */\n thumbs?: readonly SliderThumbProps[];\n};\n\n/**\n * One thumb per value, derived from whichever of `value`/`defaultValue` is present.\n *\n * Radix renders only as many thumbs as it is given children, so a range slider whose caller\n * supplied two values but one thumb would silently drop the second — the value would still be in\n * state, and no thumb would be able to reach it.\n *\n * An EMPTY array floors to one rather than to zero. Zero thumbs is a track with nothing focusable\n * in it: no `slider` role, no keyboard target, and no pointer target either, because Radix routes\n * a track click to the nearest thumb. A control that cannot be operated at all is a worse outcome\n * than one showing a fallback, and the empty array is reported separately.\n */\nfunction thumbCount(\n value: readonly number[] | undefined,\n defaultValue: readonly number[] | undefined\n): number {\n return Math.max(1, value?.length ?? defaultValue?.length ?? 1);\n}\n\n/**\n * Whether a naming attribute actually carries a name.\n *\n * A present-but-empty `aria-label` is the case a presence check misses: the attribute is there, so\n * every `!== undefined` test says the thumb is named, while the accessible name computes to the\n * empty string and assistive technology announces a bare number. It arises from ordinary code —\n * `aria-label={field.label}` before the label loads, or a template over an absent value.\n *\n * The check is deliberately shallow for `aria-labelledby`: whether the referenced element exists\n * and holds text is a property of a document this component cannot see at render, so an id that\n * resolves to nothing still passes here. This catches the empty STRING, which is the case that is\n * both common and knowable.\n */\nfunction hasAccessibleName(value: string | undefined): boolean {\n return value !== undefined && value.trim() !== \"\";\n}\n\n/**\n * A bounded numeric value chosen by dragging.\n *\n * @experimental\n */\nconst Slider = React.forwardRef<\n React.ElementRef<typeof SliderPrimitive.Root>,\n SliderProps\n>(\n (\n {\n className,\n value,\n defaultValue,\n thumbs,\n orientation = \"horizontal\",\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n ...props\n },\n ref\n ) => {\n // Radix captures an uncontrolled value array ONCE, at mount. Recomputing\n // the count from a later `defaultValue` would drop a thumb while Radix\n // still stores its value — an endpoint the user can no longer reach and\n // nothing reports. Controlled sliders keep deriving from `value`, which is\n // the prop Radix itself follows.\n const initialUncontrolledCount = React.useRef(\n thumbCount(undefined, defaultValue)\n ).current;\n // Both sources are already at least one: an empty controlled value returns before this is\n // used, and `thumbCount` floors the uncontrolled side.\n const count = value?.length ?? initialUncontrolledCount;\n\n // An empty array asks for a slider over no values, which is not a state this control can\n // represent. The two cases differ in how far they can be repaired, so they are handled\n // separately rather than with one blanket rule.\n //\n // UNCONTROLLED is fully repairable: an empty `defaultValue` is forwarded as absent, and Radix\n // then applies its own `[min]` default. Substituting the vendor's default is exactly what an\n // omitted prop would have done, so nothing downstream can tell the difference.\n //\n // CONTROLLED is NOT repairable, so the control renders NOTHING. Substituting a value would\n // either flip to uncontrolled — handing Radix ownership of state the caller believes it holds\n // — or show a number the caller's state does not contain, which then never reconciles.\n // Emitting a thumb anyway is worse than either: Radix resolves a track click through\n // `getClosestValueIndex`, which returns -1 for an empty array and so writes nowhere. That\n // thumb carries no `aria-valuenow`, cannot be dragged and cannot be moved by a key — a\n // `slider` role that looks operable and is not, which is the one outcome worse than absence.\n const isEmptyDefault =\n defaultValue !== undefined && defaultValue.length === 0;\n const isEmptyControlled = value !== undefined && value.length === 0;\n devWarnOnce(\n !isEmptyDefault && !isEmptyControlled,\n \"Slider: `value`/`defaultValue` must hold one number per thumb, and an empty array \" +\n \"holds none — the control has nothing to slide. An empty `defaultValue` falls back to \" +\n \"`min`; an empty `value` renders nothing at all, because a controlled slider cannot be \" +\n \"given a value without taking state the caller owns. Render nothing until the value is \" +\n \"loaded rather than passing `[]`.\"\n );\n // Placed after the warning so the defect is always reported, and after every hook so the\n // early return cannot change the order they are called in.\n if (isEmptyControlled) return null;\n // Everything assistive technology reads goes on the THUMB, which is what\n // carries the `slider` role and takes focus. Left on the root it is\n // announced by nothing.\n //\n // The single-thumb fallback keeps the documented one-thumb API working:\n // with one thumb the root's name is unambiguous, so it is forwarded. A\n // range has no such fallback — one name cannot distinguish two ends.\n // The requirement TypeScript cannot express: how many thumbs there are is\n // the length of an array, so nothing at compile time can insist a range\n // names both of its ends. Unmet, it fails silently — the control renders\n // and is unusable with a screen reader.\n // Every thumb needs a name from somewhere: its own entry, or — for a\n // single thumb only — the root's. A one-thumb slider with neither was\n // previously exempt from this check, which is the same silent failure the\n // check exists to report.\n const isNamed = (index: number): boolean => {\n const own = thumbs?.[index];\n if (hasAccessibleName(own?.[\"aria-label\"])) return true;\n if (hasAccessibleName(own?.[\"aria-labelledby\"])) return true;\n return (\n count === 1 &&\n (hasAccessibleName(ariaLabel) || hasAccessibleName(ariaLabelledBy))\n );\n };\n devWarnOnce(\n Array.from({ length: count }).every((_, i) => isNamed(i)),\n \"Slider: every thumb needs an accessible name. A single thumb may take \" +\n \"it from the root's `aria-label`/`aria-labelledby`; a range needs one \" +\n \"`thumbs` entry per thumb, because the root's name is not inherited \" +\n \"and two thumbs sharing one name are announced identically.\"\n );\n\n const ariaFor = (index: number): SliderThumbProps => {\n const supplied = thumbs?.[index] ?? {};\n // An empty naming attribute is dropped rather than forwarded. Emitting `aria-label=\"\"`\n // states a name and supplies none, which reads to a name computation as a deliberate\n // choice; omitting the attribute at least leaves the element honestly unnamed.\n const ownLabel = hasAccessibleName(supplied[\"aria-label\"])\n ? supplied[\"aria-label\"]\n : undefined;\n const ownLabelledBy = hasAccessibleName(supplied[\"aria-labelledby\"])\n ? supplied[\"aria-labelledby\"]\n : undefined;\n if (count !== 1) {\n return {\n ...supplied,\n \"aria-label\": ownLabel,\n \"aria-labelledby\": ownLabelledBy,\n };\n }\n // The two naming attributes are ALTERNATIVES, not independent slots, so\n // the fallback is all-or-nothing. Filling each one separately can emit a\n // thumb `aria-label` alongside a root `aria-labelledby`, and since\n // accessible-name computation prefers `aria-labelledby`, the caller's\n // explicit per-thumb name would lose to the root's without saying so.\n const namesItself = ownLabel !== undefined || ownLabelledBy !== undefined;\n return {\n \"aria-label\": namesItself ? ownLabel : ariaLabel,\n \"aria-labelledby\": namesItself ? ownLabelledBy : ariaLabelledBy,\n \"aria-valuetext\": supplied[\"aria-valuetext\"],\n \"aria-describedby\": supplied[\"aria-describedby\"],\n };\n };\n\n // Orientation is a prop, so the branch belongs in JavaScript rather than in a\n // `data-[orientation=vertical]:` variant. A variant compiles to an attribute selector, which\n // outranks the plain utility a caller passes in `className` — `h-48` would lose to the\n // wrapper's own height and the override would fail silently. Plain classes also let\n // tailwind-merge do the job it is here for: same property, caller wins.\n const isVertical = orientation === \"vertical\";\n\n return (\n // `aria-label`/`aria-labelledby` are destructured out above rather than\n // spread here: left on the root they would be a second, roleless copy\n // of a name only the thumb is read for.\n <SliderPrimitive.Root\n ref={ref}\n className={cn(\n \"relative flex touch-none select-none items-center\",\n // WCAG 2.5.8 wants a 24px target. Padding alone does not reach it: the\n // thumb is absolutely positioned, so the cross-axis size is the 6px\n // track plus the padding — 22px with `py-2`. An explicit minimum\n // states the target rather than leaving it to arithmetic that moves\n // whenever the track thickness does.\n isVertical\n ? // A vertical slider needs a LENGTH, and it cannot inherit one:\n // `h-full` inside an auto-height parent resolves to zero, leaving\n // a control with no track to drag along. A concrete default is\n // usable everywhere and, being a plain utility, is replaced by a\n // caller's own `h-*` — including `h-full`, for the fill-the-parent\n // case this default gives up.\n \"h-44 min-w-6 flex-col px-2\"\n : \"min-h-6 w-full py-2\",\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className\n )}\n orientation={orientation}\n value={value}\n // An empty array is forwarded as absent so Radix applies its own `[min]`\n // default; a populated one is passed through untouched.\n defaultValue={isEmptyDefault ? undefined : defaultValue}\n {...props}\n >\n <SliderPrimitive.Track\n className={cn(\n \"bg-secondary relative grow overflow-hidden rounded-full\",\n isVertical ? \"h-full w-1.5\" : \"h-1.5 w-full\"\n )}\n >\n <SliderPrimitive.Range\n className={cn(\n \"bg-primary absolute\",\n isVertical ? \"w-full\" : \"h-full\"\n )}\n />\n </SliderPrimitive.Track>\n {Array.from({ length: count }, (_, i) => (\n <SliderPrimitive.Thumb\n key={i}\n {...ariaFor(i)}\n className={cn(\n \"border-primary bg-background block h-4 w-4 rounded-full border-2\",\n \"ring-offset-background transition-colors\",\n \"focus-visible:ring-ring focus-visible:outline-none focus-visible:ring-2\",\n \"focus-visible:ring-offset-2\",\n \"disabled:pointer-events-none disabled:opacity-50\"\n )}\n />\n ))}\n </SliderPrimitive.Root>\n );\n }\n);\nSlider.displayName = SliderPrimitive.Root.displayName;\n\nexport { Slider };\n","/**\n * Development-time warnings for requirements the type system cannot express.\n *\n * Some contracts in this kit depend on runtime facts — a range slider needs one\n * accessible name per thumb, and how many thumbs there are is the length of an\n * array. TypeScript cannot see that, a doc comment is not checked by anything,\n * and the failure is silent: the control renders, looks finished, and is\n * unusable with a screen reader.\n *\n * **This follows the layer beneath us rather than inventing a policy.** Radix\n * Primitives warns when a Dialog is missing an accessible title or description;\n * React Aria warns for missing labels; React itself warns for missing keys. A\n * wrapper that stays silent about a defect the primitive underneath it reports\n * is less safe than the thing it wraps, and quietly removes a signal consumers\n * already had.\n *\n * The rules this module exists to enforce:\n *\n * - **Development only, proven rather than assumed.** The gate requires a\n * POSITIVE development signal. Asking instead whether the environment is\n * production fails open: this package publishes ESM that keeps the runtime\n * check, and a browser bundle that neither defines nor shims `process`\n * leaves the comparison false, so every warning would reach real users'\n * consoles. Silence in an unidentifiable environment is the cheaper mistake\n * of the two.\n * - **Once per message.** A control that re-renders through a drag would\n * otherwise emit the same line on every frame, which trains people to ignore\n * the console — the opposite of the point.\n * - **Never throws.** A missing label degrades; it must not take down the page\n * that contains it.\n *\n * @module lib/dev-warn\n */\n\n/**\n * Messages already emitted this session.\n *\n * Keyed by the message itself rather than by component instance: the same\n * defect repeated across twenty instances is one thing for the developer to\n * fix, and twenty identical lines make it harder to see, not easier.\n */\nconst emitted = new Set<string>();\n\n/**\n * The one field this module reads, declared rather than pulled in with\n * `@types/node`.\n *\n * This package targets the browser and deliberately carries no Node types;\n * adding them to reach a single string would widen what every consumer's\n * type-check sees. Bundlers replace `process.env.NODE_ENV` at build time, and\n * `typeof` guards the case where nothing does.\n */\ndeclare const process: { env?: { NODE_ENV?: string } | undefined } | undefined;\n\n/**\n * The environments a warning is allowed to speak in.\n *\n * `test` is here alongside `development` because a suite asserting that a\n * warning fires is checking the same contract a developer relies on; leaving\n * it out would make every such test pass for the wrong reason.\n */\nconst SPEAKING_ENVIRONMENTS = new Set([\"development\", \"test\"]);\n\n/**\n * Whether this runtime has positively identified itself as a development one.\n *\n * Deliberately not `!== \"production\"`. Bundlers replace `process.env.NODE_ENV`\n * at build time, but nothing obliges them to: a build that leaves `process`\n * undefined would answer \"not production\" and ship every warning to end users.\n * An unrecognized environment is treated as one to stay quiet in.\n *\n * Exported so a caller that needs to skip more than a `console.warn` in\n * production — a component gating an entire post-mount DOM check, for\n * example — reuses this SAME predicate rather than re-deriving its own\n * `process.env.NODE_ENV` guard next to it.\n */\nexport function isDevelopmentRuntime(): boolean {\n if (typeof process === \"undefined\") return false;\n const env = process?.env?.NODE_ENV;\n return env !== undefined && SPEAKING_ENVIRONMENTS.has(env);\n}\n\n/**\n * Warn once, in development, about a requirement that is unmet.\n *\n * @param condition - The requirement. Nothing is emitted while this holds.\n * @param message - What is wrong and what to do about it. Written for the\n * developer who will read it in a console with no other context.\n */\nexport function devWarnOnce(condition: boolean, message: string): void {\n if (condition) return;\n if (!isDevelopmentRuntime()) return;\n if (emitted.has(message)) return;\n emitted.add(message);\n console.warn(`[@nextlyhq/ui] ${message}`);\n}\n\n/**\n * Forget which messages have been emitted.\n *\n * For tests, which need each case to observe its own warning rather than\n * inheriting the suppression an earlier one caused.\n */\nexport function resetDevWarnings(): void {\n emitted.clear();\n}\n","/**\n * React bindings for the shortcut manager.\n *\n * Precedence follows the component tree. `ShortcutProvider` owns the single listener and is\n * depth 0; every `ShortcutScope` beneath it adds one. A shortcut registered deeper wins, which is\n * what makes an editor canvas outrank the shell that contains it without either one naming a\n * number the other has to stay clear of.\n *\n * @example\n * ```tsx\n * // The shell, once, at the root.\n * <ShortcutProvider>\n * <App />\n * </ShortcutProvider>\n *\n * // Anywhere inside it.\n * useShortcuts(\n * [{ keys: \"mod+s\", description: \"Save\", run: save, when: () => isDirty }],\n * { name: \"entry-form\" }\n * );\n *\n * // A canvas that must own the keyboard while a drag is in flight. `blocking` is what stops the\n * // shell's Escape from navigating away mid-drag: while the drag runs, nothing below this layer\n * // sees a keystroke at all.\n * //\n * // The bindings live in their own component so the hook is called at a component's top level.\n * // A scope's children are ordinary React children, so a hook cannot be called among them\n * // directly — the rules-of-hooks lint rejects it, and conditional rendering would change hook\n * // order.\n * function DragKeys({ isDragging, cancel }) {\n * useShortcuts([{ keys: \"Escape\", description: \"Cancel drag\", run: cancel }], {\n * name: \"canvas-drag\",\n * enabled: isDragging,\n * blocking: true,\n * });\n * return null;\n * }\n *\n * <ShortcutScope>\n * <DragKeys isDragging={isDragging} cancel={cancel} />\n * <Canvas />\n * </ShortcutScope>\n * ```\n *\n * @module lib/shortcuts/react\n */\n\"use client\";\n\nimport * as React from \"react\";\n\nimport { devWarnOnce } from \"../dev-warn\";\nimport { useIsomorphicLayoutEffect } from \"../isomorphic-layout-effect\";\n\nimport {\n createShortcutManager,\n type ActiveShortcut,\n type ShortcutBinding,\n type ShortcutManager,\n type ShortcutManagerOptions,\n} from \"./manager\";\n\ninterface ShortcutContextValue {\n manager: ShortcutManager;\n depth: number;\n /**\n * The target this provider's listener is installed on, already resolved.\n *\n * Carried so a nested provider can compare identity rather than props: an omitted target and\n * an explicit `document` name the same node, and comparing the props would call two providers\n * different while both attached a listener to it.\n */\n target: Pick<EventTarget, \"addEventListener\" | \"removeEventListener\"> | null;\n /**\n * The options the manager in use was built with, as a comparable string.\n *\n * Carried because the per-target registry cannot answer for a DETACHED provider: it is a\n * WeakMap keyed by the target, and `null` is not a key, so a provider that attaches nothing has\n * no entry to compare against. Two nested detached providers describe the same event stream and\n * share a manager exactly as two attached ones do, and an inner one passing different options\n * loses them the same way — with nothing in the registry to notice.\n */\n options: string;\n}\n\nconst ShortcutContext = React.createContext<ShortcutContextValue | null>(null);\n\n/** A target this kit is already listening on, and how many providers rely on that listener. */\ninterface TargetOwner {\n manager: ShortcutManager;\n providers: number;\n detach?: () => void;\n /** The options the manager was built with, so an adopting provider can tell they differ. */\n options: string;\n /**\n * Whether every provider that used this owner has since unmounted.\n *\n * Distinguishes a shell left behind, whose manager was configured by a provider that has gone,\n * from an entry a sibling RESERVED during the same render and has not mounted yet. Both have no\n * providers, and replacing the second discards the manager that sibling already registered its\n * bindings on.\n */\n retired: boolean;\n}\n\n/**\n * The manager already listening on each target.\n *\n * Keyed by the target rather than carried in context, because \"one listener per target\" is a\n * fact about the DOM and not about the React tree. Two sibling subtrees — or two independent\n * roots on one page — each render a provider with no shortcut ancestor between them, so a\n * context check sees nothing and both would attach. This registry is what makes the guarantee\n * hold across them.\n */\nconst ownersByTarget = new WeakMap<object, TargetOwner>();\n\n/**\n * The options that change how a manager behaves, as a comparable string.\n *\n * `now` is a function and cannot be compared usefully, so its PRESENCE is what is recorded: two\n * providers that both supply a clock may still disagree, and one that supplies none plainly\n * differs from one that does.\n */\nfunction optionsFingerprint(options: ShortcutManagerOptions): string {\n return [\n options.isApple ?? \"auto\",\n options.sequenceTimeoutMs ?? \"default\",\n options.now ? \"clock\" : \"no-clock\",\n ].join(\"\\u0000\");\n}\n\n/**\n * Props for {@link ShortcutProvider}.\n *\n * @experimental\n */\nexport interface ShortcutProviderProps extends ShortcutManagerOptions {\n children?: React.ReactNode;\n /**\n * Where the listener is installed. Defaults to `document`.\n *\n * The bubble phase is deliberate: a component that handles its own keys and calls\n * `stopPropagation` wins without knowing this exists, because React attaches its handlers\n * below `document`.\n */\n target?: Pick<EventTarget, \"addEventListener\" | \"removeEventListener\"> | null;\n}\n\n/**\n * Installs the application's one keydown listener and roots the layer stack.\n *\n * @experimental\n */\nexport function ShortcutProvider({\n children,\n target,\n ...managerOptions\n}: ShortcutProviderProps): React.JSX.Element {\n const parent = React.useContext(ShortcutContext);\n // A second provider on the same target is the very bug this module exists to remove: two\n // listeners on one node, where `stopPropagation` cannot suppress a sibling, so both run their\n // binding for one key. A nested provider therefore does NOT build a manager of its own — it\n // passes the outer one through, so the shortcuts inside it still work and there is still one\n // listener. Nesting with an EXPLICIT target is left alone: a second document, such as an\n // iframe or a pop-out window, genuinely needs its own listener.\n // Resolved before comparing, because `undefined` and an explicit `document` name the same\n // node. Comparing the PROPS would call two providers different while both attach a listener to\n // the same target, which is the arrangement this guard exists to prevent.\n const resolvedTarget =\n target === null\n ? null\n : (target ?? (typeof document === \"undefined\" ? null : document));\n // `null` is compared too: two providers that both attach nothing describe the SAME event\n // stream, the one the host drives through `handle()`. An inner provider building its own\n // manager there means the host never sees the bindings beneath it.\n const nestedOnSameTarget =\n parent !== null && parent.target === resolvedTarget;\n // Options are read once, when the manager is built. Re-creating it on a changed option would\n // drop every layer registered by a child, since registrations live on the manager instance.\n const optionsRef = React.useRef(managerOptions);\n // One manager per target this provider has served, rather than one for the provider.\n //\n // A single memoised manager becomes shared the moment a sibling adopts it, and then following\n // this provider to a new target would register that same manager for two documents — every\n // tree's shortcuts firing on both. Keyed by target, the manager this provider offers to a new\n // owner is one no other owner is using.\n // WEAK keys, so a pop-out or iframe document this provider has finished with can be collected.\n // A strong map would hold every former target, and its whole DOM, until the provider unmounted.\n const ownManagers = React.useRef(new WeakMap<object, ShortcutManager>());\n // The detached case has no target to key on, so it gets its own slot rather than a sentinel\n // object living in the map forever.\n const ownDetached = React.useRef<ShortcutManager | null>(null);\n const detached = React.useMemo(() => {\n if (resolvedTarget === null) {\n ownDetached.current ??= createShortcutManager(optionsRef.current);\n return ownDetached.current;\n }\n const existing = ownManagers.current.get(resolvedTarget);\n if (existing) return existing;\n const created = createShortcutManager(optionsRef.current);\n ownManagers.current.set(resolvedTarget, created);\n return created;\n }, [resolvedTarget]);\n\n // Looked up during render, because two sibling providers both need the same manager before\n // either one's effect has run. The lookup is idempotent and keyed by the target, so a repeated\n // render finds the entry it made rather than making a second one; the reference COUNT is kept\n // in the effect below, where React guarantees a matching cleanup.\n let owner =\n resolvedTarget === null ? null : ownersByTarget.get(resolvedTarget);\n // A RETIRED owner is a shell, kept only so a Strict Mode replay can find it. Its manager was\n // configured by a provider that has since gone, and adopting it would silently give this one\n // someone else's `isApple`, `sequenceTimeoutMs` and clock. An owner merely awaiting its first\n // effect is a different thing: a sibling rendered in the same pass has already taken its\n // manager and registered bindings on it, and replacing it would strand them.\n const fingerprint = optionsFingerprint(optionsRef.current);\n if (resolvedTarget !== null && (!owner || owner.retired)) {\n owner = {\n manager: detached,\n providers: 0,\n retired: false,\n options: fingerprint,\n };\n ownersByTarget.set(resolvedTarget, owner);\n }\n // Adopting a shared manager means adopting the options it was built with. That is what sharing\n // IS, and it is correct for genuine siblings — but a render that is abandoned before it commits\n // leaves a reservation nothing will ever clean up, and the next provider on that target adopts\n // its options silently. The mismatch is reported rather than hidden, because the symptom\n // otherwise is `mod` meaning the wrong key with nothing to point at.\n // Checked against the PARENT as well as the registry. The registry answers for a shared target;\n // the parent answers for the nested case, including the detached one the registry cannot see.\n const adoptedDiffers =\n (Boolean(owner) && owner?.options !== fingerprint) ||\n (nestedOnSameTarget && parent !== null && parent.options !== fingerprint);\n devWarnOnce(\n !adoptedDiffers,\n \"ShortcutProvider: another provider is already listening on this target with different \" +\n \"options, so the ones passed here are being ignored. Managers are shared per target; give \" +\n \"the providers matching options, or a target of their own.\"\n );\n // Nesting with matching options is SUPPORTED, not a mistake, and is deliberately not warned\n // about: a component that owns keys and can be rendered on its own — a command palette exported\n // for embedding — has to bring a provider with it, or it throws wherever no shell wrapped it.\n // Reusing the target's manager makes that composition free, and the warning above still reports\n // the case that genuinely loses something, which is options that disagree.\n const manager =\n nestedOnSameTarget && parent\n ? parent.manager\n : owner\n ? owner.manager\n : detached;\n\n // Layout timing, matching the effects that register the layers. A passive effect installs the\n // listener AFTER paint, so a keydown delivered between the commit and the passive flush reaches\n // no manager at all — the provider is on screen, its layers are registered, and a focused\n // control or a legacy listener still answers the first keystroke.\n useIsomorphicLayoutEffect(() => {\n // `null` is an explicit \"attach nothing\", for tests and for a host that drives `handle`\n // itself.\n if (resolvedTarget === null) return;\n let entry = ownersByTarget.get(resolvedTarget);\n if (!entry) {\n // Strict Mode replays effects as setup, cleanup, setup. Reading the entry made during\n // render would find nothing on the replayed setup, so nothing would reattach and every\n // shortcut would be dead for the rest of the mount — in development only, which is the\n // worst place for it to hide.\n entry = {\n manager,\n providers: 0,\n retired: false,\n options: optionsFingerprint(optionsRef.current),\n };\n ownersByTarget.set(resolvedTarget, entry);\n }\n const owned = entry;\n owned.providers += 1;\n owned.retired = false;\n // The first provider to arrive installs the listener; the rest share it. Ownership is a\n // property of the target rather than of the tree, so this holds for sibling subtrees and\n // independent React roots, which have no common context to consult.\n if (owned.providers === 1) {\n owned.detach = owned.manager.attach(resolvedTarget);\n }\n return () => {\n owned.providers -= 1;\n if (owned.providers === 0) {\n owned.detach?.();\n owned.detach = undefined;\n owned.retired = true;\n // The entry itself is KEPT. It is weakly keyed by the target, so it cannot outlive one,\n // and removing it is what made a Strict Mode replay lose the listener. An unused manager\n // holds no layers, since each layer is disposed by the hook that registered it.\n }\n };\n }, [resolvedTarget, manager]);\n\n // Depth continues from the parent rather than restarting, so a scope inside an ignored nested\n // provider still outranks what surrounds it.\n const depth = nestedOnSameTarget && parent ? parent.depth : 0;\n const value = React.useMemo(\n () => ({ manager, depth, target: resolvedTarget, options: fingerprint }),\n [manager, depth, resolvedTarget, fingerprint]\n );\n return (\n <ShortcutContext.Provider value={value}>\n {children}\n </ShortcutContext.Provider>\n );\n}\n\n/**\n * Raises the precedence of everything inside it by one level.\n *\n * @experimental\n */\nexport function ShortcutScope({\n children,\n}: {\n children?: React.ReactNode;\n}): React.JSX.Element {\n const parent = React.useContext(ShortcutContext);\n if (!parent) {\n throw new Error(\"ShortcutScope must be rendered inside a ShortcutProvider\");\n }\n const value = React.useMemo(\n () => ({\n manager: parent.manager,\n depth: parent.depth + 1,\n target: parent.target,\n // Inherited: a scope raises precedence, it does not build a manager, so the options in force\n // are still the ones the provider above it used.\n options: parent.options,\n }),\n [parent.manager, parent.depth, parent.target, parent.options]\n );\n return (\n <ShortcutContext.Provider value={value}>\n {children}\n </ShortcutContext.Provider>\n );\n}\n\n/**\n * Options for {@link useShortcuts}, minus the depth, which comes from the tree.\n *\n * @experimental\n */\nexport interface UseShortcutsOptions {\n /** Identifies this layer in a help panel. */\n name: string;\n /** Whether the layer participates. A disabled layer neither matches nor blocks. */\n enabled?: boolean;\n /**\n * Whether unmatched keys stop here rather than reaching layers beneath.\n *\n * Set this while a drag or a modal interaction owns the keyboard.\n */\n blocking?: boolean;\n /**\n * Sorted ABOVE depth, so a layer can outrank one nested deeper than itself.\n *\n * For a modal, whose hold must not be tied or beaten by a host scoping its own shortcuts one\n * level further. Ordinary layers leave this alone.\n */\n priority?: number;\n}\n\n/**\n * Register shortcuts for as long as the calling component is mounted.\n *\n * The bindings array may be rebuilt on every render; it is re-read in place rather than\n * re-registered, so inline closures are fine and the layer keeps its position in the stack.\n *\n * @experimental\n */\nexport function useShortcuts(\n bindings: readonly ShortcutBinding[],\n options: UseShortcutsOptions\n): void {\n const context = React.useContext(ShortcutContext);\n if (!context) {\n throw new Error(\"useShortcuts must be called inside a ShortcutProvider\");\n }\n const { manager, depth } = context;\n\n const registration = React.useRef<ReturnType<\n ShortcutManager[\"register\"]\n > | null>(null);\n\n // The newest bindings and options, reachable from an effect that must not re-run when they\n // change. Registration is deliberately NOT keyed on them: rebuilding the layer would move it\n // to the top of its depth, changing precedence for a reason the caller never asked for.\n const latest = React.useRef({ bindings, options });\n\n useIsomorphicLayoutEffect(() => {\n registration.current = manager.register([], {\n name: latest.current.options.name,\n depth,\n });\n return () => {\n registration.current?.dispose();\n registration.current = null;\n };\n }, [manager, depth]);\n\n // No dependency array: the bindings close over render-scoped values, so re-reading them every\n // render is what keeps them from going stale, and it is cheap.\n useIsomorphicLayoutEffect(() => {\n latest.current = { bindings, options };\n registration.current?.update(bindings, {\n name: options.name,\n depth,\n enabled: options.enabled,\n blocking: options.blocking,\n priority: options.priority,\n });\n });\n}\n\n/**\n * The manager itself, for a help panel that lists what is currently bound.\n *\n * @experimental\n */\nexport function useShortcutManager(): ShortcutManager {\n const context = React.useContext(ShortcutContext);\n if (!context) {\n throw new Error(\n \"useShortcutManager must be called inside a ShortcutProvider\"\n );\n }\n return context.manager;\n}\n\n/**\n * The shortcuts currently in effect, most precedent first.\n *\n * SUBSCRIBED rather than read once. A help panel mounting alongside the components that register\n * shortcuts reads before their effects have run, so a one-time read returns an empty list and no\n * later render corrects it — the panel simply shows nothing. The same applies whenever a layer is\n * enabled, disabled or replaced while the panel is open.\n *\n * The manager returns the same array until its stack changes, so this re-renders when the\n * shortcuts change and not on every read.\n *\n * @experimental\n */\nexport function useActiveShortcuts(): readonly ActiveShortcut[] {\n const manager = useShortcutManager();\n return React.useSyncExternalStore(\n manager.subscribe,\n manager.activeBindings,\n manager.activeBindings\n );\n}\n","/**\n * Parsing and matching for keyboard shortcut specifications.\n *\n * A spec is written the way it is spoken: `\"mod+s\"`, `\"Escape\"`, `\"shift+alt+f\"`, and — for a\n * sequence — `\"g d\"`, meaning `g` then `d`. Steps are separated by spaces; within a step,\n * modifiers are joined to the key with `+`.\n *\n * The space bar is written `\"Space\"`, because the character the browser reports for it is `\" \"`\n * and a spec split on whitespace has no way to carry that.\n *\n * **`mod` is the point of this module.** It resolves to Command on Apple platforms and Control\n * everywhere else, so a binding is written once. Writing `ctrl` or `meta` explicitly is still\n * possible and then means exactly that, which is what lets a platform-specific binding coexist\n * with a portable one — a distinction lost by any implementation that treats the two as\n * interchangeable.\n *\n * @module lib/shortcuts/key-spec\n */\n\n/**\n * One keystroke: a key plus the modifier state required with it.\n *\n * @experimental\n */\nexport interface KeyChord {\n /** The `KeyboardEvent.key` value, normalized to lower case for single characters. */\n readonly key: string;\n /** Command on Apple platforms, Control elsewhere. */\n readonly mod: boolean;\n readonly ctrl: boolean;\n readonly meta: boolean;\n readonly alt: boolean;\n readonly shift: boolean;\n}\n\n/**\n * A shortcut: one chord, or several pressed in order.\n *\n * @experimental\n */\nexport type KeySequence = readonly KeyChord[];\n\n/**\n * Named keys are compared exactly; single characters are compared case-insensitively.\n *\n * \"Single character\" is counted in CODE POINTS, matching the text-insertion path. A letter from\n * a supplementary plane occupies two UTF-16 units, so a length check on the string treats it as a\n * named key and skips the lowercasing — leaving its upper and lower case forms unable to match\n * each other, in a grammar that documents case-insensitive letters.\n */\nfunction normalizeKey(key: string): string {\n return [...key].length === 1 ? key.toLowerCase() : key;\n}\n\n/**\n * Whether shift is part of what a caller can meaningfully require for this key.\n *\n * On a US layout `?` is already Shift+/, so the browser reports `key: \"?\"` with `shiftKey: true`.\n * A spec of `\"?\"` must therefore match an event that carries shift, or the most natural way to\n * write the binding would never fire. For letters and named keys the opposite holds: `\"s\"` must\n * NOT match Shift+S, or a binding would swallow a keystroke its author never claimed.\n *\n * The dividing line is whether the character itself already encodes the shift.\n */\nexport function shiftIsMeaningful(key: string): boolean {\n if (key.length > 1) return true;\n // Space is a single character that shift does NOT produce, so Shift+Space is a distinct\n // keystroke and a plain `\"Space\"` binding must not answer for it.\n if (key === \" \") return true;\n // Unicode-aware on purpose: an ASCII-only test calls every non-Latin letter punctuation, so a\n // binding for `ж` would also answer for `Ж` on a Cyrillic layout and could swallow capitals.\n return /[\\p{L}\\p{N}]/u.test(key);\n}\n\n/**\n * Parse a spec into the sequence of chords it describes.\n *\n * @param spec - For example `\"mod+s\"`, `\"Escape\"`, or `\"g d\"`.\n * @throws If the spec is empty, or a step names modifiers but no key.\n *\n * @experimental\n */\nexport function parseKeys(spec: string): KeySequence {\n const steps = spec.trim().split(/\\s+/).filter(Boolean);\n if (steps.length === 0) {\n throw new Error(`Shortcut spec is empty: ${JSON.stringify(spec)}`);\n }\n return steps.map(step => parseChord(step, spec));\n}\n\nfunction parseChord(step: string, spec: string): KeyChord {\n // A `+` is both this grammar's separator and a key people bind. A LONE `+` is the key, and a\n // TRAILING one is too: `mod++` is the usual zoom-in shortcut, and splitting it naively leaves\n // a chord carrying modifiers and no key at all. Spelling it `mod+shift+=` is not a substitute,\n // because the browser reports that keystroke as `key: \"+\"`.\n // The separator has to still be there for the trailing `+` to be a KEY: `mod++` is a modifier,\n // a separator and the plus key, while `mod+` is a modifier and a separator with nothing after\n // it. Accepting the second registered the zoom-in chord for a step that names no key at all,\n // and made the \"no key\" error unreachable for exactly the steps that need it.\n const trailingPlusIsKey = step.length > 2 && step.endsWith(\"++\");\n const body = trailingPlusIsKey ? step.slice(0, -1) : step;\n const parts = step === \"+\" ? [\"+\"] : body.split(\"+\").filter(Boolean);\n let mod = false;\n let ctrl = false;\n let meta = false;\n let alt = false;\n let shift = false;\n let key: string | undefined;\n\n for (const raw of parts) {\n switch (raw.toLowerCase()) {\n case \"mod\":\n mod = true;\n break;\n case \"ctrl\":\n case \"control\":\n ctrl = true;\n break;\n case \"meta\":\n case \"cmd\":\n case \"command\":\n meta = true;\n break;\n case \"alt\":\n case \"option\":\n alt = true;\n break;\n case \"shift\":\n shift = true;\n break;\n case \"space\":\n // The browser reports the space bar as `key: \" \"`, which cannot survive a spec split on\n // whitespace — `\" \"` trims to nothing and a literal `\"Space\"` matches no event. Without\n // this alias the space bar is simply unbindable, which rules out canvas panning and\n // play/pause.\n key = \" \";\n break;\n default:\n if (key !== undefined) {\n throw new Error(\n `Shortcut step \"${step}\" names two keys (\"${key}\" and \"${raw}\") in ${JSON.stringify(spec)}`\n );\n }\n key = raw;\n }\n }\n\n if (trailingPlusIsKey) {\n if (key !== undefined) {\n throw new Error(\n `Shortcut step has more than one key: ${JSON.stringify(step)} in ${JSON.stringify(spec)}`\n );\n }\n key = \"+\";\n }\n\n if (key === undefined) {\n throw new Error(\n `Shortcut step \"${step}\" names modifiers but no key, in ${JSON.stringify(spec)}`\n );\n }\n return { key: normalizeKey(key), mod, ctrl, meta, alt, shift };\n}\n\n/**\n * The modifier state an event carries, with `mod` already resolved for the platform.\n *\n * @experimental\n */\nexport interface ModifierState {\n readonly ctrlKey: boolean;\n readonly metaKey: boolean;\n readonly altKey: boolean;\n readonly shiftKey: boolean;\n /** Optional, so a caller driving the matcher by hand need not synthesise one. */\n readonly getModifierState?: (key: string) => boolean;\n}\n\n/**\n * Whether a chord describes the given keystroke.\n *\n * Modifiers are matched EXACTLY rather than as a minimum: a binding for `s` must not fire on\n * `mod+s`, which is a different shortcut and very often a destructive one.\n *\n * @param chord - The chord to test.\n * @param key - The event's `key`.\n * @param state - The event's modifier flags.\n * @param isApple - Whether `mod` should resolve to Command rather than Control.\n *\n * @experimental\n */\nexport function chordMatches(\n chord: KeyChord,\n key: string,\n state: ModifierState,\n isApple: boolean\n): boolean {\n if (normalizeKey(key) !== chord.key) return false;\n\n // `mod` and an explicit `ctrl`/`meta` are folded into one requirement per physical modifier, so\n // a spec may combine them (`\"mod+ctrl+k\"`) without either one being silently dropped.\n const wantsCtrl = chord.ctrl || (chord.mod && !isApple);\n const wantsMeta = chord.meta || (chord.mod && isApple);\n\n if (state.metaKey !== wantsMeta) return false;\n // AltGraph produces a CHARACTER and reports itself as Ctrl+Alt. A binding written for that\n // character — `@` on a layout that needs AltGraph for it — would never match if those synthetic\n // flags had to be declared, and declaring them (`ctrl+alt+@`) is layout-specific: the same\n // character needs no modifiers at all elsewhere. So they are ignored for a character key.\n //\n // Only when the chord asks for NEITHER, though. A spec that explicitly declares `ctrl+alt+@`\n // wants those modifiers held for real; ignoring them would let a plain AltGraph `@` fire it,\n // and because declared modifiers make a binding typing-enabled by default, that firing can\n // happen inside a field and suppress the character the user was typing.\n const altGraph = state.getModifierState?.(\"AltGraph\") ?? false;\n const synthetic =\n altGraph && [...chord.key].length === 1 && !wantsCtrl && !chord.alt;\n if (!synthetic) {\n if (state.ctrlKey !== wantsCtrl) return false;\n if (state.altKey !== chord.alt) return false;\n }\n if (shiftIsMeaningful(chord.key) && state.shiftKey !== chord.shift)\n return false;\n return true;\n}\n\n/**\n * Whether this platform uses Command as its primary modifier.\n *\n * Reads the modern `userAgentData` hint before the deprecated `navigator.platform`, and answers\n * `false` when neither exists — the non-Apple default is also the correct answer for a server\n * render, where no keystroke can arrive.\n *\n * @experimental\n */\nexport function detectApplePlatform(): boolean {\n if (typeof navigator === \"undefined\") return false;\n const candidate = navigator as Navigator & {\n userAgentData?: { platform?: string };\n };\n const platform =\n candidate.userAgentData?.platform ?? navigator.platform ?? \"\";\n return /mac|iphone|ipad|ipod/i.test(platform);\n}\n","/**\n * The single owner of keyboard shortcuts for an application.\n *\n * ## Why this exists\n *\n * Shortcuts are usually registered by whoever needs them, each component adding its own\n * `document` listener. That works until two of them want the same key, and then it fails in a way\n * that is very hard to see: `stopPropagation()` does NOT stop other listeners on the same node —\n * that requires `stopImmediatePropagation()`, and even then only for listeners registered later.\n * So every global handler runs, in mount order, and mount order is not something a developer\n * chose. Pressing Escape during a drag can cancel the drag AND navigate away from the page,\n * because two independent listeners each believed they owned the key.\n *\n * This module replaces that with one listener and an explicit precedence rule.\n *\n * ## The model: a stack of layers\n *\n * A **layer** is a set of bindings belonging to one interactive context — the application shell,\n * a dialog, an editor canvas mid-drag. Layers are ordered, the topmost is offered each keystroke\n * first, and the first binding that matches consumes it.\n *\n * Precedence is `(depth, sequence)`: the deeper layer wins, and between layers at equal depth the\n * more recently registered wins.\n *\n * Of those two, **depth is declared and sequence is incidental** — and only declared properties\n * survive a refactor. A layer that unmounts and remounts takes a fresh sequence number, so a\n * subtree rebuilt for unrelated reasons can change equal-depth ordering. The guidance that falls\n * out: if relative order matters to you, express it as depth, because depth is the part of the\n * tuple you control. Equal-depth ordering is for stacking things that arrive in genuine\n * mount order, such as one dialog over another. Depth comes from how the application nests, so precedence\n * follows the component tree rather than a set of coordinated numbers — the z-index problem,\n * avoided. Equal-depth ordering is what stacks a second dialog above the first.\n *\n * A layer may be **blocking**, meaning it also swallows the keys it does NOT bind. That is the\n * property a drag or a modal needs: while it is up, nothing beneath it can act. This is the same\n * shape as a window manager's keyboard grab, and as the dismissable-layer stack this kit's\n * dialogs already sit on.\n *\n * ## What it deliberately does not do\n *\n * It listens in the BUBBLE phase, so a focused component that handles its own keys and calls\n * `stopPropagation()` wins without needing to know this module exists. React attaches its\n * handlers at the app root, below `document`, so an `onKeyDown` prop is a sufficient opt-out.\n * Capturing instead would make this module outrank every component in the tree, including the\n * kit's own dialogs, and there would be no way for a component to decline.\n *\n * @module lib/shortcuts/manager\n */\n\nimport { devWarnOnce } from \"../dev-warn\";\n\nimport {\n chordMatches,\n detectApplePlatform,\n parseKeys,\n shiftIsMeaningful,\n type KeyChord,\n type KeySequence,\n} from \"./key-spec\";\n\n/**\n * One shortcut and what it does.\n *\n * @experimental\n */\nexport interface ShortcutBinding {\n /** The keys, as understood by `parseKeys` — `\"mod+s\"`, `\"Escape\"`, `\"g d\"`. */\n keys: string;\n /**\n * What this does, in words, for a shortcuts help panel. Required because an undiscoverable\n * shortcut helps only the person who wrote it.\n */\n description: string;\n /** Runs when the shortcut fires. */\n run: (event: KeyboardEvent) => void;\n /** Checked at press time; a binding whose condition is false is skipped and passes the key on. */\n when?: () => boolean;\n /**\n * Whether this fires while the user is typing in a field.\n *\n * Defaults to true for bindings whose FIRST chord carries a non-shift modifier or is Escape,\n * and false otherwise — the rule nearly every application converges on. `mod+s` must save\n * mid-sentence and Escape must dismiss, while a bare `n` must be able to be the letter n.\n *\n * The first chord decides because it is the keystroke that has to be taken from the field.\n * `mod+k c` is a command from its opening chord, so its bare `c` completes it in an input. A\n * sequence that OPENS on a plain character cannot fire while typing whatever it ends with:\n * allowing `g Escape` would mean swallowing the `g` of every word containing one.\n */\n whenTyping?: boolean;\n /** Whether to call `preventDefault()` when it fires. Defaults to true. */\n preventDefault?: boolean;\n}\n\n/**\n * How a layer behaves for keys it does not bind.\n *\n * @experimental\n */\nexport interface ShortcutLayerOptions {\n /** Identifies the layer in diagnostics and in a help panel. */\n name: string;\n /** Precedence: deeper layers are offered keystrokes first. */\n depth: number;\n /**\n * Whether unmatched keys stop here instead of reaching layers beneath.\n *\n * The reason a drag can be interrupted safely: everything below is inert for as long as this\n * is set, so no other context can act on a keystroke aimed at this one.\n */\n blocking?: boolean;\n /**\n * Sorted ABOVE depth, so a layer can outrank one nested deeper than itself.\n *\n * Depth alone cannot express a modal. A modal wants to sit above every ordinary layer, but the\n * host chooses how deeply its own shortcuts are scoped, so any depth a modal picks can be tied\n * or beaten by a scope the host nests one level further. Priority is the axis the host does not\n * control: ordinary layers leave it at 0 and a modal raises it.\n *\n * KNOWN LIMIT, stated so it is not discovered: layers at EQUAL priority still compare depth\n * before registration order. Two modals therefore stack by how deeply each is scoped rather\n * than by which opened last, so a modal opened later at a shallower depth can sit under one\n * opened earlier and nested deeper — while whatever renders them puts the newer on top.\n *\n * Fixing it needs the manager to record when a layer is ACTIVATED, which registration order\n * does not capture: `useShortcuts` registers once at mount and updates its options in place, so\n * a layer enabled later still carries its mount-time sequence. Not attempted here because\n * nothing reaches it yet: the layers that raise priority are modal HOLDS, and a hold blocks the\n * keystroke that would open the next one — the command palette cannot be summoned over a dialog\n * that is already holding, so two of them are not both active for a keystroke to be resolved\n * between.\n */\n priority?: number;\n /** Whether the layer participates at all. A disabled layer neither matches nor blocks. */\n enabled?: boolean;\n}\n\n/** A registered layer, which can be updated in place or removed. */\ninterface RegisteredLayer {\n options: ShortcutLayerOptions;\n bindings: readonly PreparedBinding[];\n sequence: number;\n /** What this layer MATCHES, so a re-render that changed nothing can be told apart. */\n shape: string;\n}\n\ninterface PreparedBinding {\n binding: ShortcutBinding;\n keys: KeySequence;\n}\n\n/**\n * A layer's registration, held by whoever created it.\n *\n * @experimental\n */\nexport interface ShortcutRegistration {\n /** Replace this layer's bindings and options without changing its precedence. */\n update: (\n bindings: readonly ShortcutBinding[],\n options: ShortcutLayerOptions\n ) => void;\n /** Remove the layer. */\n dispose: () => void;\n}\n\n/**\n * Options for creating a manager.\n *\n * @experimental\n */\nexport interface ShortcutManagerOptions {\n /** Whether `mod` means Command. Detected from the platform when omitted. */\n isApple?: boolean;\n /** How long a partially typed sequence waits for its next key, in milliseconds. */\n sequenceTimeoutMs?: number;\n /** Clock source, for tests that need to control sequence expiry. */\n now?: () => number;\n}\n\n/**\n * A shortcut manager: the registry, the matcher, and the one listener.\n *\n * @experimental\n */\nexport interface ShortcutManager {\n /** Add a layer. */\n register: (\n bindings: readonly ShortcutBinding[],\n options: ShortcutLayerOptions\n ) => ShortcutRegistration;\n /**\n * Offer a keystroke to the stack. Returns whether it was consumed.\n *\n * Public so the behaviour can be tested without a DOM, and so a host that already owns its\n * event plumbing can drive the manager itself.\n */\n handle: (event: KeyboardEvent) => boolean;\n /** Install the single listener on a target, returning a function that removes it. */\n attach: (\n target: Pick<EventTarget, \"addEventListener\" | \"removeEventListener\">\n ) => () => void;\n /**\n * Every active binding, most-precedent layer first, for a shortcuts help panel.\n *\n * The same array is returned until the layer stack changes, so it is safe to use as an external\n * store snapshot without re-rendering on every read.\n */\n activeBindings: () => readonly ActiveShortcut[];\n /**\n * Watch for changes to the layer stack.\n *\n * A help panel mounting alongside the components that register shortcuts would otherwise read\n * BEFORE their effects run and show nothing, with no later render to correct it.\n */\n subscribe: (onChange: () => void) => () => void;\n}\n\n/**\n * A binding as presented to a help panel, with the layer it came from.\n *\n * @experimental\n */\nexport interface ActiveShortcut {\n keys: string;\n description: string;\n layer: string;\n}\n\nconst DEFAULT_SEQUENCE_TIMEOUT_MS = 1000;\n\n/**\n * Identifies the physical press, for matching a repeat back to the keystroke that began it.\n *\n * `code` rather than `key` and the modifier flags, because those CHANGE while a key is held:\n * press Ctrl+S, then add Shift, and the repeats arrive as `S` with a different modifier set. A\n * signature built from them stops matching mid-hold, the repeat is reported unhandled, and the\n * browser takes it. The physical key does not move, so the physical key is what is remembered.\n */\nfunction signature(event: KeyboardEvent): string {\n return event.code || event.key;\n}\n\n/**\n * The shape this module reads off an event target.\n *\n * Structural rather than `HTMLElement`, because `instanceof` is per-realm: a document inside an\n * iframe or a pop-out window has its OWN `HTMLElement`, and the manager documents a custom\n * `target`, so checking against the outer window's constructor rejects every control in exactly\n * the case the option exists to support. `nodeType === 1` identifies an element in any realm.\n */\ninterface ElementLike {\n tagName: string;\n isContentEditable: boolean;\n getAttribute: (name: string) => string | null;\n}\n\n/**\n * The element the keystroke actually reached.\n *\n * `event.target` is RETARGETED to the shadow host when focus is inside an open shadow root, so\n * reading it alone reports a custom element rather than the input inside it. The composed path\n * starts at the true target and crosses the boundary.\n */\nfunction eventTarget(event: KeyboardEvent): EventTarget | null {\n const path = event.composedPath?.();\n return path && path.length > 0 ? (path[0] ?? null) : event.target;\n}\n\n/** The event target as an element, whichever document it came from. */\nfunction asElement(target: EventTarget | null): ElementLike | null {\n if (target === null || typeof target !== \"object\") return null;\n const node = target as { nodeType?: unknown; tagName?: unknown };\n if (node.nodeType !== 1 || typeof node.tagName !== \"string\") return null;\n return target as unknown as ElementLike;\n}\n\n/** The `type` of an input element, or \"\" for anything else. */\nfunction inputType(element: ElementLike): string {\n if (element.tagName !== \"INPUT\") return \"\";\n const value = (element as { type?: unknown }).type;\n return typeof value === \"string\" ? value.toLowerCase() : \"\";\n}\n\n/**\n * Whether a focused native control owns this key itself.\n *\n * A checkbox is not a typing target, so bare-letter shortcuts should still fire over it — but\n * Space is how it toggles, Enter is how a button activates, and the arrows are how a radio group\n * moves. Offering those to the shortcut stack means a global `Space` binding silently stops a\n * focused checkbox working, which is a worse failure than the shortcut not firing.\n */\nfunction controlOwnsKey(\n target: EventTarget | null,\n event: KeyboardEvent\n): boolean {\n if (event.ctrlKey || event.metaKey || event.altKey) return false;\n const element = asElement(target);\n if (!element) return false;\n const tag = element.tagName;\n const type = inputType(element);\n // `reset` belongs with the other button types: it is not a text field, and Space activates it.\n if (\n tag === \"BUTTON\" ||\n type === \"button\" ||\n type === \"submit\" ||\n type === \"reset\" ||\n type === \"image\"\n ) {\n return event.key === \" \" || event.key === \"Enter\";\n }\n // A link activates on Enter. Space scrolls the page rather than following it, so it is not\n // an activation key here.\n if (tag === \"A\" && element.getAttribute(\"href\") !== null) {\n return event.key === \"Enter\";\n }\n // A summary toggles its details on either key, and the admin renders focusable ones today.\n if (tag === \"SUMMARY\") return event.key === \" \" || event.key === \"Enter\";\n if (type === \"checkbox\") return event.key === \" \";\n // A colour input opens its native picker on either key, and this product puts focusable ones\n // on screen in the page builder's colour and gradient controls.\n if (type === \"color\") return event.key === \" \" || event.key === \"Enter\";\n // A file input opens its chooser the same way, and the public `Input` accepts every native\n // type, so this is reachable without anyone writing a raw input element.\n if (type === \"file\") return event.key === \" \" || event.key === \"Enter\";\n // A range input is a slider: the arrows, Home/End and PageUp/PageDown are how its value moves.\n if (type === \"range\") {\n return event.key.startsWith(\"Arrow\") || RANGE_KEYS.has(event.key);\n }\n if (type === \"radio\") {\n return event.key === \" \" || event.key.startsWith(\"Arrow\");\n }\n return false;\n}\n\n/** Whether a keystroke is going into something the user is typing into. */\nfunction isTypingTarget(target: EventTarget | null): boolean {\n const element = asElement(target);\n if (!element) return false;\n if (element.isContentEditable) return true;\n const tag = element.tagName;\n if (tag === \"TEXTAREA\") return true;\n // A native select does type-ahead on bare letters, so a single-key shortcut firing over it\n // would both act and suppress the control's own behaviour.\n if (tag === \"SELECT\") return true;\n if (tag === \"INPUT\") {\n // Only the text-bearing input types capture letters. A checkbox or a button is an input\n // element that a bare-letter shortcut should still fire over.\n return !NON_TEXT_INPUT_TYPES.has(inputType(element));\n }\n // A custom widget that reports itself as taking text does, even when it is a div. `combobox`\n // and `listbox` are here for type-ahead rather than text entry: Radix's Select renders a\n // button with `role=\"combobox\"` and jumps between options on bare letters without stopping\n // propagation, so a single-key shortcut would fire on top of the value it just changed. This\n // kit's own `Select` wraps that trigger, so the case is reachable from our own components.\n const role = element.getAttribute(\"role\");\n return role !== null && TYPE_AHEAD_ROLES.has(role);\n}\n\nconst NON_TEXT_INPUT_TYPES = new Set([\n \"button\",\n \"checkbox\",\n \"color\",\n \"file\",\n \"hidden\",\n \"image\",\n \"radio\",\n \"range\",\n \"reset\",\n \"submit\",\n]);\n\n/** The default answer to \"does this fire while typing?\", explained on `ShortcutBinding`. */\nfunction firesWhileTyping(prepared: PreparedBinding): boolean {\n const explicit = prepared.binding.whenTyping;\n if (explicit !== undefined) return explicit;\n // The FIRST chord decides, because that is the keystroke separating \"issuing a command\"\n // from \"typing\". Reading the last one rejects `mod+k c` in an editor: the sequence is\n // unmistakably a command, but its final chord is a bare letter.\n const first = prepared.keys[0];\n if (first === undefined) return false;\n return (\n first.mod || first.ctrl || first.meta || first.alt || first.key === \"Escape\"\n );\n}\n\n/**\n * Create a shortcut manager.\n *\n * @experimental\n */\nexport function createShortcutManager(\n options: ShortcutManagerOptions = {}\n): ShortcutManager {\n const isApple = options.isApple ?? detectApplePlatform();\n const sequenceTimeoutMs =\n options.sequenceTimeoutMs ?? DEFAULT_SEQUENCE_TIMEOUT_MS;\n const now = options.now ?? (() => Date.now());\n\n const layers = new Set<RegisteredLayer>();\n let nextSequence = 0;\n\n // The partially typed sequence, shared across layers. It is global rather than per-layer\n // because the keystrokes are: once `g` has been pressed, the next key belongs to whichever\n // layer completes it, and a per-layer prefix would let two layers each hold half a sequence.\n let pendingAt: number | null = null;\n\n /**\n * The layer that claimed the sequence in progress.\n *\n * A prefix is not a property of the keyboard, it is a promise made by ONE layer. Without this,\n * disabling the claimer between keystrokes lets a lower layer's `g d` fire on a `d` whose `g`\n * it never saw, and a layer mounted mid-sequence inherits a prefix typed before it existed.\n */\n let pendingLayer: RegisteredLayer | null = null;\n\n /**\n * What each held key was consumed as, keyed by the physical key, so its repeats stay consumed.\n *\n * Keyed by the physical press rather than by the binding that answered it: by the time a repeat\n * arrives, the binding may have made itself ineligible.\n *\n * A map rather than one slot, because several keys are held at once routinely. A single slot\n * was overwritten by the next press: hold `mod+s`, press `mod+k` while `s` is still down, and\n * the repeats of `s` matched nothing, so a binding that had made itself ineligible let the\n * browser take them. The map is bounded by the number of distinct physical keys on the keyboard.\n */\n const consumedPresses = new Map<string, { prevented: boolean }>();\n\n /**\n * The physical key that opened the pending sequence, so its own repeats can be told apart from\n * every other key's.\n *\n * Holding the key that started a prefix must not cancel that prefix, but a repeat arriving from\n * any OTHER key is a real keystroke in between and does cancel it.\n */\n let pendingKey: string | null = null;\n\n /**\n * What a layer matches, ignoring the parts that change on every render.\n *\n * `useShortcuts` calls `update()` after each render, so a callback identity or an inline object\n * differs constantly while the shortcuts themselves are identical. Cancelling a sequence on\n * every update would make `g d` fail whenever a timer or a context change happened to land\n * between the two keystrokes.\n */\n function layerShape(\n bindings: readonly PreparedBinding[],\n options: ShortcutLayerOptions\n ): string {\n const keys = bindings.map(b => b.binding.keys).join(\"\\u0000\");\n return `${keys}\\u0001${options.depth}\\u0001${options.priority ?? 0}\\u0001${options.blocking === true}\\u0001${options.enabled !== false}`;\n }\n\n /** Whether any enabled layer is currently holding the keyboard. */\n function blocking(): boolean {\n return ordered().some(layer => layer.options.blocking === true);\n }\n\n /**\n * Forget a partially typed sequence.\n *\n * Every path that hands a keystroke to someone else calls this. A pending sequence models \"the\n * user is part-way through a command\", and any real keystroke in between falsifies it — a\n * dismissal, a control taking its own key, a composition, a callback that threw. One function\n * rather than a reset open-coded at each exit, so standing down and forgetting the prefix\n * cannot come apart: an exit that stands down without resetting leaves a later `d` completing\n * a `g` typed before the keystroke that interrupted it.\n */\n function abandonSequence(): void {\n pendingAt = null;\n pressedEvents.length = 0;\n pendingLayer = null;\n pendingKey = null;\n }\n\n function prepare(bindings: readonly ShortcutBinding[]): PreparedBinding[] {\n return bindings.map(binding => ({\n binding,\n keys: parseKeys(binding.keys),\n }));\n }\n\n /** Most precedent first: deeper wins, then more recently registered. */\n function ordered(): RegisteredLayer[] {\n return [...layers]\n .filter(layer => layer.options.enabled !== false)\n .sort(\n (a, b) =>\n (b.options.priority ?? 0) - (a.options.priority ?? 0) ||\n b.options.depth - a.options.depth ||\n b.sequence - a.sequence\n );\n }\n\n /**\n * Whether a binding's sequence matches the keys pressed so far.\n *\n * Returns `\"exact\"` when the sequence is complete, `\"prefix\"` when more keys would complete it,\n * and `\"none\"` otherwise. Distinguishing the middle case is what lets a sequence in progress\n * hold the keyboard without firing anything.\n */\n function matchDepth(\n prepared: PreparedBinding,\n pressed: readonly KeyboardEvent[]\n ): \"exact\" | \"prefix\" | \"none\" {\n if (pressed.length > prepared.keys.length) return \"none\";\n for (let i = 0; i < pressed.length; i++) {\n const chord = prepared.keys[i];\n const event = pressed[i];\n if (chord === undefined || event === undefined) return \"none\";\n if (!chordMatches(chord, event.key, event, isApple)) return \"none\";\n }\n return pressed.length === prepared.keys.length ? \"exact\" : \"prefix\";\n }\n\n function fire(\n prepared: PreparedBinding,\n event: KeyboardEvent,\n invoke: boolean\n ): void {\n if (prepared.binding.preventDefault !== false) event.preventDefault();\n if (invoke) prepared.binding.run(event);\n }\n\n /**\n * Whether letting this keystroke through would put a character into a field.\n *\n * The single case a blocking layer must not suppress. Everything else it swallows has to be,\n * or the grab is only half of one: the application stops acting while the BROWSER still does.\n */\n function insertsText(event: KeyboardEvent, typing: boolean): boolean {\n // Tab first, and regardless of what has focus. A modal's focus trap only cancels the WRAP at\n // its first and last tabbable element and relies on the browser default in between, so every\n // control inside it needs Tab to pass — a button and a checkbox just as much as a field.\n //\n // Only the focus-navigation spellings, though. Shift+Tab is the backwards move and belongs\n // here; Ctrl+Tab and its Shift variant change BROWSER TAB, which is a way out of the grab\n // rather than a move inside it. Exempting those reported the keystroke consumed while leaving\n // its default in place, so the layer both silenced other listeners and let the user leave.\n // A layer that genuinely wants a modified Tab can still bind it: an explicit binding matches\n // before this fallback is consulted.\n if (event.key === \"Tab\")\n return !event.ctrlKey && !event.metaKey && !event.altKey;\n if (!typing) return false;\n // AltGraph arrives as ctrl+alt on the layouts that use it, so it must be unwrapped before\n // either modifier is read as a chord.\n const altGraph = event.getModifierState?.(\"AltGraph\") ?? false;\n\n if (!altGraph && (event.ctrlKey || event.metaKey)) {\n // A field owns its own editing commands. Suppressing these would leave a user unable to\n // copy, paste, undo or select inside an input that sits in a blocking modal — a far worse\n // outcome than an unbound accelerator reaching the browser. A binding that wants one of\n // these still matches first; only UNBOUND combinations reach here.\n const letter =\n event.key.length === 1 ? event.key.toLowerCase() : event.key;\n // Redo is the one editing command spelled WITH shift on Apple platforms; everywhere else\n // it is Ctrl+Y. Both are the field's.\n if (letter === \"z\" && event.shiftKey) return !event.altKey;\n if (letter === REDO_LETTER)\n return !isApple && !event.shiftKey && !event.altKey;\n // Shift is how a selection is EXTENDED: mod+shift+arrow selects by word and\n // mod+shift+Home to a boundary, so navigation keeps it. Letters do not — allowing\n // arbitrary modified variants let Ctrl+Shift+A, the browser's tab search, pass as though\n // it were select-all and escape the grab entirely.\n if (EDITING_NAVIGATION.has(event.key)) return !event.altKey || isApple;\n if (event.shiftKey || event.altKey) return false;\n return EDITING_LETTERS.has(letter);\n }\n // Option turns caret keys into their by-word forms on macOS, and is a text modifier there;\n // on Windows and Linux, Alt with a named key is a menu accelerator.\n if (!altGraph && event.altKey) {\n // A native select opens and closes its option popup with Alt and the vertical arrows, so\n // the control's own claim is checked before the key is written off as an accelerator.\n if (\n (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") &&\n asElement(eventTarget(event))?.tagName === \"SELECT\"\n ) {\n return true;\n }\n if (!isApple) return false;\n if (EDITING_NAVIGATION.has(event.key)) return true;\n }\n // Both are the start of composed text and both precede `isComposing`.\n if (event.key === \"Dead\" || event.key === \"Process\") return true;\n // One CODE POINT, not one code unit: an astral character is a single letter written as two\n // UTF-16 units, and rejecting it stops emoji and many scripts being typed at all.\n if ([...event.key].length === 1) return true;\n // Enter, PageUp and PageDown edit or scroll only where the target owns multiple lines. In a\n // single-line input Enter submits the form and the page keys scroll the document behind it —\n // application behaviour running underneath the grab, not text entry.\n if (AMBIGUOUS_KEYS.has(event.key)) return targetOwnsAmbiguousKey(event);\n return FIELD_KEYS.has(event.key);\n }\n\n /**\n * Offer one candidate sequence to the stack.\n *\n * Takes the triggering event alongside the pressed sequence rather than reading the last\n * element back out: the sequence is the matching key, the event is what gets acted on, and\n * conflating them made the non-empty invariant something a reader had to reconstruct.\n */\n function offer(\n pressed: readonly KeyboardEvent[],\n event: KeyboardEvent,\n typing: boolean,\n invoke: boolean\n ): \"fired\" | \"pending\" | \"blocked\" | \"none\" {\n for (const layer of ordered()) {\n // Only the layer that opened a sequence may complete it. That is a rule about MATCHING and\n // deliberately not about precedence: skipping the whole layer let a modal that mounted\n // mid-sequence be stepped over entirely, so a shell command ran straight through the\n // keyboard grab the modal had just taken.\n const mayMatch =\n pressed.length <= 1 || pendingLayer === null || layer === pendingLayer;\n\n if (mayMatch) {\n // Exact matches are resolved across the WHOLE layer before any prefix is considered.\n // Scanning in registration order instead makes one of `g` and `g d` unreachable purely\n // by which was registered first: `g` fires and clears the sequence, or `g d` returns\n // pending and the exact `g` is never examined. Order of registration should not decide\n // which binding exists.\n let prefixed = false;\n for (const prepared of layer.bindings) {\n if (typing && !firesWhileTyping(prepared)) continue;\n if (prepared.binding.when && !prepared.binding.when()) continue;\n const depth = matchDepth(prepared, pressed);\n if (depth === \"exact\") {\n fire(prepared, event, invoke);\n return \"fired\";\n }\n if (depth === \"prefix\") prefixed = true;\n }\n if (prefixed) {\n pendingLayer = layer;\n // A sequence in progress must swallow its own keystroke, or the `g` of `g d` would be\n // typed into the page while the sequence waits for `d`.\n event.preventDefault();\n return \"pending\";\n }\n }\n\n if (layer.options.blocking) return \"blocked\";\n }\n return \"none\";\n }\n\n /**\n * Warn when one binding's sequence is a strict prefix of another's in the same layer.\n *\n * `g` and `g d` cannot both be reachable: the first keystroke either acts or waits, and\n * whichever answer the matcher gives, the other binding is dead. Resolving it by registration\n * order would make the outcome depend on the order of an array, so the matcher is\n * deterministic (exact wins) and the ambiguity is reported instead of hidden.\n */\n function warnOnPrefixConflicts(\n prepared: readonly PreparedBinding[],\n layerName: string\n ): void {\n // `mod` is an alias, so the comparison has to happen after it is resolved: on Windows,\n // `mod+k` and `ctrl+k` are the same physical chord and raw flags call them different.\n const resolved = (chord: KeyChord): string => {\n const ctrl = chord.ctrl || (chord.mod && !isApple);\n const meta = chord.meta || (chord.mod && isApple);\n // Shift is normalised the way the MATCHER treats it. For punctuation whose glyph already\n // encodes shift, the matcher ignores the flag, so `?` and `shift+?` are one chord to it —\n // and a diagnostic that called them different stayed silent about a genuine conflict.\n const shift = shiftIsMeaningful(chord.key) ? chord.shift : false;\n return `${chord.key}\\u0000${ctrl}${meta}${chord.alt}${shift}`;\n };\n const sameChord = (a: KeyChord, b: KeyChord): boolean =>\n resolved(a) === resolved(b);\n for (const short of prepared) {\n for (const long of prepared) {\n if (short === long || short.keys.length >= long.keys.length) continue;\n // Only claim the longer binding is dead when nothing can separate the two at press time.\n // A conditional shorter binding is skipped while its `when` is false, and a difference in\n // typing eligibility means one of them is out of play in a focused field — in both cases\n // the sequence does become reachable, and telling the developer to delete one of them\n // would be wrong.\n if (short.binding.when !== undefined) continue;\n // Only ONE direction makes the longer binding reachable. A typing-disabled shorter\n // binding paired with a typing-enabled longer one is genuinely separable: inside a field\n // the short one is out of play and the sequence can run. The reverse is not — outside a\n // field both are eligible and the exact match wins, inside it only the short one is — so\n // the longer binding is dead either way and the warning belongs.\n if (!firesWhileTyping(short) && firesWhileTyping(long)) continue;\n if (short.keys.every((chord, i) => sameChord(chord, long.keys[i]))) {\n devWarnOnce(\n false,\n `shortcuts: in layer \"${layerName}\", \"${short.binding.keys}\" is a prefix of ` +\n `\"${long.binding.keys}\", so the longer one can never fire. Bind one or the other.`\n );\n }\n }\n }\n }\n\n const watchers = new Set<() => void>();\n /** The last computed binding list, so repeated reads return the same array identity. */\n let snapshot: readonly ActiveShortcut[] | null = null;\n\n /** The bindings a reader sees, in precedence order. */\n function computeSnapshot(): readonly ActiveShortcut[] {\n return ordered().flatMap(layer =>\n layer.bindings.map(prepared => ({\n keys: prepared.binding.keys,\n description: prepared.binding.description,\n layer: layer.options.name,\n }))\n );\n }\n\n /** Whether two binding lists describe the same surface, field by field. */\n function sameShortcuts(\n a: readonly ActiveShortcut[],\n b: readonly ActiveShortcut[]\n ): boolean {\n return (\n a.length === b.length &&\n a.every(\n (entry, index) =>\n entry.keys === b[index]?.keys &&\n entry.description === b[index]?.description &&\n entry.layer === b[index]?.layer\n )\n );\n }\n\n /**\n * Invalidate the snapshot and tell anyone watching that the stack changed.\n *\n * Watchers are notified only when what they can OBSERVE differs. `update()` runs after every\n * render of a registering component, so notifying unconditionally makes a component that both\n * registers shortcuts and reads them re-render, update, and notify again without end, until\n * React stops it with \"Maximum update depth exceeded\". An unchanged surface also keeps its\n * previous array identity, which is what an external store must return for a reader not to\n * re-render on a read.\n */\n function changed(): void {\n const previous = snapshot;\n snapshot = null;\n if (watchers.size === 0) return;\n const next = computeSnapshot();\n if (previous && sameShortcuts(previous, next)) {\n snapshot = previous;\n return;\n }\n snapshot = next;\n for (const watcher of watchers) watcher();\n }\n\n const pressedEvents: KeyboardEvent[] = [];\n\n /**\n * Offer the keystroke, leaving no sequence behind if a consumer's callback throws.\n *\n * An uncaught handler exception does not stop the page, so without this the half-typed prefix\n * outlives the keystroke that failed: a later key could complete a DIFFERENT command in a\n * lower layer, long after the one that threw had already acted.\n */\n function runOffer(\n pressed: readonly KeyboardEvent[],\n event: KeyboardEvent,\n typing: boolean\n ): \"fired\" | \"pending\" | \"blocked\" | \"none\" {\n try {\n return offer(pressed, event, typing, true);\n } catch (error) {\n abandonSequence();\n // Only THIS key's consumption is dropped. Clearing the map forgot every other key still\n // held: a later repeat of one of those was re-offered rather than inheriting its\n // suppression, and a binding whose own action had made it ineligible reported the repeat\n // unhandled, handing the browser an accelerator the first press had suppressed.\n consumedPresses.delete(signature(event));\n throw error;\n }\n }\n\n function handle(event: KeyboardEvent): boolean {\n // An event this manager cannot read as a keystroke at all.\n //\n // `attach` listens on `document`, so EVERYTHING dispatched on the page arrives here,\n // including synthetic events from code that is not ours -- `new CustomEvent(\"keydown\")`,\n // password managers, autofill shims. Those carry no `key`, and the match path spreads it\n // (`[...key]`) and calls `startsWith` on it, both of which throw on `undefined`.\n //\n // Admitted ONCE, here, rather than defended at each read: `handle` is the only way in, and\n // `key` is the only property whose absence throws. The modifier flags degrade to \"no match\"\n // when undefined, and `getModifierState` is already optional-chained at both call sites.\n //\n // Reported as NOT consumed, so `attach` leaves it propagating: an event this manager cannot\n // interpret must reach whatever listener does understand it.\n if (typeof event.key !== \"string\") return false;\n\n // Checked FIRST among real keystrokes: an owner closer to the keystroke has already answered it, and that stays\n // true even while an IME is composing. Reported as consumed so `attach` stops it\n // propagating — the manager runs no binding, but it is the one place that can keep a\n // window-level owner from acting on a key someone else already answered.\n if (event.defaultPrevented) {\n abandonSequence();\n return true;\n }\n // Composition keystrokes belong to the IME. Escape there means \"abandon what I am\n // composing\", so acting on it would cancel the composition AND whatever the application\n // binds Escape to.\n if (event.isComposing) {\n abandonSequence();\n // Reported as consumed WITHOUT preventing the default: the IME's own handling must go\n // ahead, and no other listener should act on the keystroke either. During a staged\n // migration a window-level owner would otherwise dismiss or navigate on the Escape the\n // user pressed to cancel what they were composing.\n return true;\n }\n // Pressing a modifier on its own is not a keystroke to match, and treating it as one would\n // clear any sequence in progress the moment the user reached for Shift. A layer holding the\n // keyboard still consumes it, though — without preventing its default, since a modifier press\n // has no default worth suppressing, and without disturbing the sequence. Otherwise a legacy\n // window-level handler reacting to Shift or Alt still changes application state underneath a\n // grab that claims to hold every unmatched key.\n if (MODIFIER_KEYS.has(event.key)) return blocking();\n\n // A focused native control gets its own activation keys before the shortcut stack sees them.\n if (controlOwnsKey(eventTarget(event), event)) {\n abandonSequence();\n // Consumed WITHOUT preventing the default, exactly as a composing keystroke is: the\n // control's own activation must go ahead, and no other listener should act on it either.\n // A window-level owner acting on the Space that ticked a checkbox is the same double\n // action in a quieter place.\n return true;\n }\n\n const typing = isTypingTarget(eventTarget(event));\n\n // A held key repeats. The binding must not run again, but the key must stay CONSUMED: a\n // shortcut that suppressed the browser on the first keydown and then let every repeat\n // through would open the browser's own save dialog while the key was held down.\n if (event.repeat) {\n // A repeat of some OTHER key is a real keystroke between the sequence's own. While `x` is\n // held, pressing `g`, receiving another `x` repeat, then pressing `d` must not complete\n // `g d` as though nothing had come between them.\n //\n // Measured against the key that OPENED the prefix, not against whether this manager\n // consumed the repeating key. Holding a consumed key — `mod+s` — while typing `g d` put\n // that key in the consumed map, so asking the map preserved the prefix across a keystroke\n // from an entirely different key.\n if (pendingKey !== signature(event)) {\n abandonSequence();\n }\n // Re-offering is not enough on its own. A binding whose action changes its own condition —\n // `mod+s` saving and clearing the dirty flag — is no longer eligible by the second\n // keydown, so the repeat would be reported unhandled and the browser would take it. What\n // was consumed is a PRESS, not a match, so the press is what gets remembered.\n const held = consumedPresses.get(signature(event));\n if (held) {\n // Two different questions about one held key, and they have different answers.\n //\n // CONSUMED belongs to the physical press: it does not move when the modifiers around it\n // do, so the repeats of a keystroke this manager answered stay its own.\n //\n // SUPPRESSED is a property of the keystroke, and modifiers change what that is. A press\n // that was prevented stays prevented — adding shift to a held `mod+s` must not hand the\n // browser a Save As. A press that was PERMITTED, though, was permitted because it was\n // text: add Ctrl to a held `w` and it becomes the accelerator that closes the tab, so the\n // decision is re-made rather than inherited.\n //\n // A PERMITTED press is re-decided by ASKING the stack again, rather than by comparing a\n // signature of the things that might have changed.\n //\n // Three independent inputs decide it — the modifiers, the layer stack, and each binding's\n // own `when` — and the last cannot be signed at all: it is a function, so every render\n // supplies a new identity while the condition is unchanged, and signing it would re-decide\n // constantly. Re-offering reads all three at once, so a binding whose action falsified its\n // own condition stops permitting the browser default on its next repeat, rather than\n // leaving the page scrolling under a layer that claims to hold the keyboard.\n //\n // Offered with `invoke` false, so the matching binding's `preventDefault` policy applies\n // without its action running a second time.\n if (held.prevented) {\n event.preventDefault();\n } else {\n const still = offer([event], event, typing, false);\n // \"fired\" means a binding matched and its own `preventDefault` policy has already been\n // applied, so nothing more is decided here. Every other outcome leaves a press this\n // manager still owns with no one applying a policy to it, and the browser must not act\n // on a key we claim — unless it is text, which is the one thing a grab may never eat.\n //\n // The \"none\" case is not hypothetical: hold a plain `w` bound with\n // `preventDefault: false`, then add Ctrl. No binding matches Ctrl+W, there may be no\n // blocking layer to report it, and the browser closes the tab.\n if (still !== \"fired\" && !insertsText(event, typing)) {\n event.preventDefault();\n }\n }\n return true;\n }\n const repeated = offer([event], event, typing, false);\n if (repeated === \"blocked\" && !insertsText(event, typing)) {\n // A key can begin repeating BEFORE the layer that grabs the keyboard appears, so this is\n // the first time the manager sees it and there is no earlier press to inherit from.\n // Without this the browser keeps scrolling underneath the grab.\n event.preventDefault();\n }\n return repeated !== \"none\";\n }\n\n if (pendingAt !== null && now() - pendingAt > sequenceTimeoutMs) {\n abandonSequence();\n }\n\n pressedEvents.push(event);\n let outcome = runOffer(pressedEvents, event, typing);\n\n // A sequence that led nowhere must not eat the key that broke it: `g` then `mod+k` should\n // open the palette rather than being discarded with the abandoned prefix.\n //\n // \"blocked\" counts as leading nowhere. A blocking layer holding both a sequence and a\n // single-key binding would otherwise swallow the key that broke its own sequence — press\n // `g`, then Escape, and the layer's own Escape handler would need a SECOND press.\n if (\n pressedEvents.length > 1 &&\n (outcome === \"none\" || outcome === \"blocked\")\n ) {\n abandonSequence();\n pressedEvents.push(event);\n outcome = runOffer(pressedEvents, event, typing);\n }\n\n if (outcome === \"pending\") {\n pendingAt = now();\n pendingKey = signature(event);\n consumedPresses.set(signature(event), {\n prevented: event.defaultPrevented,\n });\n return true;\n }\n\n abandonSequence();\n if (outcome === \"blocked\") {\n // Applied HERE rather than inside `offer`, because a \"blocked\" from a multi-key candidate\n // is tentative: the retry below may still find an exact single-key binding, and one that\n // sets `preventDefault: false` cannot uncancel an event the fallback already cancelled.\n // A grab that leaves the browser default in place is still not a grab, so this runs once\n // the outcome is final.\n if (!insertsText(event, typing)) event.preventDefault();\n }\n const consumed = outcome === \"fired\" || outcome === \"blocked\";\n if (consumed) {\n consumedPresses.set(signature(event), {\n prevented: event.defaultPrevented,\n });\n } else {\n consumedPresses.delete(signature(event));\n }\n return consumed;\n }\n\n return {\n register(bindings, layerOptions) {\n const prepared = prepare(bindings);\n const layer: RegisteredLayer = {\n options: layerOptions,\n bindings: prepared,\n sequence: nextSequence++,\n shape: layerShape(prepared, layerOptions),\n };\n warnOnPrefixConflicts(layer.bindings, layerOptions.name);\n layers.add(layer);\n changed();\n return {\n update(nextBindings, nextOptions) {\n layer.bindings = prepare(nextBindings);\n layer.options = nextOptions;\n // The React hook registers empty and supplies its real bindings here, so a diagnostic\n // that only ran at `register` would never see the bindings anyone actually writes.\n warnOnPrefixConflicts(layer.bindings, nextOptions.name);\n const shape = layerShape(layer.bindings, nextOptions);\n const shapeChanged = shape !== layer.shape;\n layer.shape = shape;\n // Only a change to what this layer MATCHES can invalidate a promise it made. `update`\n // runs after every render, so cancelling unconditionally made a sequence fail whenever\n // an unrelated re-render landed between its two keystrokes.\n if (shapeChanged && pendingLayer === layer) abandonSequence();\n changed();\n },\n dispose() {\n layers.delete(layer);\n changed();\n if (pendingLayer === layer) abandonSequence();\n },\n };\n },\n handle,\n attach(target) {\n const listener = (event: Event): void => {\n // `preventDefault` suppresses the BROWSER, not other JavaScript listeners. A consumed\n // key must also stop bubbling, or a window-level owner runs the second half of the\n // double action this manager exists to remove — which is the state of the tree during a\n // staged migration, when some owners have moved over and some have not.\n try {\n if (handle(event as KeyboardEvent)) event.stopPropagation();\n } catch (error) {\n // A binding whose callback threw still CLAIMED the key. Dispatch continues to later\n // listeners after an exception is reported, so leaving the event unstopped would hand\n // the same keystroke to a window-level owner and recreate the double action — with a\n // failed handler, which is the worst moment to run a fallback as though nothing had.\n event.stopPropagation();\n throw error;\n }\n };\n target.addEventListener(\"keydown\", listener);\n return () => {\n target.removeEventListener(\"keydown\", listener);\n // A sequence belongs to the event stream that began it. A provider swapping targets\n // would otherwise let a `g` from the old document be completed by a `d` on the new one,\n // and a repeat inherit consumption state from keystrokes this target never saw.\n abandonSequence();\n consumedPresses.clear();\n };\n },\n subscribe(onChange) {\n watchers.add(onChange);\n return () => {\n watchers.delete(onChange);\n };\n },\n activeBindings() {\n // Cached, because an external store must return a stable identity for an unchanged stack:\n // a fresh array on every read makes React re-render without end.\n if (snapshot) return snapshot;\n snapshot = computeSnapshot();\n return snapshot;\n },\n };\n}\n\nconst MODIFIER_KEYS = new Set([\n \"Control\",\n \"Meta\",\n \"Alt\",\n \"Shift\",\n // A dedicated AltGraph key reports its own keydown before the character-producing one. Without\n // it here, pressing AltGraph mid-sequence abandons the sequence before the character that would\n // have completed it ever arrives.\n \"AltGraph\",\n]);\n\n/**\n * Roles whose widgets consume bare characters themselves.\n *\n * `textbox` takes text; the rest do type-ahead — Radix's Select jumps between options on a\n * letter, and its menus move focus the same way, neither preventing default nor stopping\n * propagation. A shortcut firing over them acts on top of a selection the user just made.\n */\nconst TYPE_AHEAD_ROLES = new Set([\n \"textbox\",\n \"combobox\",\n \"listbox\",\n // The focused element inside an open listbox is the OPTION, and it is what the event reports;\n // the listbox itself is only its ancestor.\n \"option\",\n \"menu\",\n \"menuitem\",\n \"menuitemcheckbox\",\n \"menuitemradio\",\n]);\n\n/** The non-arrow keys a native range input uses to move its value. */\nconst RANGE_KEYS = new Set([\"Home\", \"End\", \"PageUp\", \"PageDown\"]);\n\n/**\n * The letters a text field claims with Ctrl or Command: clipboard, select-all, undo and redo.\n *\n * Unbound, these belong to the field rather than to the application, so a modal that grabbed the\n * keyboard would otherwise make copy and paste impossible inside its own inputs.\n */\nconst EDITING_LETTERS = new Set([\"a\", \"c\", \"v\", \"x\", \"z\"]);\n\n/**\n * Redo, which is spelled differently on each platform.\n *\n * Ctrl+Y is redo on Windows and Linux. On macOS redo is Command+Shift+Z, and Command+Y is a\n * BROWSER accelerator that opens history — so treating it as an editing key everywhere would let\n * it escape a keyboard grab on the one platform where it is not editing at all.\n */\nconst REDO_LETTER = \"y\";\n\n/** Caret movement and deletion, which a modifier turns into their by-word forms. */\nconst EDITING_NAVIGATION = new Set([\n \"Insert\",\n \"ArrowLeft\",\n \"ArrowRight\",\n \"ArrowUp\",\n \"ArrowDown\",\n \"Home\",\n \"End\",\n \"Backspace\",\n \"Delete\",\n]);\n\n/** Keys whose owner depends on which control has focus. */\nconst AMBIGUOUS_KEYS = new Set([\"Enter\", \"PageUp\", \"PageDown\"]);\n\n/**\n * Whether the focused target owns this particular ambiguous key.\n *\n * Enter, PageUp and PageDown mean different things to different controls, so one answer for all\n * three would be wrong for at least one of them. Enter inserts a newline only where there are\n * lines; the page keys page through content, which a native select does with its option list.\n */\nfunction targetOwnsAmbiguousKey(event: KeyboardEvent): boolean {\n const element = asElement(eventTarget(event));\n if (element === null) return false;\n const multiline = element.tagName === \"TEXTAREA\" || element.isContentEditable;\n if (event.key === \"Enter\") return multiline;\n return multiline || element.tagName === \"SELECT\";\n}\n\n/**\n * Keys a focused field consumes itself: caret movement and the edits that carry no character.\n *\n * Tab is here because a focus trap needs it: it only cancels the wrap at the first and last\n * tabbable element, and relies on the browser default for every move in between.\n *\n * Used to decide what a blocking layer may suppress while the user is typing. A key outside this\n * set and not a character belongs to the browser, not the field.\n */\nconst FIELD_KEYS = new Set([\n \"Backspace\",\n \"Delete\",\n \"ArrowUp\",\n \"ArrowDown\",\n \"ArrowLeft\",\n \"ArrowRight\",\n \"Home\",\n \"End\",\n // Shift+Insert pastes and carries no ctrl or meta, so it arrives here rather than at the\n // chord branch where Ctrl+Insert is recognised.\n \"Insert\",\n // Tab moves focus, and a blocking layer must NOT take it. The documented case for blocking is\n // a modal, whose focus trap only calls `preventDefault()` at the first and last tabbable\n // element — ordinary moves between the controls inside it rely on the browser default.\n // Suppressing every Tab therefore pinned focus to one control in exactly the situation\n // blocking exists to serve. A layer that genuinely wants Tab binds it.\n \"Tab\",\n]);\n","\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport type * as React from \"react\";\nimport { cloneElement, Fragment, useEffect, useId } from \"react\";\n\nimport { devWarnOnce, isDevelopmentRuntime } from \"../lib/dev-warn\";\nimport { cn } from \"../lib/utils\";\nimport type {\n FieldShellProps,\n FieldShellRenderProps,\n} from \"../types/form-layout\";\n\n/**\n * The width cap applies to a wrapper around the control, not to the field row.\n *\n * The row keeps its container's full width so labels, descriptions and errors\n * align down the form; only the control itself is bounded. Capping the row\n * would indent the label along with the input and make a column of mixed-width\n * fields read as ragged.\n *\n * The fallbacks are the literals a caller would otherwise reach for, so the\n * component works before any theme defines these properties.\n */\nconst controlWidth = cva(\"w-full\", {\n variants: {\n width: {\n half: \"max-w-[var(--nx-field-half,380px)]\",\n full: \"max-w-[var(--nx-field-full,760px)]\",\n fill: \"\",\n },\n },\n defaultVariants: { width: \"half\" },\n});\n\n/**\n * The subset of a child's own props this component reads before deciding\n * what to merge onto it.\n *\n * `child.props` is untyped (`ReactElement<unknown>`), so this narrows it\n * defensively — checking each key is actually present with the expected\n * primitive type — rather than asserting a shape onto a value nothing has\n * verified. A key present with the wrong type (an `id` that is a number, an\n * `aria-describedby` that is a boolean) is treated the same as absent: the\n * caller's field-shell contract is about ids, id-reference strings and a\n * validity flag, and a value that cannot serve as one is not a real\n * override.\n */\ninterface KnownControlProps {\n id?: unknown;\n \"aria-describedby\"?: unknown;\n \"aria-invalid\"?: unknown;\n}\n\nfunction readControlProps(child: React.ReactElement): KnownControlProps {\n const props: unknown = child.props;\n // An object with no properties the type checker knows about is already\n // assignable to a type whose properties are all optional, so no cast is\n // needed here: only the `typeof` guard is doing real work.\n return props && typeof props === \"object\" ? props : {};\n}\n\n/**\n * The props this component injects onto a cloned control, computed once and\n * applied with a single `cloneElement` call.\n *\n * Declared as its own type, rather than inlined at the call site, so the\n * object passed to `cloneElement` carries real key names instead of a\n * loosely-typed record. `children`'s props are unknown to this component (see\n * `KnownControlProps` above), so `cloneElement`'s `Partial<P>` parameter\n * collapses to `{}` for any child it is handed — meaning this type is the\n * only thing constraining what gets attached, and getting its keys right is\n * what keeps a typo from silently landing on the DOM as a data attribute.\n */\ninterface ControlOverrides {\n id: string;\n \"aria-describedby\"?: string;\n \"aria-invalid\"?: boolean;\n}\n\n/**\n * `children` may be a single element (cloned) or a function that receives\n * the computed wiring and applies it itself.\n *\n * `typeof` is the only check that can tell the two apart at runtime: both\n * are valid members of the union, and nothing about a value's STATIC type\n * alone settles which one a given `children` is. Declaring this as a real\n * type-guard function — rather than inlining `typeof children === \"function\"`\n * at each call site — is what lets every caller below narrow `children`\n * without a cast.\n */\nfunction isRenderFunction(\n children: FieldShellProps[\"children\"]\n): children is (field: FieldShellRenderProps) => React.ReactNode {\n return typeof children === \"function\";\n}\n\n/**\n * The id, `aria-describedby` and `aria-invalid` this component computes for\n * its control — ONE computation, shared by both the element-clone path and\n * the render-function path, so the two can never silently drift into\n * answering the same question differently.\n *\n * `ownProps` carries whatever the caller's single element already had (its\n * own id, an existing `aria-describedby` to compose with, an\n * `aria-invalid` to defer to when there is no error). The render-function\n * path passes an empty object: there is no pre-existing child to read those\n * from — the caller applies the returned wiring itself — so \"nothing to\n * defer to\" is simply the empty case of this same function rather than a\n * second, parallel computation.\n */\nfunction computeControlWiring(\n ownProps: KnownControlProps,\n requestedId: string,\n renderedMessageIds: readonly string[],\n hasError: boolean\n): FieldShellRenderProps {\n // A non-empty string the child already carries wins over the requested id;\n // anything else — including an explicitly-present `id={undefined}`, which\n // a naive object spread would let win — does not. Deciding this here,\n // rather than leaving it to a generic prop-merge, is the entire point of\n // owning the merge: there is exactly one rule for what counts as \"the\n // child already has an id\", and it is applied before the clone rather than\n // discovered afterward in whatever a merge library happened to do.\n const ownId =\n typeof ownProps.id === \"string\" && ownProps.id !== \"\"\n ? ownProps.id\n : undefined;\n const id = ownId ?? requestedId;\n\n const ownDescribedByIds =\n typeof ownProps[\"aria-describedby\"] === \"string\"\n ? ownProps[\"aria-describedby\"].split(\" \").filter(Boolean)\n : [];\n // Compose, never replace: a child may already point at ids of its own (a\n // unit label, a character counter) that this component knows nothing\n // about, and overwriting them would break whatever wired them up. The\n // child's own ids come first so the reading order matches what the caller\n // wrote; `Set` then drops any id both sides already agree on.\n const describedByIds = Array.from(\n new Set([...ownDescribedByIds, ...renderedMessageIds])\n );\n const describedBy =\n describedByIds.length > 0 ? describedByIds.join(\" \") : undefined;\n\n const ownInvalid =\n typeof ownProps[\"aria-invalid\"] === \"boolean\"\n ? ownProps[\"aria-invalid\"]\n : undefined;\n // A rendered error always forces the control invalid: a child that\n // already set `aria-invalid={false}`, or left it unset, must not\n // suppress a validation message that is visibly on the page. With no\n // error, the child's own claim about itself (if any) passes through\n // unmodified instead of being cleared to absent.\n const invalid = hasError ? true : ownInvalid;\n\n return { id, describedBy, invalid };\n}\n\n/** @experimental */\nexport function FieldShell({\n label,\n description,\n error,\n width = \"half\",\n htmlFor,\n className,\n children,\n}: FieldShellProps) {\n // Two independent id namespaces: one for the control (below), one for the\n // description/error text this field may render. The latter never depends\n // on `htmlFor` or the child's own id, because those name the CONTROL, not\n // FieldShell's own paragraphs.\n const generatedControlId = useId();\n const messageBaseId = useId();\n const descriptionId = `${messageBaseId}-description`;\n const errorId = `${messageBaseId}-error`;\n\n // What FieldShell would use for the control absent any id the child\n // already carries: `htmlFor` when the caller supplied one, a generated id\n // otherwise.\n const requestedId = htmlFor ?? generatedControlId;\n\n // Only messages that actually render get an id, and only those ids are\n // listed: a control pointed at an id nothing carries is worse than one\n // with no description at all.\n const renderedMessageIds = [\n description ? descriptionId : null,\n error ? errorId : null,\n ].filter((id): id is string => id !== null);\n\n const wiring = isRenderFunction(children)\n ? computeControlWiring({}, requestedId, renderedMessageIds, Boolean(error))\n : computeControlWiring(\n readControlProps(children),\n requestedId,\n renderedMessageIds,\n Boolean(error)\n );\n\n // A Fragment is a valid `ReactElement` — it type-checks as one — but it\n // forwards none of these props to anything inside it, so cloning it would\n // silently disconnect the label and the validation wiring from every real\n // element the Fragment contains. The type system cannot rule this out\n // (`Fragment`'s element type is indistinguishable from any other\n // component's at the type level), so it is checked at runtime instead, and\n // computed here — once — rather than separately by the render branch below\n // and the mount check that follows it.\n const isFragmentChild =\n !isRenderFunction(children) && children.type === Fragment;\n\n // Development-only: confirm the id this component computed actually\n // landed on something in the document. A compound Radix control (the\n // `Select` root, and by the same shape `RadioGroup`) destructures a fixed,\n // named prop list and never spreads the remainder, so an id attached via\n // `cloneElement` — or one a render function forgot to apply to its real\n // control — is silently dropped: nothing throws, nothing else warns, and\n // the label ends up pointing at an id nothing carries. Gated on\n // `isDevelopmentRuntime()` up front, rather than only inside\n // `devWarnOnce`, so the DOM query itself never runs in production — not\n // merely its console output. Skipped for a Fragment child: that case is\n // already reported, precisely and without a DOM query, by the warning\n // below — this check would only restate the same defect less specifically.\n useEffect(() => {\n if (!isDevelopmentRuntime()) return;\n if (isFragmentChild) return;\n const landed = document.getElementById(wiring.id) !== null;\n const fieldName = typeof label === \"string\" ? `\"${label}\"` : \"this field\";\n devWarnOnce(\n landed,\n `FieldShell: the id computed for ${fieldName} never appeared on any element in the ` +\n \"document, so its label and any description are not connected to the control. This \" +\n \"happens when the control is a compound component — a Radix `Select`, `RadioGroup`, \" +\n \"or similar — whose root does not forward `id`/`aria-describedby`/`aria-invalid` to a \" +\n \"real DOM node. Pass `children` as a function and apply those to the control's actual \" +\n \"focusable element (its trigger) instead of a single top-level clone.\"\n );\n // `wiring.id` is the value being checked; `label` supplies the message's\n // field name; `isFragmentChild` decides whether the check runs at all.\n // Re-running when any of these changes lets the check re-evaluate a\n // field whose identity, generated id or child shape shifted, rather\n // than only ever inspecting the very first commit.\n }, [wiring.id, label, isFragmentChild]);\n\n let control: React.ReactNode;\n if (isRenderFunction(children)) {\n control = children(wiring);\n } else {\n devWarnOnce(\n !isFragmentChild,\n \"FieldShell: `children` must be a single element, not a Fragment. A Fragment forwards \" +\n \"no props to the elements inside it, so the id, aria-describedby and aria-invalid this \" +\n \"component computes would have nowhere to land — the label and the control would look \" +\n \"wired up and never actually connect. Wrap the intended elements in a real element \" +\n \"instead, such as a `<div>`.\"\n );\n const controlOverrides: ControlOverrides = {\n id: wiring.id,\n ...(wiring.describedBy !== undefined\n ? { \"aria-describedby\": wiring.describedBy }\n : {}),\n ...(wiring.invalid !== undefined\n ? { \"aria-invalid\": wiring.invalid }\n : {}),\n };\n // Cloning a Fragment with these props would only add React's own\n // \"invalid prop supplied to React.Fragment\" warning on top of the one\n // above without fixing anything, so it is rendered unmodified and the\n // warning is the only signal.\n control = isFragmentChild\n ? children\n : cloneElement(children, controlOverrides);\n }\n\n return (\n <div className={cn(\"flex flex-col gap-1.5\", className)}>\n {label ? (\n <label\n htmlFor={wiring.id}\n className=\"text-sm font-medium text-foreground\"\n >\n {label}\n </label>\n ) : null}\n <div className={controlWidth({ width })}>{control}</div>\n {description ? (\n <p id={descriptionId} className=\"text-sm text-muted-foreground\">\n {description}\n </p>\n ) : null}\n {error ? (\n <p id={errorId} className=\"text-sm font-medium text-destructive\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n","import type * as React from \"react\";\nimport { useId } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\nimport { Card } from \"./card\";\n\n/** @experimental */\nexport interface FormSectionProps {\n /** Short label above the card, rendered uppercase. */\n label: string;\n /** Optional sentence under the label. */\n description?: React.ReactNode;\n className?: string;\n children: React.ReactNode;\n}\n\n/**\n * A labelled card holding a group of fields.\n *\n * Composes `Card` rather than hand-rolling its own border and background, so\n * a section carries the CONTAINER radius tier `Card` already defines instead\n * of a second, drifting copy of the same chrome. There is deliberately no\n * footer slot. A form commits as one document, so its action belongs to the\n * page rather than to a section.\n * @experimental\n */\nexport function FormSection({\n label,\n description,\n className,\n children,\n}: FormSectionProps) {\n // The visible label stays a `<p>` — promoting it to a heading would pick a\n // heading LEVEL, which depends on where in the page this section lands and\n // this component has no way to know. `aria-labelledby` names the region\n // for assistive tech without making that document-structure claim.\n const labelId = useId();\n\n return (\n <section aria-labelledby={labelId} className={cn(\"space-y-2\", className)}>\n <div className=\"space-y-1\">\n <p\n id={labelId}\n className=\"text-xs font-semibold tracking-[0.08em] uppercase text-muted-foreground\"\n >\n {label}\n </p>\n {description ? (\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n ) : null}\n </div>\n <Card className=\"overflow-hidden\">\n {/* The section owns its vertical rhythm rather than leaving each child\n to pad itself. A card renders whatever children it is handed and\n cannot tell one row idiom from another, so a rhythm supplied by the\n rows is only as reliable as the least careful of them — and a row\n that supplies none renders flush against the card's borders.\n\n One token serves both the card's edge padding and the gap between\n two fields, because they are the same measurement seen twice. Two\n tokens could drift apart with nothing to notice.\n\n The rhythm itself is a plain CSS rule shipped in the theme\n (`.nx-form-section-rows`) rather than a Tailwind utility here. The\n utility spelling differs between Tailwind majors, and an\n arbitrary-value token is extracted from any file the scanner reads —\n a comment naming one included. A theme rule has neither property.\n\n A child must not pad itself: the two are additive, so a row carrying\n its own `py-*` doubles the rhythm on the sections that are already\n correct. */}\n <div className=\"nx-form-section-rows divide-y divide-foreground/10 px-6\">\n {children}\n </div>\n </Card>\n </section>\n );\n}\n","import { cn } from \"../lib/utils\";\nimport type { FormActionsProps } from \"../types/form-layout\";\n\n/**\n * One action bar per form, at the end of the page's measure.\n *\n * A form commits as a single document, so there is one place to commit it. The\n * dirty flag arrives from the page because the form state already answers that\n * question, and a second implementation of it here would disagree with the\n * first as soon as either changed.\n * @experimental\n */\nexport function FormActions({ dirty, className, children }: FormActionsProps) {\n return (\n <div\n className={cn(\n \"sticky bottom-0 mt-8 flex items-center justify-end gap-3\",\n \"border-t border-border bg-background/95 py-4 backdrop-blur\",\n className\n )}\n >\n {dirty ? (\n // `role=\"status\"` (implying `aria-live=\"polite\"`) so a screen-reader\n // user is told when the flag flips false to true, not only sighted\n // users watching the bar. This is the only live region FormActions\n // renders, one per form.\n <span role=\"status\" className=\"mr-auto text-sm text-muted-foreground\">\n You have unsaved changes\n </span>\n ) : null}\n {children}\n </div>\n );\n}\n","import type { CSSProperties, HTMLAttributes } from \"react\";\nimport {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useRef,\n} from \"react\";\n\nimport { devWarnOnce, isDevelopmentRuntime } from \"../lib/dev-warn\";\nimport { cn } from \"../lib/utils\";\n\n/** @experimental */\nexport interface PageShellProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Which measure the content column is bounded to. `full` removes the cap so\n * the column takes whatever the panel gives it, while KEEPING the gutter — a\n * full-width page is still inset from the panel's edge.\n */\n width?: \"form\" | \"wide\" | \"full\";\n}\n\n/**\n * `CSSProperties` models only the properties csstype knows about, so a CSS\n * custom property is not assignable to it.\n *\n * Naming the single property this component sets keeps the object CHECKED: a\n * typo in the property name is still a compile error, and the value still has\n * to be a string. The blanket `as CSSProperties` assertion used elsewhere in\n * this repo would accept a misspelled custom property silently, which for a\n * value the grid template reads by name is the failure worth preventing — the\n * layout would fall back to its default measure and nothing would say so.\n */\ntype ShellStyle = CSSProperties & Record<\"--nx-shell-measure\", string>;\n\n/**\n * Whether the shell has a direct child TEXT node with visible content.\n *\n * Read from the DOM after mount rather than by walking `children` before it,\n * because the element tree cannot answer this question. A component child is\n * opaque to a pre-render walk — `() => \"hello\"` is an element whose type is a\n * function, and what it returns is decided at render — so a traversal can only\n * ever recognise the shapes someone thought to enumerate: a bare literal, then\n * a fragment, then a component, then a component returning a fragment. The\n * rendered DOM is where the answer already exists, and it covers every shape at\n * once.\n *\n * Whitespace-only nodes are ignored: JSX routinely leaves them between elements\n * and CSS Grid does not make a grid item of one.\n */\nfunction hasBareTextChild(shell: HTMLElement): boolean {\n return Array.from(shell.childNodes).some(\n node => node.nodeType === Node.TEXT_NODE && node.textContent?.trim() !== \"\"\n );\n}\n\n/**\n * A shell already owns the inset somewhere up the tree.\n *\n * Nesting reintroduces the exact defect this primitive exists to end: an outer\n * shell places the inner one in its content column and the inner grid adds a\n * second pair of gutter tracks, so content is inset twice. Relying on every\n * caller to know whether an ancestor layout already rendered a shell is the\n * kind of unwritten precondition that holds until one page is composed\n * differently, so it is REPORTED.\n *\n * It is reported and not silently corrected, which is a deliberate choice\n * between two imperfect options. Suppressing the inner grid means either\n * keeping its wrapper — which lands in the outer content column and puts a\n * `Bleed` below it out of reach of `.nx-page-shell > .nx-bleed`, collapsing a\n * full-bleed block to the measure in PRODUCTION — or dropping the wrapper, and\n * with it the caller's `className`, `style` and `ref`. Both trade a visible,\n * warned mistake for a silent one. A double inset is conspicuous and arrives\n * with a message naming the fix.\n *\n * React context crosses a portal while DOM ancestry does not, so a shell\n * rendered through `createPortal` into a host outside this tree is reported as\n * nested when it is not. That costs a spurious development message and nothing\n * else: what renders no longer depends on this value.\n */\nconst InsideShell = createContext(false);\n\n/**\n * Whether a direct child has been taken out of the grid by `display: contents`.\n *\n * Such a child generates no box, so the `grid-column` rule has nothing to\n * apply to, while ITS children are promoted into this grid and match no\n * selector — they auto-place from the first track, which is a gutter. The\n * element is present and correctly classed, so nothing about the markup says\n * the content left the measure.\n */\nfunction hasDisplayContentsChild(shell: HTMLElement): boolean {\n return Array.from(shell.children).some(\n child => getComputedStyle(child).display === \"contents\"\n );\n}\n\n/**\n * What each named width resolves to, owned here because this is what applies it.\n *\n * Declared as a lookup rather than branched at the call site so the three arms\n * are one list. A `switch` here would let a fourth width be added to the type\n * and forgotten in the mapping, which the checker cannot see through a\n * `default` arm.\n *\n * Exported because a caller whose CONTENT carries the measure needs the same\n * value as a length, and the alternative is a second table naming the same\n * tokens — which drifts silently, since both look correct beside their own\n * neighbours. Reading it here means there is one answer rather than two that\n * agree today.\n *\n * @experimental\n */\nexport const SHELL_MEASURE: Record<\n NonNullable<PageShellProps[\"width\"]>,\n string\n> = {\n form: \"var(--nx-measure-form)\",\n wide: \"var(--nx-measure-wide)\",\n full: \"100%\",\n};\n\n/**\n * The page's inset and measure, owned in one place and spent as GRID COLUMNS.\n *\n * This replaces a pairing in which an outer container padded the panel and an\n * inner one padded again while capping the width. That shape had three\n * defects, and all three are structural rather than cosmetic:\n *\n * - The two insets ADDED, because padding is not something a descendant can\n * cancel. Measured on the settings page, the header sat at x=360 and the\n * form card at x=384 — a 24px disagreement between two elements that are\n * supposed to share a left edge. Here the inset is a column, so there is one\n * declaration and no second site to disagree with it.\n * - A measure applied INSIDE a form component lets anything the page renders\n * beside that form escape it. With the page owning the shell, a sibling is\n * inside the measure by default and leaves it only by saying `Bleed`.\n * - Centring by `mx-auto` on a max-width box does nothing at panel widths\n * where the cap does not bind. Here the two outer tracks are equal and\n * flexible, so the content column is centred at every width and no\n * `justify-content` is declared — with flexible tracks the grid fills its\n * container and there is no free space for one to distribute.\n *\n * Vertical padding stays ordinary `padding-block`: it is not in tension with\n * the columns, and keeping it here means one component answers the whole of\n * \"how far is content from the panel's edge\".\n * @experimental\n */\nexport const PageShell = forwardRef<HTMLDivElement, PageShellProps>(\n ({ width = \"form\", className, children, style, ...props }, ref) => {\n // The shell's own handle on its node, kept alongside whatever ref the\n // caller passed so the development check below can read the rendered DOM\n // without taking the ref away from them.\n const shellRef = useRef<HTMLDivElement | null>(null);\n const attachRef = useCallback(\n (node: HTMLDivElement | null) => {\n shellRef.current = node;\n // A callback ref's RETURN is the caller's cleanup under React 19, and\n // React runs it instead of calling the ref again with null. Discarding\n // it here would silently drop, say, an observer's disconnect. Passing it\n // straight through is also correct under the React 18 half of this\n // package's peer range, where such a ref returns nothing.\n if (typeof ref === \"function\") return ref(node);\n if (ref) ref.current = node;\n },\n [ref]\n );\n\n const nested = useContext(InsideShell);\n\n // Gated on the runtime up front so neither the DOM read nor the observer\n // below exists in production, not merely their console output.\n useEffect(() => {\n if (!isDevelopmentRuntime()) return;\n const shell = shellRef.current;\n if (!shell) return;\n\n devWarnOnce(\n !nested,\n \"PageShell: an ancestor already renders a PageShell. The two grids each add a pair of \" +\n \"gutter tracks, so this page's content is inset twice. Remove this shell, or move \" +\n \"the outer one.\"\n );\n\n const check = () => {\n devWarnOnce(\n !hasBareTextChild(shell),\n \"PageShell: a direct child renders as bare text. CSS Grid wraps it in an anonymous \" +\n \"grid item, which no selector can reach, so it is placed in the gutter rather than \" +\n \"the content column and sits outside the page's measure. Wrap it in an element — \" +\n \"a `<p>`, or the section it belongs to.\"\n );\n devWarnOnce(\n !hasDisplayContentsChild(shell),\n \"PageShell: a direct child has `display: contents`, so it generates no grid item and \" +\n \"the content-column rule has nothing to apply to. Its own children are promoted \" +\n \"into this grid, match no selector, and are placed from the gutter onward. Give \" +\n \"the child a box, or move `display: contents` inside it.\"\n );\n };\n\n check();\n\n // A child that swaps an element for text through its OWN state does not\n // re-render this component, so the effect above would never run again and\n // the defect would arrive unreported. Watching the child list is what\n // makes the check a property of the rendered DOM rather than of when this\n // component happened to render.\n //\n // `childList` ALONE, deliberately, and this is the boundary of the check\n // rather than an oversight. A child that stays mounted and mutates its\n // own class or style to `display: contents` is not reported, because\n // catching it needs `attributes` with `subtree: true` — MutationObserver\n // cannot scope attributes to direct children — which fires on every\n // descendant class change anywhere in the page. In an admin full of hover\n // states, transitions and editor chrome that is continuous, and each\n // notification re-runs `getComputedStyle` over every direct child.\n //\n // This is an advisory development warning: a miss costs only the report,\n // while a check that makes every developer's page churn is one that gets\n // deleted, taking its true positives with it. The mount-time pass above\n // still catches `display: contents` present at first render, which is how\n // it is almost always written.\n const observer = new MutationObserver(check);\n observer.observe(shell, { childList: true });\n return () => {\n observer.disconnect();\n };\n });\n\n // The caller's `style` is spread FIRST so the measure this component\n // computes from `width` wins over a hand-written `--nx-shell-measure`.\n // Two sources for one value would otherwise disagree silently, and\n // `width` is the supported way to choose it.\n const shellStyle: ShellStyle = {\n ...style,\n \"--nx-shell-measure\": SHELL_MEASURE[width],\n };\n\n return (\n <InsideShell.Provider value={true}>\n <div\n ref={attachRef}\n data-slot=\"page-shell\"\n // The measure travels as a custom property rather than as a utility\n // class because the grid template reads it: one `grid-template-columns`\n // serves all three widths, instead of three near-identical templates\n // that would each have to be corrected together.\n style={shellStyle}\n className={cn(\"nx-page-shell py-8\", className)}\n {...props}\n >\n {children}\n </div>\n </InsideShell.Provider>\n );\n }\n);\nPageShell.displayName = \"PageShell\";\n\n/** @experimental */\nexport type BleedProps = HTMLAttributes<HTMLDivElement>;\n\n/**\n * Opts one child out of the measure, edge to edge across the shell's gutter.\n *\n * The sanctioned form of something that previously only happened by accident.\n * A wide data table, a delivery log or a toolbar declares that it wants the\n * full panel, so a reviewer can see the intent — and, just as usefully, a block\n * that is merely in the wrong place no longer LOOKS like a deliberate\n * full-bleed.\n *\n * Valid only as a DIRECT child of `PageShell`. The `full-start`/`full-end`\n * lines are named on the shell's own grid, so they are in scope for its\n * children and nowhere else; nested inside a `FormSection` this renders a plain\n * block and the `grid-column` is inert. That is a real constraint rather than a\n * stylistic preference, and `page-shell.test.tsx` pins both halves: that a\n * `Bleed` rendered directly under the shell is its child, and that one nested a\n * level deeper does NOT receive the full column.\n *\n * It forwards its ref and any div attributes for the same reason: a consumer\n * cannot reach for the usual remedy of wrapping it, because a wrapper is\n * precisely what makes it stop working.\n * @experimental\n */\nexport const Bleed = forwardRef<HTMLDivElement, BleedProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n data-slot=\"bleed\"\n className={cn(\"nx-bleed\", className)}\n {...props}\n >\n {children}\n </div>\n )\n);\nBleed.displayName = \"Bleed\";\n","import type { HTMLAttributes, ReactNode } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../lib/utils\";\n\n/** @experimental */\nexport interface PageHeaderProps\n extends Omit<HTMLAttributes<HTMLElement>, \"title\"> {\n /** The page's name, rendered as its `h1`. */\n title: string;\n /**\n * A sentence under the title. A `ReactNode` rather than a string because a\n * description carrying a link or an inline code span is ordinary here, and\n * typing it narrowly would push those pages back to hand-rolling the header.\n */\n description?: ReactNode;\n /** The trail above the title. The page supplies it; this only places it. */\n breadcrumbs?: ReactNode;\n /** Page-level actions, trailing the title on one line where there is room. */\n actions?: ReactNode;\n}\n\n/**\n * A page's own identity — its trail, its name, its one-line summary and its\n * actions — rendered once instead of at every page that needs one.\n *\n * Every value arrives as a PROP, and that is the point rather than an\n * implementation detail. The markup this replaces was written out by hand on 22\n * pages, and the settings pages took their title from a ~130-line chain that\n * matched `window.location.pathname` in a file none of them import. Both are\n * the same defect from opposite ends: a page knows what it is, and nothing let\n * it say so — so the title lived either in 22 copies or in one foreign file\n * that had to be edited whenever a route was added.\n *\n * The route registry already made this decision for the sidebar. A private\n * route must DECLARE the rail section it belongs to, because the sidebar reads\n * that declaration rather than matching the URL, which makes a route added\n * without one a compile error instead of a page that silently highlights the\n * wrong entry. A title derived from a pathname is the same defect in the half\n * nobody had covered.\n *\n * It also makes a plugin's page indistinguishable from a first-party one: a\n * plugin cannot add a branch to an if-chain it does not ship, but it can pass a\n * prop.\n * @experimental\n */\nexport const PageHeader = forwardRef<HTMLElement, PageHeaderProps>(\n ({ title, description, breadcrumbs, actions, className, ...props }, ref) => (\n <header\n ref={ref}\n data-slot=\"page-header\"\n className={cn(\"mb-8\", className)}\n {...props}\n >\n {breadcrumbs ? <div className=\"mb-6\">{breadcrumbs}</div> : null}\n\n <div className=\"flex flex-col justify-between gap-4 sm:flex-row sm:items-center\">\n <div className=\"space-y-1\">\n <h1 className=\"text-xl font-semibold tracking-tight\">{title}</h1>\n {/* Muted rather than a faint tint of the primary: the latter was tried\n and did not meet contrast for secondary text. */}\n {description ? (\n <p className=\"mt-1 text-sm font-normal text-muted-foreground\">\n {description}\n </p>\n ) : null}\n </div>\n\n {/* Each optional slot is omitted rather than rendered empty. An empty\n <p> still occupies a line and still separates the title from what\n follows, so a title-only page would not keep the spacing of a page\n that never had a description. */}\n {actions ? (\n <div className=\"flex items-center gap-3\">{actions}</div>\n ) : null}\n </div>\n </header>\n )\n);\nPageHeader.displayName = \"PageHeader\";\n"],"mappings":"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","names":["CollapsibleContent","CollapsibleTrigger","import_class_variance_authority","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","LabelRoot","React","import_react","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_class_variance_authority","import_jsx_runtime","import_class_variance_authority","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_class_variance_authority","import_react","import_jsx_runtime","import_jsx_runtime","React","import_jsx_runtime","import_class_variance_authority","React","import_jsx_runtime","import_lucide_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","SwitchRoot","SwitchThumb","CollapsibleTrigger","CollapsibleContent","import_lucide_react","import_react","import_jsx_runtime","import_class_variance_authority","import_react","import_jsx_runtime","AvatarRoot","AvatarImagePrimitive","AvatarFallbackPrimitive","import_class_variance_authority","import_react","import_jsx_runtime","React","import_jsx_runtime","import_class_variance_authority","import_lucide_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_lucide_react","React","import_jsx_runtime","import_class_variance_authority","import_lucide_react","import_react","import_jsx_runtime","DialogPrimitive","import_class_variance_authority","React","import_jsx_runtime","DialogPrimitive","import_lucide_react","import_react","import_jsx_runtime","CommandPrimitive","useCommandStatePrimitive","import_class_variance_authority","import_lucide_react","import_react","import_jsx_runtime","import_lucide_react","import_jsx_runtime","Sonner","React","import_jsx_runtime","import_lucide_react","import_jsx_runtime","import_lucide_react","import_jsx_runtime","import_jsx_runtime","_","import_lucide_react","React","clamp01","clamp01","React","import_jsx_runtime","import_lucide_react","React","import_jsx_runtime","menuItemBase","import_lucide_react","import_jsx_runtime","import_lucide_react","React","import_jsx_runtime","React","import_jsx_runtime","React","options","import_jsx_runtime","import_class_variance_authority","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime"]}