@ngrok/mantle 0.76.2 → 0.76.4
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.
- package/README.md +8 -8
- package/dist/accordion.d.ts +1 -2
- package/dist/accordion.js +1 -2
- package/dist/agent.json +1 -1
- package/dist/alert-dialog.d.ts +4 -45
- package/dist/alert-dialog.js +1 -2
- package/dist/alert.d.ts +2 -3
- package/dist/alert.js +1 -2
- package/dist/anchor-CcTY5SIz.js +1 -2
- package/dist/anchor.d.ts +1 -2
- package/dist/as-child-uN_018tj.d.ts +1 -2
- package/dist/badge.d.ts +1 -2
- package/dist/badge.js +1 -2
- package/dist/booleanish-BfvnW6vy.js +1 -2
- package/dist/browser-only-BSl_hruR.js +1 -2
- package/dist/browser-only.d.ts +1 -2
- package/dist/button-BAxneEMu.js +1 -2
- package/dist/{button-uMIZVKit.js → button-BfMn3PgP.js} +1 -2
- package/dist/button-mfYak6Rx.d.ts +71 -0
- package/dist/button.d.ts +3 -3
- package/dist/button.js +1 -1
- package/dist/calendar.d.ts +2 -3
- package/dist/calendar.js +1 -2
- package/dist/card.d.ts +1 -2
- package/dist/card.js +1 -2
- package/dist/checkbox.d.ts +30 -2
- package/dist/checkbox.js +1 -2
- package/dist/code-block.d.ts +1 -2
- package/dist/code-block.js +2 -3
- package/dist/code-block_highlight-utils.js +1 -1
- package/dist/code.d.ts +1 -2
- package/dist/code.js +1 -2
- package/dist/color.js +1 -2
- package/dist/combobox.d.ts +1 -2
- package/dist/combobox.js +1 -2
- package/dist/command.d.ts +3 -4
- package/dist/command.js +1 -2
- package/dist/compose-refs-Cjf2gfB8.js +1 -2
- package/dist/copy-to-clipboard-Baw30q9O.js +1 -2
- package/dist/cx-CBSnSC36.js +1 -2
- package/dist/cx.d.ts +1 -2
- package/dist/data-table.d.ts +124 -45
- package/dist/data-table.js +1 -2
- package/dist/description-list.d.ts +1 -2
- package/dist/description-list.js +1 -2
- package/dist/{dialog-DR2V7zsR.js → dialog-ebkUwitP.js} +1 -2
- package/dist/dialog.d.ts +2 -3
- package/dist/dialog.js +1 -1
- package/dist/direction-CcTY0FmA.d.ts +1 -2
- package/dist/direction-Wa9W2F61.js +1 -2
- package/dist/{dropdown-menu-C3YZJBkV.js → dropdown-menu-BHyYWtrH.js} +1 -2
- package/dist/dropdown-menu-BqdyTFLu.d.ts +1 -2
- package/dist/dropdown-menu.js +1 -1
- package/dist/empty.d.ts +1 -2
- package/dist/empty.js +1 -2
- package/dist/field-context-4k1kI7Bo.js +1 -2
- package/dist/field.d.ts +3 -4
- package/dist/field.js +1 -2
- package/dist/flag.d.ts +1 -2
- package/dist/flag.js +1 -2
- package/dist/hooks.d.ts +1 -2
- package/dist/hooks.js +1 -2
- package/dist/hover-card.d.ts +1 -2
- package/dist/hover-card.js +1 -2
- package/dist/icon-C8bYBIHW.js +1 -2
- package/dist/{icon-button-ntupABbM.d.ts → icon-button-D7hs6bX2.d.ts} +52 -44
- package/dist/{icon-button-C_Ht_g1C.js → icon-button-DUNHVWpb.js} +1 -2
- package/dist/icon-n49kOh4_.d.ts +1 -2
- package/dist/icons.d.ts +1 -2
- package/dist/icons.js +1 -2
- package/dist/in-view-BC3wmz-a.d.ts +1 -2
- package/dist/in-view-C2DpZ6s0.js +1 -2
- package/dist/{index-L3NmbHi5.d.ts → index-Bed_XLWa.d.ts} +16 -2
- package/dist/{index-BL5WVva_.d.ts → index-CJbKEKr2.d.ts} +4 -3
- package/dist/{index-DBZ3eRsl.d.ts → index-CTU6apE6.d.ts} +2 -3
- package/dist/index-DorCusfG.d.ts +1 -2
- package/dist/input.d.ts +4 -5
- package/dist/input.js +1 -2
- package/dist/is-input-CXmS0OFN.js +1 -2
- package/dist/kbd-Bv6tefdB.js +1 -2
- package/dist/kbd.d.ts +1 -2
- package/dist/label-DhIUmTN2.js +1 -2
- package/dist/label.d.ts +1 -2
- package/dist/llms.txt +1 -1
- package/dist/main.d.ts +1 -2
- package/dist/main.js +1 -2
- package/dist/mantle.css +191 -14
- package/dist/media-object.d.ts +1 -2
- package/dist/media-object.js +1 -2
- package/dist/multi-select.d.ts +1 -2
- package/dist/multi-select.js +1 -2
- package/dist/otp-input.d.ts +1 -2
- package/dist/otp-input.js +1 -2
- package/dist/pagination.d.ts +2 -3
- package/dist/pagination.js +1 -2
- package/dist/popover-DponNBot.js +1 -2
- package/dist/popover.d.ts +1 -2
- package/dist/primitive-Cn3h4DJg.js +1 -2
- package/dist/primitive-FoWela9a.d.ts +1 -2
- package/dist/progress.d.ts +1 -2
- package/dist/progress.js +1 -2
- package/dist/qr-code.d.ts +1 -2
- package/dist/qr-code.js +1 -2
- package/dist/radio-group.d.ts +1 -2
- package/dist/radio-group.js +1 -2
- package/dist/{resolve-pre-rendered-props-C-vrNxH1.js → resolve-pre-rendered-props-D9nlC6xE.js} +2 -3
- package/dist/resolve-pre-rendered-props-DxJ9-DAl.d.ts +1 -2
- package/dist/sandboxed-on-click.d.ts +2 -2
- package/dist/sandboxed-on-click.js +1 -2
- package/dist/select-C15-XvRT.d.ts +1 -2
- package/dist/{select-Cxc9VmP8.js → select-g0E_TsXr.js} +1 -2
- package/dist/select.js +1 -1
- package/dist/{separator-Bqjy77rG.js → separator-BXFUCWFa.js} +1 -2
- package/dist/separator.d.ts +1 -2
- package/dist/separator.js +1 -1
- package/dist/sheet.d.ts +3 -4
- package/dist/sheet.js +1 -2
- package/dist/skeleton.d.ts +1 -2
- package/dist/skeleton.js +1 -2
- package/dist/skip-to-main-link.d.ts +1 -2
- package/dist/skip-to-main-link.js +1 -2
- package/dist/slider.d.ts +1 -2
- package/dist/slider.js +1 -2
- package/dist/slot-CV5fmqFr.js +1 -2
- package/dist/slot.d.ts +1 -1
- package/dist/sort-BPX2Fk9t.js +1 -2
- package/dist/split-button.d.ts +5 -6
- package/dist/split-button.js +1 -2
- package/dist/svg-only-Cz1cby8y.js +1 -2
- package/dist/svg-only-f6ToFLH0.d.ts +1 -2
- package/dist/switch.d.ts +1 -2
- package/dist/switch.js +1 -2
- package/dist/table-BWD9IlIN.d.ts +1 -2
- package/dist/table-DWy_oNta.js +1 -0
- package/dist/table.js +1 -1
- package/dist/tabs.d.ts +1 -2
- package/dist/tabs.js +1 -2
- package/dist/text-area.d.ts +1 -2
- package/dist/text-area.js +1 -2
- package/dist/theme-provider-MMwxHEfw.js +1 -2
- package/dist/theme.d.ts +4 -5
- package/dist/theme.js +1 -2
- package/dist/themes-CYNpplwN.d.ts +1 -2
- package/dist/toast-CR3MVChj.js +1 -2
- package/dist/toast.d.ts +1 -2
- package/dist/tooltip.d.ts +1 -2
- package/dist/tooltip.js +1 -2
- package/dist/traffic-policy-file-0g5RXFqu.js +1 -2
- package/dist/types-BvUzforF.d.ts +1 -2
- package/dist/types-D85fCNV3.js +1 -2
- package/dist/types.d.ts +1 -3
- package/dist/use-copy-to-clipboard-BLpquU9d.js +1 -2
- package/dist/use-isomorphic-layout-effect-DdTRtMY-.js +1 -2
- package/dist/use-matches-media-query-CMSxHR9n.js +1 -2
- package/dist/use-prefers-reduced-motion-CWIoFA6W.js +1 -2
- package/dist/utils.d.ts +1 -2
- package/dist/utils.js +1 -2
- package/dist/validation-DCyx-ceH.js +1 -2
- package/dist/validation-xyX_6kph.d.ts +1 -2
- package/dist/well.d.ts +1 -2
- package/dist/well.js +1 -2
- package/dist/with-style-props-CyImx7vd.d.ts +1 -2
- package/package.json +22 -22
- package/dist/accordion.js.map +0 -1
- package/dist/alert-dialog.js.map +0 -1
- package/dist/alert.js.map +0 -1
- package/dist/anchor-CcTY5SIz.js.map +0 -1
- package/dist/badge.js.map +0 -1
- package/dist/booleanish-BfvnW6vy.js.map +0 -1
- package/dist/browser-only-BSl_hruR.js.map +0 -1
- package/dist/button-BAxneEMu.js.map +0 -1
- package/dist/button-BYZOBUgj.d.ts +0 -172
- package/dist/button-uMIZVKit.js.map +0 -1
- package/dist/calendar.js.map +0 -1
- package/dist/card.js.map +0 -1
- package/dist/checkbox.js.map +0 -1
- package/dist/code-block.js.map +0 -1
- package/dist/code.js.map +0 -1
- package/dist/color.js.map +0 -1
- package/dist/combobox.js.map +0 -1
- package/dist/command.js.map +0 -1
- package/dist/compose-refs-Cjf2gfB8.js.map +0 -1
- package/dist/copy-to-clipboard-Baw30q9O.js.map +0 -1
- package/dist/cx-CBSnSC36.js.map +0 -1
- package/dist/data-table.js.map +0 -1
- package/dist/deep-non-nullable-BxRoySYR.d.ts +0 -8
- package/dist/description-list.js.map +0 -1
- package/dist/dialog-DR2V7zsR.js.map +0 -1
- package/dist/direction-Wa9W2F61.js.map +0 -1
- package/dist/dropdown-menu-C3YZJBkV.js.map +0 -1
- package/dist/empty.js.map +0 -1
- package/dist/field-context-4k1kI7Bo.js.map +0 -1
- package/dist/field.js.map +0 -1
- package/dist/flag.js.map +0 -1
- package/dist/hooks.js.map +0 -1
- package/dist/hover-card.js.map +0 -1
- package/dist/icon-C8bYBIHW.js.map +0 -1
- package/dist/icon-button-C_Ht_g1C.js.map +0 -1
- package/dist/icons.js.map +0 -1
- package/dist/in-view-C2DpZ6s0.js.map +0 -1
- package/dist/input.js.map +0 -1
- package/dist/is-input-CXmS0OFN.js.map +0 -1
- package/dist/kbd-Bv6tefdB.js.map +0 -1
- package/dist/label-DhIUmTN2.js.map +0 -1
- package/dist/main.js.map +0 -1
- package/dist/media-object.js.map +0 -1
- package/dist/multi-select.js.map +0 -1
- package/dist/otp-input.js.map +0 -1
- package/dist/pagination.js.map +0 -1
- package/dist/popover-DponNBot.js.map +0 -1
- package/dist/primitive-Cn3h4DJg.js.map +0 -1
- package/dist/progress.js.map +0 -1
- package/dist/qr-code.js.map +0 -1
- package/dist/radio-group.js.map +0 -1
- package/dist/resolve-pre-rendered-props-C-vrNxH1.js.map +0 -1
- package/dist/sandboxed-on-click.js.map +0 -1
- package/dist/select-Cxc9VmP8.js.map +0 -1
- package/dist/separator-Bqjy77rG.js.map +0 -1
- package/dist/sheet.js.map +0 -1
- package/dist/skeleton.js.map +0 -1
- package/dist/skip-to-main-link.js.map +0 -1
- package/dist/slider.js.map +0 -1
- package/dist/slot-CV5fmqFr.js.map +0 -1
- package/dist/sort-BPX2Fk9t.js.map +0 -1
- package/dist/split-button.js.map +0 -1
- package/dist/svg-only-Cz1cby8y.js.map +0 -1
- package/dist/switch.js.map +0 -1
- package/dist/table-eyoUW2Uv.js +0 -2
- package/dist/table-eyoUW2Uv.js.map +0 -1
- package/dist/tabs.js.map +0 -1
- package/dist/text-area.js.map +0 -1
- package/dist/theme-provider-MMwxHEfw.js.map +0 -1
- package/dist/theme.js.map +0 -1
- package/dist/toast-CR3MVChj.js.map +0 -1
- package/dist/tooltip.js.map +0 -1
- package/dist/traffic-policy-file-0g5RXFqu.js.map +0 -1
- package/dist/types-D85fCNV3.js.map +0 -1
- package/dist/use-copy-to-clipboard-BLpquU9d.js.map +0 -1
- package/dist/use-isomorphic-layout-effect-DdTRtMY-.js.map +0 -1
- package/dist/use-matches-media-query-CMSxHR9n.js.map +0 -1
- package/dist/use-prefers-reduced-motion-CWIoFA6W.js.map +0 -1
- package/dist/utils.js.map +0 -1
- package/dist/validation-DCyx-ceH.js.map +0 -1
- package/dist/variant-props-CVymuSfa.d.ts +0 -13
- package/dist/well.js.map +0 -1
package/dist/hover-card.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hover-card.js","names":[],"sources":["../src/components/hover-card/hover-card.tsx"],"sourcesContent":["\"use client\";\n\nimport * as HoverCardPrimitive from \"@radix-ui/react-hover-card\";\nimport { forwardRef } from \"react\";\nimport type { ComponentPropsWithoutRef, ComponentRef } from \"react\";\nimport { cx } from \"../../utils/cx/cx.js\";\n\n/**\n * A floating card that appears when a user hovers over a trigger element.\n * This is the root, stateful component that manages the open/closed state of the hover card.\n *\n * @see https://mantle.ngrok.com/components/hover-card#hovercardroot\n *\n * @example\n * ```tsx\n * <HoverCard.Root>\n * <HoverCard.Trigger asChild>\n * <Button type=\"button\" appearance=\"outlined\">\n * Hover me\n * </Button>\n * </HoverCard.Trigger>\n * <HoverCard.Content>\n * <p>This is the hover card content.</p>\n * </HoverCard.Content>\n * </HoverCard.Root>\n * ```\n */\nconst Root = ({\n\tcloseDelay = 300,\n\topenDelay = 100,\n\t...props\n}: ComponentPropsWithoutRef<typeof HoverCardPrimitive.Root>) => (\n\t<HoverCardPrimitive.Root closeDelay={closeDelay} openDelay={openDelay} {...props} />\n);\nRoot.displayName = \"HoverCard\";\n\n/**\n * The trigger element that opens the hover card when hovered.\n *\n * @see https://mantle.ngrok.com/components/hover-card#hovercardtrigger\n *\n * @example\n * ```tsx\n * <HoverCard.Root>\n * <HoverCard.Trigger asChild>\n * <Button type=\"button\" appearance=\"outlined\">\n * Hover me\n * </Button>\n * </HoverCard.Trigger>\n * <HoverCard.Content>\n * <p>This is the hover card content.</p>\n * </HoverCard.Content>\n * </HoverCard.Root>\n * ```\n */\nconst Trigger = forwardRef<\n\tComponentRef<typeof HoverCardPrimitive.Trigger>,\n\tComponentPropsWithoutRef<typeof HoverCardPrimitive.Trigger>\n>((props, ref) => (\n\t<HoverCardPrimitive.Trigger ref={ref} data-slot=\"hover-card-trigger\" {...props} />\n));\nTrigger.displayName = \"HoverCardTrigger\";\n\n/**\n * The portal container for rendering hover card content outside the normal DOM tree.\n * `HoverCard.Content` already renders inside this portal internally, so you typically\n * do not need to use `HoverCard.Portal` directly. Use it only when you need to\n * customize portal placement (e.g., pass a `container` prop) or wrap multiple\n * `HoverCard.Content` instances in a shared portal.\n *\n * @see https://mantle.ngrok.com/components/hover-card#hovercardportal\n *\n * @example\n * ```tsx\n * <HoverCard.Root>\n * <HoverCard.Trigger asChild>\n * <Button type=\"button\" appearance=\"outlined\">\n * Hover me\n * </Button>\n * </HoverCard.Trigger>\n * <HoverCard.Portal>\n * <HoverCard.Content>\n * <p>This is the hover card content.</p>\n * </HoverCard.Content>\n * </HoverCard.Portal>\n * </HoverCard.Root>\n * ```\n */\nconst Portal = HoverCardPrimitive.Portal;\nPortal.displayName = \"HoverCardPortal\";\n\n/**\n * The content to render inside the hover card.\n *\n * @see https://mantle.ngrok.com/components/hover-card#hovercardcontent\n *\n * @example\n * ```tsx\n * <HoverCard.Root>\n * <HoverCard.Trigger asChild>\n * <Button type=\"button\" appearance=\"outlined\">\n * Hover me\n * </Button>\n * </HoverCard.Trigger>\n * <HoverCard.Content>\n * <p>This is the hover card content.</p>\n * </HoverCard.Content>\n * </HoverCard.Root>\n * ```\n */\nconst Content = forwardRef<\n\tComponentRef<typeof HoverCardPrimitive.Content>,\n\tComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>\n>(({ className, onClick, align = \"center\", sideOffset = 4, ...props }, ref) => (\n\t<Portal>\n\t\t<HoverCardPrimitive.Content\n\t\t\tref={ref}\n\t\t\tdata-slot=\"hover-card-content\"\n\t\t\talign={align}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={cx(\n\t\t\t\t\"bg-popover border-popover z-50 w-64 rounded-md border p-4 shadow-md outline-hidden\",\n\t\t\t\t\"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\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tonClick={(event) => {\n\t\t\t\t/**\n\t\t\t\t * Prevent the click event from propagating up to parent/containing elements\n\t\t\t\t */\n\t\t\t\tevent.stopPropagation();\n\t\t\t\tonClick?.(event);\n\t\t\t}}\n\t\t\t{...props}\n\t\t/>\n\t</Portal>\n));\nContent.displayName = HoverCardPrimitive.Content.displayName;\n\n/**\n * A floating card that appears when a user hovers over a trigger element.\n *\n * Use `HoverCard` for non-essential preview content shown on HOVER — user\n * cards, repo previews, rich link previews. Because hover is not reachable\n * via keyboard, all content inside a `HoverCard` must be supplemental,\n * never the only path to information; the trigger is typically a link that\n * already leads to the same content for keyboard and screen reader users.\n * For short, non-interactive labels or hints, use `Tooltip`. For\n * interactive overlays the user opens deliberately, use `Popover`.\n *\n * @see https://mantle.ngrok.com/components/hover-card\n *\n * @example\n * Composition:\n * ```\n * HoverCard.Root\n * ├── HoverCard.Trigger\n * └── HoverCard.Content\n * ```\n *\n * @example\n * ```tsx\n * <HoverCard.Root>\n * <HoverCard.Trigger asChild>\n * <Button type=\"button\" appearance=\"outlined\">\n * Hover me\n * </Button>\n * </HoverCard.Trigger>\n * <HoverCard.Content>\n * <p>This is the hover card content.</p>\n * </HoverCard.Content>\n * </HoverCard.Root>\n * ```\n */\nconst HoverCard = {\n\t/**\n\t * The root, stateful component that manages the open/closed state of the hover card.\n\t *\n\t * @see https://mantle.ngrok.com/components/hover-card#hovercardroot\n\t *\n\t * @example\n\t * ```tsx\n\t * <HoverCard.Root>\n\t * <HoverCard.Trigger asChild>\n\t * <Button>Hover me</Button>\n\t * </HoverCard.Trigger>\n\t * <HoverCard.Content>\n\t * <p>This is the hover card content.</p>\n\t * </HoverCard.Content>\n\t * </HoverCard.Root>\n\t * ```\n\t */\n\tRoot,\n\t/**\n\t * The content to render inside the hover card. Appears in a portal with rich styling and animations.\n\t *\n\t * @see https://mantle.ngrok.com/components/hover-card#hovercardcontent\n\t *\n\t * @example\n\t * ```tsx\n\t * <HoverCard.Root>\n\t * <HoverCard.Trigger asChild>\n\t * <Button type=\"button\" variant=\"link\">@username</Button>\n\t * </HoverCard.Trigger>\n\t * <HoverCard.Content side=\"top\">\n\t * <div className=\"space-y-2\">\n\t * <Text weight=\"strong\">User Profile</Text>\n\t * <Text>Additional information about the user.</Text>\n\t * <Button type=\"button\" size=\"sm\">Follow</Button>\n\t * </div>\n\t * </HoverCard.Content>\n\t * </HoverCard.Root>\n\t * ```\n\t */\n\tContent,\n\t/**\n\t * The portal container for rendering hover card content outside the normal DOM tree.\n\t * `HoverCard.Content` already renders inside this portal internally, so you typically\n\t * do not need to use `HoverCard.Portal` directly. Use it only when you need to\n\t * customize portal placement or wrap multiple `HoverCard.Content` instances.\n\t *\n\t * @see https://mantle.ngrok.com/components/hover-card#hovercardportal\n\t *\n\t * @example\n\t * ```tsx\n\t * <HoverCard.Root>\n\t * <HoverCard.Trigger asChild>\n\t * <Button type=\"button\" appearance=\"outlined\">\n\t * Hover me\n\t * </Button>\n\t * </HoverCard.Trigger>\n\t * <HoverCard.Portal>\n\t * <HoverCard.Content>\n\t * <p>This is the hover card content.</p>\n\t * </HoverCard.Content>\n\t * </HoverCard.Portal>\n\t * </HoverCard.Root>\n\t * ```\n\t */\n\tPortal,\n\t/**\n\t * The trigger element that opens the hover card when hovered.\n\t *\n\t * @see https://mantle.ngrok.com/components/hover-card#hovercardtrigger\n\t *\n\t * @example\n\t * ```tsx\n\t * <HoverCard.Root>\n\t * <HoverCard.Trigger asChild>\n\t * <Button type=\"button\" variant=\"ghost\">\n\t * Hover for details\n\t * </Button>\n\t * </HoverCard.Trigger>\n\t * <HoverCard.Content>\n\t * <div className=\"space-y-1\">\n\t * <Text weight=\"strong\">Quick Info</Text>\n\t * <Text>This appears when you hover over the trigger.</Text>\n\t * </div>\n\t * </HoverCard.Content>\n\t * </HoverCard.Root>\n\t * ```\n\t */\n\tTrigger,\n} as const;\n\nexport {\n\t//,\n\tHoverCard,\n};\n"],"mappings":"6JA2BA,MAAM,GAAQ,CACb,aAAa,IACb,YAAY,IACZ,GAAG,KAEH,EAAC,EAAmB,KAApB,CAAqC,aAAuB,YAAW,GAAI,CAAQ,CAAA,EAEpF,EAAK,YAAc,YAqBnB,MAAM,EAAU,GAGb,EAAO,IACT,EAAC,EAAmB,QAApB,CAAiC,MAAK,YAAU,qBAAqB,GAAI,CAAQ,CAAA,CACjF,EACD,EAAQ,YAAc,mBA2BtB,MAAM,EAAS,EAAmB,OAClC,EAAO,YAAc,kBAqBrB,MAAM,EAAU,GAGb,CAAE,YAAW,UAAS,QAAQ,SAAU,aAAa,EAAG,GAAG,GAAS,IACtE,EAAC,EAAD,CAAA,SACC,EAAC,EAAmB,QAApB,CACM,MACL,YAAU,qBACH,QACK,aACZ,UAAW,EACV,qFACA,+TACA,CACD,EACA,QAAU,GAAU,CAInB,EAAM,gBAAgB,EACtB,IAAU,CAAK,CAChB,EACA,GAAI,CACJ,CAAA,CACM,CAAA,CACR,EACD,EAAQ,YAAc,EAAmB,QAAQ,YAqCjD,MAAM,EAAY,CAkBjB,OAsBA,UAyBA,SAuBA,SACD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"icon-C8bYBIHW.js","names":[],"sources":["../src/components/icon/icon.tsx"],"sourcesContent":["import { type ComponentRef, type ReactNode, forwardRef } from \"react\";\nimport { cx } from \"../../utils/cx/cx.js\";\nimport { SvgOnly } from \"./svg-only.js\";\nimport type { SvgAttributes } from \"./types.js\";\n\ntype IconProps = Omit<SvgAttributes, \"children\"> & {\n\t/**\n\t * A single SVG icon element.\n\t */\n\tsvg: ReactNode;\n};\n\n/**\n * Decorates an svg icon with automatic sizing styles and a `shrink-0` class.\n *\n * @see https://mantle.ngrok.com/components/icon\n *\n * @example\n * ```tsx\n * import { ShrimpIcon } from \"@phosphor-icons/react/Shrimp\";\n *\n * <Icon svg={<ShrimpIcon />} />\n * ```\n */\nconst Icon = forwardRef<ComponentRef<\"svg\">, IconProps>(\n\t({ className, style, svg, ...props }, ref) => (\n\t\t<SvgOnly\n\t\t\tref={ref}\n\t\t\tdata-slot=\"icon\"\n\t\t\tclassName={cx(\"size-5\", className)}\n\t\t\tstyle={style}\n\t\t\tsvg={svg}\n\t\t\t{...props}\n\t\t/>\n\t),\n);\nIcon.displayName = \"Icon\";\n\nexport {\n\t//,\n\tIcon,\n};\n\nexport type {\n\t//,\n\tIconProps,\n};\n"],"mappings":"sJAwBA,MAAM,EAAO,GACX,CAAE,YAAW,QAAO,MAAK,GAAG,GAAS,IACrC,EAAC,EAAD,CACM,MACL,YAAU,OACV,UAAW,EAAG,SAAU,CAAS,EAC1B,QACF,MACL,GAAI,CACJ,CAAA,CAEH,EACA,EAAK,YAAc"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"icon-button-C_Ht_g1C.js","names":[],"sources":["../src/components/button/icon-button.tsx"],"sourcesContent":["import { CircleNotchIcon } from \"@phosphor-icons/react/CircleNotch\";\nimport { cva } from \"class-variance-authority\";\nimport type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { Children, cloneElement, forwardRef, isValidElement } from \"react\";\nimport invariant from \"tiny-invariant\";\nimport type { VariantProps, WithAsChild } from \"../../types/index.js\";\nimport { parseBooleanish } from \"../../types/index.js\";\nimport { cx } from \"../../utils/cx/cx.js\";\nimport { Icon } from \"../icon/index.js\";\nimport { Slot } from \"../slot/index.js\";\n\nconst baseIconButtonClasses = cx(\n\t\"icon-button\",\n\t\"inline-flex shrink-0 items-center justify-center rounded-[var(--icon-button-border-radius,0.375rem)] border\",\n\t\"focus:outline-hidden focus-visible:ring-4\",\n\t\"disabled:cursor-default disabled:opacity-50\",\n\t\"not-disabled:active:scale-97 ease-out transition-transform duration-150\",\n);\n\nconst iconButtonVariants = cva(baseIconButtonClasses, {\n\tvariants: {\n\t\t/**\n\t\t * Defines the visual style of the Button.\n\t\t */\n\t\tappearance: {\n\t\t\tghost:\n\t\t\t\t\"text-strong focus-visible:ring-focus-accent not-disabled:hover:bg-neutral-500/10 not-disabled:hover:text-strong border-transparent\",\n\t\t\toutlined:\n\t\t\t\t\"border-form bg-form text-strong focus-visible:border-accent-600 focus-visible:ring-focus-accent not-disabled:hover:border-neutral-400 not-disabled:hover:bg-form-hover not-disabled:hover:text-strong focus-visible:not-disabled:hover:border-accent-600 focus-visible:not-disabled:active:border-accent-600\",\n\t\t},\n\t\t/**\n\t\t * Whether or not the button is in a loading state, default `false`. Setting `isLoading` will\n\t\t * replace the `icon` with a spinner.\n\t\t * It will also disable user interaction with the button and set `aria-disabled`.\n\t\t */\n\t\tisLoading: {\n\t\t\tfalse: \"\",\n\t\t\ttrue: \"opacity-50\",\n\t\t},\n\t\t/**\n\t\t * The size of the IconButton.\n\t\t */\n\t\tsize: {\n\t\t\txs: \"size-6\",\n\t\t\tsm: \"size-7\",\n\t\t\tmd: \"size-9\",\n\t\t},\n\t},\n\tdefaultVariants: {\n\t\tappearance: \"outlined\",\n\t\tsize: \"md\",\n\t},\n});\n\ntype IconButtonVariants = VariantProps<typeof iconButtonVariants>;\n\n/**\n * The props for the `Button` component.\n */\ntype IconButtonProps = ButtonHTMLAttributes<HTMLButtonElement> &\n\tWithAsChild &\n\tIconButtonVariants & {\n\t\t/**\n\t\t * The accessible label for the icon. This label will be visually hidden but announced to screen reader users, similar to alt text for img tags.\n\t\t */\n\t\tlabel: string;\n\t\t/**\n\t\t * An icon to render inside the button. If the `state` is `\"pending\"`, then\n\t\t * the icon will automatically be replaced with a spinner.\n\t\t */\n\t\ticon: ReactNode;\n\t} & (\n\t\t| {\n\t\t\t\t/**\n\t\t\t\t * Use the `asChild` prop to compose Radix's functionality onto alternative\n\t\t\t\t * element types or your own React components.\n\t\t\t\t *\n\t\t\t\t * When `asChild` is set to `true`, mantle will not render a default DOM\n\t\t\t\t * element, instead cloning the component's child and passing it the props and\n\t\t\t\t * behavior required to make it functional.\n\t\t\t\t *\n\t\t\t\t * asChild can be used as deeply as you need to. This means it is a great way\n\t\t\t\t * to compose multiple primitive's behavior together.\n\t\t\t\t *\n\t\t\t\t * @see https://www.radix-ui.com/docs/primitives/guides/composition#composition\n\t\t\t\t */\n\t\t\t\tasChild: true;\n\t\t\t\t/**\n\t\t\t\t * The default behavior of the button. Possible values are: `\"button\"`, `\"submit\"`, and `\"reset\"`.\n\t\t\t\t *\n\t\t\t\t * if `asChild` is NOT used: Unlike the native `<button>` element, this prop is required and has no default value.\n\t\t\t\t *\n\t\t\t\t * If `asChild` IS used: This prop HAS NO EFFECT, is REMOVED, and has no default value. This is because we do not want the `button` `type` to automatically merge with any child anchor `type` attribute because the `anchor` `type` is _strictly different_ than the `button` type, see: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#type\n\t\t\t\t *\n\t\t\t\t * @enum\n\t\t\t\t * - `\"button\"`: The button has no default behavior, and does nothing when pressed by default. It can have client-side scripts listen to the element's events, which are triggered when the events occur.\n\t\t\t\t * - `\"reset\"`: The button resets all the controls to their initial values.\n\t\t\t\t * - `\"submit\"`: The button submits the form data to the server.\n\t\t\t\t *\n\t\t\t\t * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#type\n\t\t\t\t */\n\t\t\t\ttype?: ButtonHTMLAttributes<HTMLButtonElement>[\"type\"];\n\t\t }\n\t\t| {\n\t\t\t\tasChild?: false | undefined;\n\t\t\t\t/**\n\t\t\t\t * The default behavior of the button. Possible values are: `\"button\"`, `\"submit\"`, and `\"reset\"`.\n\t\t\t\t *\n\t\t\t\t * if `asChild` is NOT used: Unlike the native `<button>` element, this prop is required and has no default value.\n\t\t\t\t *\n\t\t\t\t * If `asChild` IS used: This prop HAS NO EFFECT, is REMOVED, and has no default value. This is because we do not want the `button` `type` to automatically merge with any child anchor `type` attribute because the `anchor` `type` is _strictly different_ than the `button` type, see: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#type\n\t\t\t\t *\n\t\t\t\t * @enum\n\t\t\t\t * - `\"button\"`: The button has no default behavior, and does nothing when pressed by default. It can have client-side scripts listen to the element's events, which are triggered when the events occur.\n\t\t\t\t * - `\"reset\"`: The button resets all the controls to their initial values.\n\t\t\t\t * - `\"submit\"`: The button submits the form data to the server.\n\t\t\t\t *\n\t\t\t\t * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#type\n\t\t\t\t */\n\t\t\t\ttype: Exclude<ButtonHTMLAttributes<HTMLButtonElement>[\"type\"], undefined>;\n\t\t }\n\t);\n\n/**\n * Renders a button or a component that looks like a button, an interactive\n * element activated by a user with a mouse, keyboard, finger, voice command, or\n * other assistive technology. Once activated, it then performs an action, such\n * as submitting a form or opening a dialog.\n * Renders only a single icon as children with an accessible, screen-reader-only label.\n *\n * @see https://mantle.ngrok.com/components/button\n *\n * @example\n * ```tsx\n * <IconButton\n * type=\"button\"\n * icon={<TrashIcon />}\n * label=\"Delete item\"\n * appearance=\"ghost\"\n * size=\"sm\"\n * />\n * ```\n */\nconst IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(\n\t(\n\t\t{\n\t\t\t\"aria-disabled\": _ariaDisabled,\n\t\t\tappearance,\n\t\t\tasChild = false,\n\t\t\tchildren,\n\t\t\tclassName,\n\t\t\tdisabled: _disabled,\n\t\t\ticon: propIcon,\n\t\t\tisLoading = false,\n\t\t\tlabel,\n\t\t\tsize,\n\t\t\ttype,\n\t\t\t...props\n\t\t},\n\t\tref,\n\t) => {\n\t\tconst disabled = parseBooleanish(_ariaDisabled ?? _disabled ?? isLoading);\n\t\tconst icon = isLoading ? <CircleNotchIcon className=\"animate-spin\" /> : propIcon;\n\n\t\tconst buttonProps = {\n\t\t\t\"aria-disabled\": disabled,\n\t\t\t\"data-slot\": \"icon-button\",\n\t\t\tclassName: cx(iconButtonVariants({ appearance, isLoading, size }), className),\n\t\t\t\"data-appearance\": appearance,\n\t\t\t\"data-disabled\": disabled,\n\t\t\t\"data-icon-button\": true,\n\t\t\t\"data-loading\": isLoading,\n\t\t\t\"data-size\": size,\n\t\t\tdisabled,\n\t\t\tref,\n\t\t\t...props,\n\t\t};\n\n\t\tconst innerChildren = (\n\t\t\t<>\n\t\t\t\t<span className=\"sr-only\">{label}</span>\n\t\t\t\t<Icon svg={icon} />\n\t\t\t</>\n\t\t);\n\n\t\tif (asChild) {\n\t\t\tinvariant(\n\t\t\t\tisValidElement(children) && Children.only(children),\n\t\t\t\t\"When using `asChild`, IconButton must be passed a single child as a JSX tag.\",\n\t\t\t);\n\n\t\t\treturn <Slot {...buttonProps}>{cloneElement(children, {}, innerChildren)}</Slot>;\n\t\t}\n\n\t\treturn (\n\t\t\t// oxlint-disable-next-line react/button-has-type -- `type` is resolved at runtime from the `type` prop (defaulted to \"button\"); the static analyzer can't see that.\n\t\t\t<button {...buttonProps} type={type}>\n\t\t\t\t{innerChildren}\n\t\t\t</button>\n\t\t);\n\t},\n);\nIconButton.displayName = \"IconButton\";\n\nexport {\n\tbaseIconButtonClasses,\n\t//,\n\tIconButton,\n\ticonButtonVariants,\n};\n\nexport type {\n\t//,\n\tIconButtonProps,\n};\n"],"mappings":"mcAWA,MAAM,EAAwB,EAC7B,cACA,8GACA,4CACA,8CACA,yEACD,EAEM,EAAqB,EAAI,EAAuB,CACrD,SAAU,CAIT,WAAY,CACX,MACC,qIACD,SACC,8SACF,EAMA,UAAW,CACV,MAAO,GACP,KAAM,YACP,EAIA,KAAM,CACL,GAAI,SACJ,GAAI,SACJ,GAAI,QACL,CACD,EACA,gBAAiB,CAChB,WAAY,WACZ,KAAM,IACP,CACD,CAAC,EA2FK,EAAa,GAEjB,CACC,gBAAiB,EACjB,aACA,UAAU,GACV,WACA,YACA,SAAU,EACV,KAAM,EACN,YAAY,GACZ,QACA,OACA,OACA,GAAG,GAEJ,IACI,CACJ,IAAM,EAAW,EAAgB,GAAiB,GAAa,CAAS,EAClE,EAAO,EAAY,EAAC,EAAD,CAAiB,UAAU,cAAgB,CAAA,EAAI,EAElE,EAAc,CACnB,gBAAiB,EACjB,YAAa,cACb,UAAW,EAAG,EAAmB,CAAE,aAAY,YAAW,MAAK,CAAC,EAAG,CAAS,EAC5E,kBAAmB,EACnB,gBAAiB,EACjB,mBAAoB,GACpB,eAAgB,EAChB,YAAa,EACb,WACA,MACA,GAAG,CACJ,EAEM,EACL,EAAA,EAAA,CAAA,SAAA,CACC,EAAC,OAAD,CAAM,UAAU,mBAAW,CAAY,CAAA,EACvC,EAAC,EAAD,CAAM,IAAK,CAAO,CAAA,CACjB,CAAA,CAAA,EAYH,OATI,GACH,EACC,EAAe,CAAQ,GAAK,EAAS,KAAK,CAAQ,EAClD,8EACD,EAEO,EAAC,EAAD,CAAM,GAAI,WAAc,EAAa,EAAU,CAAC,EAAG,CAAa,CAAQ,CAAA,GAK/E,EAAC,SAAD,CAAQ,GAAI,EAAmB,gBAC7B,CACM,CAAA,CAEV,CACD,EACA,EAAW,YAAc"}
|
package/dist/icons.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"icons.js","names":[],"sources":["../src/components/icons/theme.tsx","../src/components/icons/ngrok.tsx"],"sourcesContent":["import { DesktopIcon } from \"@phosphor-icons/react/Desktop\";\nimport { MoonIcon } from \"@phosphor-icons/react/Moon\";\nimport { SunIcon } from \"@phosphor-icons/react/Sun\";\nimport type { SvgAttributes } from \"../icon/types.js\";\nimport { useAppliedTheme } from \"../theme/theme-provider.js\";\nimport type { Theme } from \"../theme/themes.js\";\n\n/**\n * An icon that automatically adapts to the current applied theme.\n * - `light`: SunIcon\n * - `dark`: MoonIcon\n * - `light-high-contrast`: SunIcon (fill)\n * - `dark-high-contrast`: MoonIcon (fill)\n */\nfunction AutoThemeIcon(props: SvgAttributes) {\n\tconst appliedTheme = useAppliedTheme();\n\n\treturn <ThemeIcon theme={appliedTheme} {...props} />;\n}\nAutoThemeIcon.displayName = \"AutoThemeIcon\";\n\ntype ThemeIconProps = SvgAttributes & { theme: Theme };\n\n/**\n * An icon that adapts to a specific theme.\n * It will render a different icon based on the provided theme:\n * - `system`: DesktopIcon\n * - `light`: SunIcon\n * - `dark`: MoonIcon\n * - `light-high-contrast`: SunIcon (fill)\n * - `dark-high-contrast`: MoonIcon (fill)\n */\nfunction ThemeIcon({ theme, ...props }: ThemeIconProps) {\n\tswitch (theme) {\n\t\tcase \"system\":\n\t\t\treturn <DesktopIcon {...props} />;\n\t\tcase \"light\":\n\t\t\treturn <SunIcon {...props} />;\n\t\tcase \"dark\":\n\t\t\treturn <MoonIcon {...props} />;\n\t\tcase \"light-high-contrast\":\n\t\t\treturn <SunIcon {...props} weight=\"fill\" />;\n\t\tcase \"dark-high-contrast\":\n\t\t\treturn <MoonIcon {...props} weight=\"fill\" />;\n\t}\n}\nThemeIcon.displayName = \"ThemeIcon\";\n\nexport {\n\t//,\n\tAutoThemeIcon,\n\tThemeIcon,\n};\n","import type { InlineIconProps } from \"./types.js\";\n\n/**\n * An inline svg icon that renders the ngrok wordmark logo. Fill color is determined by the `color` CSS property.\n */\nfunction NgrokWordmarkIcon(props: Omit<InlineIconProps, \"color\">) {\n\treturn (\n\t\t<svg fill=\"currentColor\" height=\"1em\" viewBox=\"0 0 94 36\" width=\"2.61em\" {...props}>\n\t\t\t<path d=\"M32.272 12.011c-1.298-1.466-2.904-2.205-4.812-2.205-1.176 0-2.26.233-3.255.7a7.995 7.995 0 0 0-2.581 1.906 9.205 9.205 0 0 0-1.715 2.853 9.773 9.773 0 0 0-.628 3.546c0 1.25.194 2.39.58 3.419.362.98.918 1.877 1.635 2.636A7.543 7.543 0 0 0 24 26.584c.965.41 2.025.617 3.176.617.522 0 1.005-.041 1.445-.116.439-.075.858-.2 1.26-.37.4-.175.79-.398 1.18-.664.385-.27.792-.612 1.21-1.018v4.353h-.005v.421h-5.33l-4.005 4.64v.798h15.037v-24.98h-5.697v1.746Zm-.014 7.979a4.25 4.25 0 0 1-.786 1.215 3.555 3.555 0 0 1-2.592 1.1 3.627 3.627 0 0 1-1.464-.292 3.508 3.508 0 0 1-1.166-.808 3.93 3.93 0 0 1-1.054-2.72c0-.519.097-1.006.298-1.457a3.77 3.77 0 0 1 .804-1.181 4.114 4.114 0 0 1 1.162-.808 3.484 3.484 0 0 1 2.817-.016c.448.19.844.463 1.181.81.336.347.6.743.804 1.194.202.452.298.95.298 1.493 0 .505-.104 1.005-.302 1.47m-16.261-7.708a6.173 6.173 0 0 0-2.06-1.602 4.875 4.875 0 0 0-.57-.22 6.383 6.383 0 0 0-.923-.216H8.383L5.697 13.39v-3.082H.002v16.61h5.695V15.712h5.35l.444-.01v11.214h5.697V16.528c0-.885-.084-1.674-.25-2.366a4.655 4.655 0 0 0-.941-1.877zm38.367-2.018h-6.213l-2.47 2.863v-2.864h-5.7v16.61h5.71l.004-11.117h4.144l4.526-5.26zm31.051 7.672 7.79-7.392v-.281H85.7l-5.975 5.991V0h-5.696v26.87h5.696v-6.766l6.262 6.763h7.663v-.316l-8.233-8.617zm-16.11-5.78a9.436 9.436 0 0 0-3.085-1.842 10.953 10.953 0 0 0-3.855-.664c-1.407 0-2.705.226-3.884.678a9.611 9.611 0 0 0-3.072 1.858 8.488 8.488 0 0 0-2.016 2.788 8.281 8.281 0 0 0-.722 3.449c0 1.362.24 2.596.722 3.707a8.52 8.52 0 0 0 2.002 2.862c.85.798 1.86 1.415 3.036 1.847 1.177.432 2.455.647 3.842.647 1.406 0 2.707-.215 3.919-.647 1.204-.431 2.24-1.04 3.098-1.833a8.583 8.583 0 0 0 2.031-2.816c.493-1.09.742-2.29.742-3.611 0-1.316-.244-2.52-.722-3.612a8.424 8.424 0 0 0-2.035-2.81Zm-3.558 7.864c-.2.461-.463.869-.786 1.215a3.573 3.573 0 0 1-2.592 1.1c-.502 0-.981-.096-1.434-.291a3.44 3.44 0 0 1-1.16-.809 4.155 4.155 0 0 1-.788-1.215 3.825 3.825 0 0 1-.297-1.537c0-.517.098-1.004.297-1.456.201-.451.46-.849.787-1.194a3.579 3.579 0 0 1 2.597-1.1c.502 0 .98.096 1.43.29.448.19.839.461 1.16.81.328.345.586.752.786 1.214.2.461.297.954.297 1.471 0 .538-.096 1.04-.297 1.502\" />\n\t\t</svg>\n\t);\n}\n\n/**\n * An inline svg icon that renders the ngrok lettermark \"n\" logo. Fill color is determined by the `color` CSS property.\n */\nfunction NgrokLettermarkIcon(props: Omit<InlineIconProps, \"color\">) {\n\treturn (\n\t\t<svg fill=\"currentColor\" height=\"1em\" viewBox=\"0 0 32 32\" width=\"1em\" {...props}>\n\t\t\t<path d=\"M27.2 6.18a9.47 9.47 0 0 0-3.12-2.5A9.42 9.42 0 0 0 21.82 3h-6.14l-4.06 4.9V3.1H3V29h8.62V11.53h8.09l.67-.02v17.48H29V12.8c0-1.37-.13-2.6-.38-3.68a7.35 7.35 0 0 0-1.42-2.93Z\" />\n\t\t</svg>\n\t);\n}\n\nexport {\n\t//,\n\tNgrokWordmarkIcon,\n\tNgrokLettermarkIcon,\n};\n"],"mappings":"uVAcA,SAAS,EAAc,EAAsB,CAG5C,OAAO,EAAC,EAAD,CAAW,MAFG,EAEe,EAAG,GAAI,CAAQ,CAAA,CACpD,CACA,EAAc,YAAc,gBAa5B,SAAS,EAAU,CAAE,QAAO,GAAG,GAAyB,CACvD,OAAQ,EAAR,CACC,IAAK,SACJ,OAAO,EAAC,EAAD,CAAa,GAAI,CAAQ,CAAA,EACjC,IAAK,QACJ,OAAO,EAAC,EAAD,CAAS,GAAI,CAAQ,CAAA,EAC7B,IAAK,OACJ,OAAO,EAAC,EAAD,CAAU,GAAI,CAAQ,CAAA,EAC9B,IAAK,sBACJ,OAAO,EAAC,EAAD,CAAS,GAAI,EAAO,OAAO,MAAQ,CAAA,EAC3C,IAAK,qBACJ,OAAO,EAAC,EAAD,CAAU,GAAI,EAAO,OAAO,MAAQ,CAAA,CAC7C,CACD,CACA,EAAU,YAAc,YCzCxB,SAAS,EAAkB,EAAuC,CACjE,OACC,EAAC,MAAD,CAAK,KAAK,eAAe,OAAO,MAAM,QAAQ,YAAY,MAAM,SAAS,GAAI,WAC5E,EAAC,OAAD,CAAM,EAAE,klEAAolE,CAAA,CACxlE,CAAA,CAEP,CAKA,SAAS,EAAoB,EAAuC,CACnE,OACC,EAAC,MAAD,CAAK,KAAK,eAAe,OAAO,MAAM,QAAQ,YAAY,MAAM,MAAM,GAAI,WACzE,EAAC,OAAD,CAAM,EAAE,+KAAiL,CAAA,CACrL,CAAA,CAEP"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"in-view-C2DpZ6s0.js","names":[],"sources":["../src/utils/in-view.ts"],"sourcesContent":["type MarginValue = `${number}${\"px\" | \"%\"}`;\n\n/**\n * Margin string used to expand or contract the intersection root's bounding box.\n * Follows the same syntax as the CSS `margin` shorthand (1–4 values).\n *\n * @example \"10px\"\n * @example \"10% 20px\"\n * @example \"10px 20px 10px 20px\"\n */\ntype MarginType =\n\t| MarginValue\n\t| `${MarginValue} ${MarginValue}`\n\t| `${MarginValue} ${MarginValue} ${MarginValue}`\n\t| `${MarginValue} ${MarginValue} ${MarginValue} ${MarginValue}`;\n\n/**\n * Options for the `inView` helper.\n */\ntype InViewOptions = {\n\t/**\n\t * The scrollable container element (or `Document`) to use as the intersection root.\n\t * Defaults to the browser viewport.\n\t */\n\troot?: Element | Document;\n\n\t/**\n\t * Expand or contract the detected area from each side of the root's bounding box.\n\t * Uses the same syntax as the CSS `margin` shorthand (e.g. `\"10px\"`, `\"10% 20px\"`).\n\t */\n\tmargin?: MarginType;\n\n\t/**\n\t * How much of the element must be visible before it is considered in view.\n\t * - `\"some\"` (default): Any part of the element is visible.\n\t * - `\"all\"`: The entire element is visible.\n\t * - `number`: An intersection ratio between `0` and `1` (e.g. `0.5` for 50%).\n\t */\n\tamount?: \"some\" | \"all\" | number;\n};\n\n/**\n * Callback invoked when an observed element leaves the viewport.\n * Receives the `IntersectionObserverEntry` for the departing element.\n */\ntype ViewChangeHandler = (entry: IntersectionObserverEntry) => void;\n\nconst thresholds = {\n\tsome: 0,\n\tall: 1,\n};\n\n/**\n * Observe when a DOM element enters or leaves the viewport (or a scrollable\n * container) using the `IntersectionObserver` API.\n *\n * When the element enters the viewport, `onStart` is called. If `onStart`\n * returns a function, that function is called when the element leaves the\n * viewport. If `onStart` returns nothing, the element is unobserved after\n * the first entry.\n *\n * @param element - The DOM element to observe.\n * @param onStart - Called when the element enters the viewport. Optionally\n * returns a cleanup function called when the element leaves.\n * @param options - Options for the intersection root, margin, and threshold.\n * @returns A cleanup function that disconnects the observer.\n *\n * @example\n * const stop = inView(element, (el) => {\n * el.classList.add(\"visible\");\n * return () => el.classList.remove(\"visible\");\n * });\n *\n * // Later, stop observing:\n * stop();\n */\nfunction inView(\n\telement: Element,\n\t// `void | ViewChangeHandler` mirrors React's `EffectCallback` pattern so callers can\n\t// optionally return a cleanup handler without TS complaining about implicit-void returns.\n\t// oxlint-disable-next-line typescript/no-invalid-void-type\n\tonStart: (element: Element, entry: IntersectionObserverEntry) => void | ViewChangeHandler,\n\t{ root, margin: rootMargin, amount = \"some\" }: InViewOptions = {},\n): VoidFunction {\n\tconst activeIntersections = new WeakMap<Element, ViewChangeHandler>();\n\n\tconst onIntersectionChange: IntersectionObserverCallback = (entries) => {\n\t\tentries.forEach((entry) => {\n\t\t\tconst onEnd = activeIntersections.get(entry.target);\n\n\t\t\t/**\n\t\t\t * If there's no change to the intersection, we don't need to\n\t\t\t * do anything here.\n\t\t\t */\n\t\t\tif (entry.isIntersecting === Boolean(onEnd)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (entry.isIntersecting) {\n\t\t\t\tconst newOnEnd = onStart(entry.target, entry);\n\t\t\t\tif (typeof newOnEnd === \"function\") {\n\t\t\t\t\tactiveIntersections.set(entry.target, newOnEnd);\n\t\t\t\t} else {\n\t\t\t\t\tobserver.unobserve(entry.target);\n\t\t\t\t}\n\t\t\t} else if (typeof onEnd === \"function\") {\n\t\t\t\tonEnd(entry);\n\t\t\t\tactiveIntersections.delete(entry.target);\n\t\t\t}\n\t\t});\n\t};\n\n\tconst observer = new IntersectionObserver(onIntersectionChange, {\n\t\troot,\n\t\trootMargin,\n\t\tthreshold: typeof amount === \"number\" ? amount : thresholds[amount],\n\t});\n\n\tobserver.observe(element);\n\n\treturn () => {\n\t\tobserver.unobserve(element);\n\t\tobserver.disconnect();\n\t};\n}\n\nexport { inView };\nexport type { InViewOptions, MarginType, ViewChangeHandler };\n"],"mappings":"AA+CA,MAAM,EAAa,CAClB,KAAM,EACN,IAAK,CACN,EA0BA,SAAS,EACR,EAIA,EACA,CAAE,OAAM,OAAQ,EAAY,SAAS,QAA0B,CAAC,EACjD,CACf,IAAM,EAAsB,IAAI,QA4B1B,EAAW,IAAI,qBA1BuC,GAAY,CACvE,EAAQ,QAAS,GAAU,CAC1B,IAAM,EAAQ,EAAoB,IAAI,EAAM,MAAM,EAM9C,KAAM,iBAAmB,EAAQ,EAIrC,GAAI,EAAM,eAAgB,CACzB,IAAM,EAAW,EAAQ,EAAM,OAAQ,CAAK,EACxC,OAAO,GAAa,WACvB,EAAoB,IAAI,EAAM,OAAQ,CAAQ,EAE9C,EAAS,UAAU,EAAM,MAAM,CAEjC,MAAW,OAAO,GAAU,aAC3B,EAAM,CAAK,EACX,EAAoB,OAAO,EAAM,MAAM,EAEzC,CAAC,CACF,EAEgE,CAC/D,OACA,aACA,UAAW,OAAO,GAAW,SAAW,EAAS,EAAW,EAC7D,CAAC,EAID,OAFA,EAAS,QAAQ,CAAO,MAEX,CACZ,EAAS,UAAU,CAAO,EAC1B,EAAS,WAAW,CACrB,CACD"}
|
package/dist/input.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"input.js","names":["clsx"],"sources":["../src/components/input/input.tsx","../src/components/input/password-input.tsx"],"sourcesContent":["\"use client\";\n\nimport { CheckCircleIcon } from \"@phosphor-icons/react/CheckCircle\";\nimport { WarningIcon } from \"@phosphor-icons/react/Warning\";\nimport { WarningDiamondIcon } from \"@phosphor-icons/react/WarningDiamond\";\nimport clsx from \"clsx\";\nimport type {\n\tComponentRef,\n\tForwardedRef,\n\tInputHTMLAttributes,\n\tMutableRefObject,\n\tPropsWithChildren,\n} from \"react\";\nimport { createContext, forwardRef, useContext, useMemo, useRef } from \"react\";\nimport { composeRefs } from \"../../utils/compose-refs/compose-refs.js\";\nimport { cx } from \"../../utils/cx/cx.js\";\nimport { parseValidation, useFieldValidation } from \"../field/validation.js\";\nimport type { Validation, WithValidation } from \"../field/validation.js\";\nimport { Icon } from \"../icon/icon.js\";\nimport type { WithAutoComplete, WithInputType } from \"./types.js\";\n\ntype BaseProps = WithAutoComplete & WithInputType & WithValidation;\n\n/**\n * The props for the `Input` component.\n */\ntype InputProps = Omit<InputHTMLAttributes<HTMLInputElement>, \"autoComplete\" | \"type\"> &\n\tBaseProps &\n\tPropsWithChildren;\n\n/**\n * Used to create interactive controls for web-based forms in order to accept data from the user.\n * A versatile input element that supports various types, validation states, and can be composed with other elements.\n *\n * @see https://mantle.ngrok.com/components/input\n *\n * @example\n * ```tsx\n * <Input\n * type=\"email\"\n * placeholder=\"Enter your email\"\n * validation=\"success\"\n * />\n * ```\n */\nconst Input = forwardRef<HTMLInputElement, InputProps>(\n\t({ children, className, ...props }, forwardedRef) => {\n\t\tconst hasChildren = Boolean(children);\n\t\tconst innerRef = useRef<ComponentRef<\"input\">>(null);\n\n\t\tif (hasChildren) {\n\t\t\treturn (\n\t\t\t\t<InputContainer\n\t\t\t\t\tclassName={className}\n\t\t\t\t\tforwardedRef={forwardedRef}\n\t\t\t\t\tinnerRef={innerRef}\n\t\t\t\t\t{...props}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</InputContainer>\n\t\t\t);\n\t\t}\n\n\t\treturn (\n\t\t\t<InputContainer\n\t\t\t\t{...props}\n\t\t\t\tclassName={className}\n\t\t\t\tforwardedRef={forwardedRef}\n\t\t\t\tinnerRef={innerRef}\n\t\t\t>\n\t\t\t\t<InputCapture {...props} />\n\t\t\t</InputContainer>\n\t\t);\n\t},\n);\nInput.displayName = \"Input\";\n\ntype InputCaptureProps = Omit<InputHTMLAttributes<HTMLInputElement>, \"autoComplete\" | \"type\"> &\n\tBaseProps;\n\n/**\n * The actual <input /> element that captures user input.\n * Used internally by Input component or when you need direct control over the input element.\n *\n * @see https://mantle.ngrok.com/components/input\n *\n * @example\n * ```tsx\n * <Input>\n * <InputCapture />\n * <Icon svg={<SearchIcon />} />\n * </Input>\n * ```\n */\nconst InputCapture = forwardRef<HTMLInputElement, InputCaptureProps>(\n\t({ \"aria-invalid\": _ariaInvalid, className, validation: _validation, ...restProps }, ref) => {\n\t\tconst {\n\t\t\t\"aria-invalid\": ctxAriaInvalid,\n\t\t\tforwardedRef: ctxForwardedRef,\n\t\t\tinnerRef: ctxInnerRef,\n\t\t\tvalidation: ctxValidation,\n\t\t\t...ctx\n\t\t} = useContext(InputContext);\n\t\tconst fieldValidation = useFieldValidation();\n\n\t\tconst { ariaInvalid, validation } = parseValidation({\n\t\t\t\"aria-invalid\": ctxAriaInvalid ?? _ariaInvalid,\n\t\t\tvalidation: ctxValidation ?? _validation ?? fieldValidation,\n\t\t});\n\t\tconst props = {\n\t\t\t...ctx,\n\t\t\t...restProps,\n\t\t\ttype: restProps.type ?? ctx.type ?? \"text\",\n\t\t};\n\n\t\treturn (\n\t\t\t<input\n\t\t\t\taria-invalid={ariaInvalid}\n\t\t\t\tdata-slot=\"input-capture\"\n\t\t\t\tdata-validation={validation}\n\t\t\t\tclassName={cx(\n\t\t\t\t\t\"placeholder:text-placeholder min-w-0 flex-1 bg-transparent text-left autofill:shadow-[inset_0_0_0px_1000px_var(--color-blue-50)] focus:outline-hidden\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tref={composeRefs(ref, ctxForwardedRef, ctxInnerRef)}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t},\n);\nInputCapture.displayName = \"InputCapture\";\n\ntype InputContextType = Omit<InputHTMLAttributes<HTMLInputElement>, \"autoComplete\" | \"type\"> &\n\tBaseProps & {\n\t\t/**\n\t\t * inner ref for the input element, controlled by `Input`\n\t\t */\n\t\tinnerRef: MutableRefObject<HTMLInputElement | null>;\n\t\t/**\n\t\t * forwarded ref to the input element, forwarded from `Input` to `InputCapture`\n\t\t */\n\t\tforwardedRef?: ForwardedRef<HTMLInputElement>;\n\t};\n\nconst InputContext = createContext<InputContextType>({\n\tvalidation: undefined,\n\tinnerRef: { current: null },\n});\n\ntype InputContainerProps = InputHTMLAttributes<HTMLInputElement> &\n\tBaseProps & {\n\t\t/**\n\t\t * @private inner ref for the input element, controlled by `Input`\n\t\t */\n\t\tinnerRef: MutableRefObject<HTMLInputElement | null>;\n\t\t/**\n\t\t * @private ref to the input element, forwarded from `Input` to `InputCapture`\n\t\t */\n\t\tforwardedRef: ForwardedRef<HTMLInputElement>;\n\t};\n\n/**\n * The container for the input element.\n */\nconst InputContainer = ({\n\t\"aria-invalid\": _ariaInvalid,\n\t\"aria-disabled\": _ariaDisabled,\n\t\"data-slot\": dataSlot = \"input\",\n\tchildren,\n\tclassName,\n\tdisabled,\n\tforwardedRef,\n\tinnerRef,\n\tstyle,\n\ttype,\n\tvalidation: _validation,\n\t...props\n}: InputContainerProps & { \"data-slot\"?: string }) => {\n\tconst fieldValidation = useFieldValidation();\n\tconst { validation } = parseValidation({\n\t\t\"aria-invalid\": _ariaInvalid,\n\t\tvalidation: _validation ?? fieldValidation,\n\t});\n\tconst contextValue = useMemo(\n\t\t() => ({\n\t\t\t\"aria-invalid\": _ariaInvalid,\n\t\t\t\"aria-disabled\": _ariaDisabled,\n\t\t\tdisabled,\n\t\t\ttype,\n\t\t\tvalidation: _validation,\n\t\t\t...props,\n\t\t\tforwardedRef,\n\t\t\tinnerRef,\n\t\t}),\n\t\t[_ariaInvalid, _ariaDisabled, disabled, type, _validation, props, forwardedRef, innerRef],\n\t);\n\treturn (\n\t\t<InputContext.Provider value={contextValue}>\n\t\t\t<div\n\t\t\t\trole=\"none\"\n\t\t\t\tdata-slot={dataSlot}\n\t\t\t\tdata-disabled={(disabled ?? _ariaDisabled) || undefined}\n\t\t\t\tdata-validation={validation || undefined}\n\t\t\t\tclassName={cx(\n\t\t\t\t\t\"pointer-coarse:text-base h-9 text-sm\",\n\t\t\t\t\t\"bg-form relative flex w-full items-center gap-1.5 rounded-md border px-3 py-2 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-within:outline-hidden focus-within:ring-4\",\n\t\t\t\t\t\"data-disabled:opacity-50\",\n\t\t\t\t\t\"has-[input:not(:first-child)]:ps-2.5 has-[input:not(:last-child)]:pe-2.5 [&>:not(input)]:shrink-0 [&_svg]:size-5\",\n\t\t\t\t\t\"border-form text-strong focus-within:border-accent-600 focus-within:ring-focus-accent\",\n\t\t\t\t\t\"data-validation-success:border-success-600 focus-within:data-validation-success:border-success-600 focus-within:data-validation-success:ring-focus-success\",\n\t\t\t\t\t\"data-validation-warning:border-warning-600 focus-within:data-validation-warning:border-warning-600 focus-within:data-validation-warning:ring-focus-warning\",\n\t\t\t\t\t\"data-validation-error:border-danger-600 focus-within:data-validation-error:border-danger-600 focus-within:data-validation-error:ring-focus-danger\",\n\t\t\t\t\t\"autofill:shadow-[inset_0_0_0px_1000px_var(--color-blue-50)] has-autofill:bg-blue-50 has-autofill:[-webkit-text-fill-color:var(--text-color-strong)]\", // Autofill styling on the input itself and any children with autofill styling\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tonMouseDown={(event) => {\n\t\t\t\t\t// Prevent mousedown on non-input children (icons, buttons, etc.) from\n\t\t\t\t\t// blurring the input, which would cause the focus ring to flicker.\n\t\t\t\t\tif (event.target !== innerRef?.current) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t\tonClick={() => {\n\t\t\t\t\tinnerRef?.current?.focus();\n\t\t\t\t}}\n\t\t\t\tonKeyDown={() => {\n\t\t\t\t\tif (innerRef?.current !== document.activeElement) {\n\t\t\t\t\t\tinnerRef?.current?.focus();\n\t\t\t\t\t}\n\t\t\t\t}}\n\t\t\t\tstyle={style}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t\t<ValidationFeedback name={props.name} validation={validation} />\n\t\t\t</div>\n\t\t</InputContext.Provider>\n\t);\n};\nInputContainer.displayName = \"InputContainer\";\n\nexport { Input, InputCapture };\nexport type { InputProps, InputCaptureProps };\n\nconst ValidationFeedback = ({\n\tname,\n\tvalidation,\n}: {\n\tname?: string;\n\tvalidation: Validation | undefined;\n}) => {\n\tswitch (validation) {\n\t\tcase \"error\":\n\t\t\treturn (\n\t\t\t\t<div className=\"text-danger-600 order-last select-none\">\n\t\t\t\t\t<span className=\"sr-only\">\n\t\t\t\t\t\t{clsx(\"The value entered for the\", name, \"input has failed validation.\")}\n\t\t\t\t\t</span>\n\t\t\t\t\t<Icon svg={<WarningIcon aria-hidden weight=\"fill\" />} />\n\t\t\t\t</div>\n\t\t\t);\n\t\tcase \"success\":\n\t\t\treturn (\n\t\t\t\t<div className=\"text-success-600 order-last select-none\">\n\t\t\t\t\t<Icon svg={<CheckCircleIcon weight=\"fill\" />} />\n\t\t\t\t</div>\n\t\t\t);\n\t\tcase \"warning\":\n\t\t\treturn (\n\t\t\t\t<div className=\"text-warning-600 order-last select-none\">\n\t\t\t\t\t<Icon svg={<WarningDiamondIcon weight=\"fill\" />} />\n\t\t\t\t</div>\n\t\t\t);\n\t\tdefault:\n\t\t\treturn null;\n\t}\n};\nValidationFeedback.displayName = \"ValidationFeedback\";\n","\"use client\";\n\nimport { EyeIcon } from \"@phosphor-icons/react/Eye\";\nimport { EyeClosedIcon } from \"@phosphor-icons/react/EyeClosed\";\nimport { forwardRef, useEffect, useRef, useState } from \"react\";\nimport type { InputHTMLAttributes } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport { getPrefersReducedMotion } from \"../../hooks/use-prefers-reduced-motion.js\";\nimport type { WithValidation } from \"../field/validation.js\";\nimport { Icon } from \"../icon/icon.js\";\nimport { Input, InputCapture } from \"./input.js\";\nimport type { InputType, WithAutoComplete } from \"./types.js\";\n\ntype PasswordInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, \"autoComplete\" | \"type\"> &\n\tWithValidation &\n\tWithAutoComplete & {\n\t\t/**\n\t\t * Callback for when the visibility of the password value changes.\n\t\t */\n\t\tonValueVisibilityChange?: (visible: boolean) => void;\n\t\t/**\n\t\t * Show/hide the password value as a controlled state.\n\t\t * @default false\n\t\t */\n\t\tshowValue?: boolean;\n\t};\n\ntype PasswordInputType = Extract<InputType, \"text\" | \"password\">;\n\n/**\n * An input optimized for password and other sensitive-value entry. Renders a\n * native `<input type=\"password\">` with a built-in trailing button that\n * toggles between hidden (`••••`) and revealed (`text`) display.\n *\n * **When to use**\n * - Password fields on login, signup, and reset flows.\n * - One-time tokens, recovery codes, or secrets the user needs to type\n * accurately and may want to verify visually before submitting.\n *\n * **When not to use**\n * - For values that are never sensitive — use a plain {@link https://mantle.ngrok.com/components/input Input}.\n * - For controls where the toggle would be confusing (e.g. masked input\n * formatting like phone numbers).\n *\n * **Visibility state.** The toggle is uncontrolled by default. Pass\n * `showValue` to control the visibility from the outside (useful when one\n * UI control toggles multiple password fields), and `onValueVisibilityChange`\n * to be notified when the user toggles via the built-in button.\n *\n * **Accessibility.** Always pair with a {@link https://mantle.ngrok.com/components/label Label}.\n * The toggle button has its own accessible name announcing the current\n * state. The input keeps `autocomplete=\"current-password\"` /\n * `\"new-password\"` semantics — set `autoComplete` explicitly per flow.\n *\n * **Browser password managers.** When revealed, the input switches to\n * `type=\"text\"` — some password managers may pause autofill in this state,\n * which is the intended security tradeoff.\n *\n * @see https://mantle.ngrok.com/components/password-input\n *\n * @example\n * ```tsx\n * import { PasswordInput } from \"@ngrok/mantle/input\";\n * import { Label } from \"@ngrok/mantle/label\";\n * import { useState } from \"react\";\n *\n * // Basic — uncontrolled visibility.\n * <Label className=\"grid gap-1\">\n * <span>Password</span>\n * <PasswordInput name=\"password\" autoComplete=\"current-password\" />\n * </Label>\n *\n * // Validation state.\n * <PasswordInput validation=\"error\" />\n *\n * // Controlled visibility — one toggle reveals multiple fields.\n * function PasswordPair() {\n * const [show, setShow] = useState(false);\n * return (\n * <>\n * <PasswordInput showValue={show} onValueVisibilityChange={setShow} />\n * <PasswordInput showValue={show} onValueVisibilityChange={setShow} />\n * </>\n * );\n * }\n * ```\n */\nconst PasswordInput = forwardRef<HTMLInputElement, PasswordInputProps>(\n\t({ onValueVisibilityChange, showValue = false, ...props }, ref) => {\n\t\tconst [showPassword, setShowPassword] = useState<boolean>(showValue);\n\t\tconst type: PasswordInputType = showPassword ? \"text\" : \"password\";\n\t\tconst EyeCon = showPassword ? EyeIcon : EyeClosedIcon;\n\t\tconst iconRef = useRef<SVGSVGElement>(null);\n\t\tconst animationRef = useRef<Animation | null>(null);\n\n\t\tuseEffect(() => {\n\t\t\tsetShowPassword(showValue);\n\t\t}, [showValue]);\n\n\t\treturn (\n\t\t\t<Input data-slot=\"password-input\" type={type} ref={ref} {...props}>\n\t\t\t\t<InputCapture />\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\tclassName=\"text-body hover:text-strong ml-1 cursor-pointer bg-inherit p-0\"\n\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t// Cancel any in-flight animation so rapid clicks are never blocked\n\t\t\t\t\t\tif (animationRef.current) {\n\t\t\t\t\t\t\tanimationRef.current.cancel();\n\t\t\t\t\t\t\tanimationRef.current = null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Flush synchronously so React commits the new icon to the DOM before we animate\n\t\t\t\t\t\tconst nextShowPassword = !showPassword;\n\t\t\t\t\t\tflushSync(() => {\n\t\t\t\t\t\t\tsetShowPassword(nextShowPassword);\n\t\t\t\t\t\t});\n\t\t\t\t\t\tonValueVisibilityChange?.(nextShowPassword);\n\n\t\t\t\t\t\tconst icon = iconRef.current;\n\t\t\t\t\t\tif (icon && !getPrefersReducedMotion()) {\n\t\t\t\t\t\t\tanimationRef.current = icon.animate(\n\t\t\t\t\t\t\t\t[{ transform: \"scaleY(0)\" }, { transform: \"scaleY(1)\" }],\n\t\t\t\t\t\t\t\t{ duration: 200, easing: \"ease-out\" },\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tanimationRef.current.onfinish = () => {\n\t\t\t\t\t\t\t\tanimationRef.current = null;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<span className=\"sr-only\">Turn password visibility {showPassword ? \"off\" : \"on\"}</span>\n\t\t\t\t\t<Icon ref={iconRef} svg={<EyeCon aria-hidden />} />\n\t\t\t\t</button>\n\t\t\t</Input>\n\t\t);\n\t},\n);\nPasswordInput.displayName = \"PasswordInput\";\n\nexport { PasswordInput };\nexport type { PasswordInputProps };\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"is-input-CXmS0OFN.js","names":[],"sources":["../src/components/input/is-input.ts"],"sourcesContent":["/**\n * Type guard for an HTMLInputElement.\n *\n * @example\n * ```tsx\n * function handleElement(element: HTMLElement) {\n * if (isInput(element)) {\n * // TypeScript now knows element is HTMLInputElement\n * element.value = \"new value\";\n * element.focus();\n * }\n * }\n * ```\n */\nexport function isInput(value: unknown): value is HTMLInputElement {\n\treturn value != null && value instanceof HTMLInputElement;\n}\n"],"mappings":"AAcA,SAAgB,EAAQ,EAA2C,CAClE,OAAO,GAAS,MAAQ,aAAiB,gBAC1C"}
|
package/dist/kbd-Bv6tefdB.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"kbd-Bv6tefdB.js","names":[],"sources":["../src/components/kbd/kbd.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport { cx } from \"../../utils/cx/cx.js\";\n\n/**\n * A square, centered keyboard \"key\" chip for rendering shortcut hints —\n * \"K\", \"⌘\", \"⌃\", \"Enter\". Renders a native `<kbd>` element so screen\n * readers announce it as keyboard input. Sized so letters and modifier\n * symbols share a consistent visual height, width, and baseline.\n *\n * **When to use**\n * - Documenting keyboard shortcuts in copy or tooltips.\n * - Inside menu items and command palettes alongside the action label.\n * - Inline with prose: \"Press `Kbd K` to open search.\"\n *\n * **When not to use**\n * - For arbitrary monospace text — use {@link https://mantle.ngrok.com/components/code Code}.\n * - For chord-style multi-key shortcuts as a single chip — render multiple\n * `<Kbd>` elements separated by `+` text instead.\n *\n * **Accessibility.** Symbol-only glyphs (`⌘`, `⌃`, `↵`) are not announced\n * meaningfully by screen readers. Provide an accessible name via\n * `aria-label` on the `<Kbd>` or include a visually-hidden label inside,\n * and mark the visible glyph `aria-hidden`.\n *\n * @see https://mantle.ngrok.com/components/kbd\n *\n * @example\n * ```tsx\n * import { Kbd } from \"@ngrok/mantle/kbd\";\n *\n * // Letter key.\n * <Kbd>K</Kbd>\n *\n * // Chord — render each key separately.\n * <span>\n * <Kbd aria-label=\"Command\">⌘</Kbd> + <Kbd>K</Kbd>\n * </span>\n *\n * // Symbol with sr-only label.\n * <Kbd>\n * <span className=\"sr-only\">Enter</span>\n * <span aria-hidden>↵</span>\n * </Kbd>\n * ```\n */\nfunction Kbd({ children, className, ...props }: ComponentProps<\"kbd\">) {\n\treturn (\n\t\t<kbd\n\t\t\tdata-slot=\"kbd\"\n\t\t\tclassName={cx(\n\t\t\t\t\"[font-kerning:normal] [font-variant-ligatures:common-ligatures_contextual]\",\n\t\t\t\t\"appearance-none tabular-nums inline-grid place-items-center size-5 bg-neutral-500/15 px-1 rounded text-mono leading-none font-mono\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</kbd>\n\t);\n}\n\nexport {\n\t//,\n\tKbd,\n};\n"],"mappings":"6EA6CA,SAAS,EAAI,CAAE,WAAU,YAAW,GAAG,GAAgC,CACtE,OACC,EAAC,MAAD,CACC,YAAU,MACV,UAAW,EACV,6EACA,qIACA,CACD,EACA,GAAI,EAEH,UACG,CAAA,CAEP"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"label-DhIUmTN2.js","names":[],"sources":["../src/components/label/label.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { ComponentPropsWithoutRef, ComponentRef } from \"react\";\nimport { cx } from \"../../utils/cx/cx.js\";\n\ntype LabelProps = ComponentPropsWithoutRef<\"label\"> & {\n\t/**\n\t * If set, the label will appear disabled.\n\t */\n\tdisabled?: boolean;\n};\n\n/**\n * A caption for a form control — input, checkbox, radio, switch, select.\n * Renders a native `<label>`. Pair every form control with a `Label` so the\n * control has an accessible name, clicks on the label focus the control, and\n * screen readers announce the field correctly.\n *\n * **When to use**\n * - Every visible form control. Always.\n * - Above or beside an input to describe it (\"Email\", \"API key\").\n * - Wrapping a checkbox or radio next to its descriptive text.\n *\n * **When not to use**\n * - For static UI text that isn't labeling a control — use a heading or\n * plain `<p>`/`<span>`.\n * - As a substitute for `aria-label` on non-`<input>` widgets that don't\n * support `<label for>` association.\n *\n * **Two ways to associate.** Either wrap the control inside the `<Label>`\n * (implicit association — simplest) or set `htmlFor` to the control's `id`\n * (explicit — required when the control isn't a child).\n *\n * **Disabled state.** Pass `disabled` to render the label in a disabled\n * style. Typically you'll want this to mirror the underlying control's\n * disabled state so the visual treatment stays consistent.\n *\n * **Font weight.** A `Label` automatically gets `font-medium` when it does\n * **not** contain a nested form control (`<input>`, `<textarea>`, `<select>`,\n * `<button>`, or `[contenteditable]`). When the label *does* wrap a control,\n * the auto default is intentionally skipped so the control's own typography\n * isn't bolded — apply `font-medium` to your own caption element (e.g. a\n * `<span>` or `<p>`) inside the label. Override the default at any time by\n * passing a font-weight utility on the `Label` itself, e.g.\n * `<Label className=\"font-bold\">`.\n *\n * @see https://mantle.ngrok.com/components/label\n *\n * @example\n * ```tsx\n * import { Label } from \"@ngrok/mantle/label\";\n * import { Input } from \"@ngrok/mantle/input\";\n *\n * // Implicit — control nested inside the label.\n * <Label className=\"grid gap-1\">\n * <span>Email</span>\n * <Input type=\"email\" name=\"email\" />\n * </Label>\n *\n * // Explicit — htmlFor matches the control's id.\n * <div className=\"grid gap-1\">\n * <Label htmlFor=\"api-key\">API key</Label>\n * <Input id=\"api-key\" name=\"apiKey\" />\n * </div>\n *\n * // Inline label for a checkbox.\n * <Label className=\"flex items-center gap-2\">\n * <Checkbox name=\"terms\" />\n * <span>I agree to the terms</span>\n * </Label>\n * ```\n */\nconst Label = forwardRef<ComponentRef<\"label\">, LabelProps>(\n\t(\n\t\t{ \"aria-disabled\": _ariaDisabled, children, className, disabled, onMouseDown, ...props },\n\t\tref,\n\t) => (\n\t\t<label\n\t\t\taria-disabled={disabled ?? _ariaDisabled}\n\t\t\tdata-slot=\"label\"\n\t\t\tclassName={cx(\n\t\t\t\t\"text-strong cursor-pointer text-sm peer-disabled:cursor-default has-disabled:cursor-default aria-disabled:cursor-default font-sans\",\n\t\t\t\t// Default to font-medium when the label isn't wrapping a form control. The\n\t\t\t\t// arbitrary variant wraps the *entire* matched selector — class + the\n\t\t\t\t// `:not(:has(...))` check — in `:where()`, flattening total specificity to 0.\n\t\t\t\t// That lets a user-supplied font-weight utility (`font-bold`, `font-normal`,\n\t\t\t\t// etc.) at (0,1,0) override cleanly, even though `[contenteditable]` is an\n\t\t\t\t// attribute selector that would otherwise lift the rule to (0,1,0) and tie.\n\t\t\t\t\"[:where(&:not(:has(input,textarea,select,button,[contenteditable])))]:font-medium\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tonMouseDown={(event) => {\n\t\t\t\t// only prevent text selection if clicking inside the label itself\n\t\t\t\tconst target = event.target as HTMLElement;\n\t\t\t\tif (target.closest(\"button, input, select, textarea\")) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tonMouseDown?.(event);\n\n\t\t\t\t// prevent text selection when double clicking label\n\t\t\t\tif (!event.defaultPrevented && event.detail > 1) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}}\n\t\t\tref={ref}\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</label>\n\t),\n);\nLabel.displayName = \"Label\";\n\nexport {\n\t//\n\tLabel,\n};\n"],"mappings":"gHAuEA,MAAM,EAAQ,GAEZ,CAAE,gBAAiB,EAAe,WAAU,YAAW,WAAU,cAAa,GAAG,GACjF,IAEA,EAAC,QAAD,CACC,gBAAe,GAAY,EAC3B,YAAU,QACV,UAAW,EACV,qIAOA,oFACA,CACD,EACA,YAAc,GAAU,CAER,EAAM,OACV,QAAQ,iCAAiC,IAIpD,IAAc,CAAK,EAGf,CAAC,EAAM,kBAAoB,EAAM,OAAS,GAC7C,EAAM,eAAe,EAEvB,EACK,MACL,GAAI,EAEH,UACK,CAAA,CAET,EACA,EAAM,YAAc"}
|
package/dist/main.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","names":[],"sources":["../src/components/main/main.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport { cx } from \"../../utils/cx/cx.js\";\n\n/**\n * A focusable `<main>` landmark for the page's primary content. Renders with\n * `id=\"main\"` and `tabIndex={-1}` so a skip link (or any programmatic focus\n * call) can send keyboard users directly to the main content without exposing\n * a visible focus ring on the region itself (`focus:outline-hidden`).\n *\n * Pair with the `<SkipToMainLink>` component at the top of the document.\n *\n * @see https://mantle.ngrok.com/components/main\n *\n * @example\n * ```tsx\n * <SkipToMainLink />\n * <Header />\n * <Main>\n * <h1>Page title</h1>\n * </Main>\n * ```\n */\nconst Main = ({ className, ...props }: ComponentProps<\"main\">) => {\n\treturn (\n\t\t<main\n\t\t\t{...props}\n\t\t\tdata-slot=\"main\"\n\t\t\tid=\"main\"\n\t\t\ttabIndex={-1}\n\t\t\tclassName={cx(\"focus:outline-hidden\", className)}\n\t\t/>\n\t);\n};\nMain.displayName = \"Main\";\n\nexport {\n\t//,\n\tMain,\n};\n"],"mappings":"6EAsBA,MAAM,GAAQ,CAAE,YAAW,GAAG,KAE5B,EAAC,OAAD,CACC,GAAI,EACJ,YAAU,OACV,GAAG,OACH,SAAU,GACV,UAAW,EAAG,uBAAwB,CAAS,CAC/C,CAAA,EAGH,EAAK,YAAc"}
|
package/dist/media-object.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"media-object.js","names":[],"sources":["../src/components/media-object/media-object.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport { forwardRef } from \"react\";\nimport type { WithAsChild } from \"../../types/as-child.js\";\nimport { cx } from \"../../utils/cx/cx.js\";\nimport { Slot } from \"../slot/index.js\";\n\ntype Props = ComponentProps<\"div\"> & WithAsChild;\n\n/**\n * The media object is an image/icon (media) to the left, with descriptive\n * content (title and subtitle/description) to the right. This is the root\n * component of the media object.\n */\nconst Root = forwardRef<HTMLDivElement, Props>(\n\t({ asChild = false, className, children, style }, ref) => {\n\t\tconst Component = asChild ? Slot : \"div\";\n\n\t\treturn (\n\t\t\t<Component\n\t\t\t\tref={ref}\n\t\t\t\tdata-slot=\"media-object\"\n\t\t\t\tclassName={cx(\"flex gap-4\", className)}\n\t\t\t\tstyle={style}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Component>\n\t\t);\n\t},\n);\nRoot.displayName = \"MediaObject\";\n\n/**\n * The container for an image or icon to display in the media slot of the media object.\n */\nconst Media = forwardRef<HTMLDivElement, Props>(\n\t({ asChild = false, className, children, style }, ref) => {\n\t\tconst Component = asChild ? Slot : \"div\";\n\n\t\treturn (\n\t\t\t<Component\n\t\t\t\tref={ref}\n\t\t\t\tdata-slot=\"media-object-media\"\n\t\t\t\tclassName={cx(\"shrink-0 leading-none\", className)}\n\t\t\t\tstyle={style}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Component>\n\t\t);\n\t},\n);\nMedia.displayName = \"MediaObjectMedia\";\n\n/**\n * The container for the content slot of a media object.\n */\nconst Content = forwardRef<HTMLDivElement, Props>(\n\t({ asChild = false, className, children, style }, ref) => {\n\t\tconst Component = asChild ? Slot : \"div\";\n\n\t\treturn (\n\t\t\t<Component\n\t\t\t\tref={ref}\n\t\t\t\tdata-slot=\"media-object-content\"\n\t\t\t\tclassName={cx(\"min-w-0 flex-1\", className)}\n\t\t\t\tstyle={style}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Component>\n\t\t);\n\t},\n);\nContent.displayName = \"MediaObject.Content\";\n\n/**\n * A small, reusable layout primitive for \"image/icon on one side,\n * descriptive content on the other\" — the foundational\n * {@link https://www.stubbornella.org/2010/06/25/the-media-object-saves-hundreds-of-lines-of-code/ \"media object\" pattern}.\n * Use it to compose avatars-with-text, icons-with-copy, thumbnails-with-titles,\n * and similar two-up rows without re-implementing flexbox each time.\n *\n * **When to use**\n * - Comment threads (avatar + name + body).\n * - Compact list items (icon + label + secondary text).\n * - Notification rows.\n * - Feature lists, profile cards, attachment previews.\n *\n * **When not to use**\n * - For complex multi-region layouts — reach for {@link https://mantle.ngrok.com/components/card Card} or build a bespoke flex/grid.\n * - When the media is purely decorative and adds no information — drop it\n * and use a plain block.\n *\n * **Spacing & alignment.** Default gap is `gap-4`; override by passing a\n * different `gap-*` class to `MediaObject.Root`. Use standard flex\n * utilities (`items-start`, `items-center`, etc.) to align media and\n * content vertically.\n *\n * **Polymorphism.** Each part accepts `asChild` for swapping the rendered\n * element (e.g. render `Root` as an `<a>` to make the whole row clickable).\n *\n * @see https://mantle.ngrok.com/components/media-object\n *\n * @example\n * Composition:\n * ```\n * MediaObject.Root\n * ├── MediaObject.Media\n * └── MediaObject.Content\n * ```\n *\n * @example\n * ```tsx\n * import { MediaObject } from \"@ngrok/mantle/media-object\";\n *\n * <MediaObject.Root>\n * <MediaObject.Media>\n * <Avatar src={user.avatarUrl} alt=\"\" />\n * </MediaObject.Media>\n * <MediaObject.Content>\n * <p className=\"font-medium\">{user.name}</p>\n * <p className=\"text-muted text-sm\">{comment}</p>\n * </MediaObject.Content>\n * </MediaObject.Root>\n * ```\n */\nconst MediaObject = {\n\t/**\n\t * The media object is an image/icon (media) to the left, with descriptive\n\t * content (title and subtitle/description) to the right. This is the root\n\t * component of the media object.\n\t *\n\t * Change the spacing between the media and content by passing a `gap-*` class.\n\t * The default gap is `gap-4`.\n\t *\n\t * Use flexbox utilities to change the alignment of the media and content.\n\t *\n\t * Compose the media object with the `MediaObject.Media` and `MediaObject.Content`\n\t * components as direct children.\n\t *\n\t * @see https://mantle.ngrok.com/components/media-object#mediaobjectroot\n\t *\n\t * @example\n\t * ```tsx\n\t * <MediaObject.Root>\n\t * <MediaObject.Media>\n\t * <ExampleMedia />\n\t * </MediaObject.Media>\n\t * <MediaObject.Content>\n\t * <p>Ea culpa id id ea minim labore.</p>\n\t * </MediaObject.Content>\n\t * </MediaObject.Root>\n\t * ```\n\t */\n\tRoot,\n\t/**\n\t * The container for an image or icon to display in the media slot of the media object.\n\t *\n\t * @see https://mantle.ngrok.com/components/media-object#mediaobjectmedia\n\t *\n\t * @example\n\t * ```tsx\n\t * <MediaObject.Root>\n\t * <MediaObject.Media>\n\t * <ExampleMedia />\n\t * </MediaObject.Media>\n\t * <MediaObject.Content>\n\t * <p>Ea culpa id id ea minim labore.</p>\n\t * </MediaObject.Content>\n\t * </MediaObject.Root>\n\t * ```\n\t */\n\tMedia,\n\t/**\n\t * The container for the content slot of a media object.\n\t *\n\t * @see https://mantle.ngrok.com/components/media-object#mediaobjectcontent\n\t *\n\t * @example\n\t * ```tsx\n\t * <MediaObject.Root>\n\t * <MediaObject.Media>\n\t * <ExampleMedia />\n\t * </MediaObject.Media>\n\t * <MediaObject.Content>\n\t * <p>Ea culpa id id ea minim labore.</p>\n\t * </MediaObject.Content>\n\t * </MediaObject.Root>\n\t * ```\n\t */\n\tContent,\n} as const;\n\nexport {\n\t//,\n\tMediaObject,\n};\n"],"mappings":"kJAaA,MAAM,EAAO,GACX,CAAE,UAAU,GAAO,YAAW,WAAU,SAAS,IAIhD,EAHiB,EAAU,EAAO,MAGlC,CACM,MACL,YAAU,eACV,UAAW,EAAG,aAAc,CAAS,EAC9B,QAEN,UACS,CAAA,CAGd,EACA,EAAK,YAAc,cAKnB,MAAM,EAAQ,GACZ,CAAE,UAAU,GAAO,YAAW,WAAU,SAAS,IAIhD,EAHiB,EAAU,EAAO,MAGlC,CACM,MACL,YAAU,qBACV,UAAW,EAAG,wBAAyB,CAAS,EACzC,QAEN,UACS,CAAA,CAGd,EACA,EAAM,YAAc,mBAKpB,MAAM,EAAU,GACd,CAAE,UAAU,GAAO,YAAW,WAAU,SAAS,IAIhD,EAHiB,EAAU,EAAO,MAGlC,CACM,MACL,YAAU,uBACV,UAAW,EAAG,iBAAkB,CAAS,EAClC,QAEN,UACS,CAAA,CAGd,EACA,EAAQ,YAAc,sBAqDtB,MAAM,EAAc,CA4BnB,OAkBA,QAkBA,SACD"}
|
package/dist/multi-select.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"multi-select.js","names":[],"sources":["../src/components/multi-select/multi-select.tsx"],"sourcesContent":["\"use client\";\n\nimport * as Primitive from \"@ariakit/react\";\nimport { CheckIcon } from \"@phosphor-icons/react/Check\";\nimport { LockIcon } from \"@phosphor-icons/react/Lock\";\nimport { XIcon } from \"@phosphor-icons/react/X\";\nimport type {\n\tComponentProps,\n\tComponentPropsWithoutRef,\n\tComponentRef,\n\tKeyboardEvent,\n\tReactNode,\n\tRefObject,\n} from \"react\";\nimport {\n\tcreateContext,\n\tforwardRef,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n} from \"react\";\nimport type { WithAsChild } from \"../../types/as-child.js\";\nimport { getPrefersReducedMotion } from \"../../hooks/use-prefers-reduced-motion.js\";\nimport { composeRefs } from \"../../utils/compose-refs/compose-refs.js\";\nimport { cx } from \"../../utils/cx/cx.js\";\nimport { FieldControlContext } from \"../field/field-context.js\";\nimport { parseValidation, useFieldValidation } from \"../field/validation.js\";\nimport type { WithValidation } from \"../field/validation.js\";\nimport { Icon } from \"../icon/icon.js\";\nimport { Separator } from \"../separator/separator.js\";\nimport { Slot } from \"../slot/index.js\";\n\n/** Type guard to safely narrow Ariakit store state to `string[]` without `as` assertions. */\nconst isStringArray = (value: unknown): value is string[] =>\n\tArray.isArray(value) && value.every((item) => typeof item === \"string\");\n\n/** Stable empty array used as a fallback for `selectedValues` to avoid creating new arrays on every render. */\nconst EMPTY_ARRAY: string[] = [];\n\nconst TriggerRefContext = createContext<RefObject<HTMLDivElement | null>>({ current: null });\n\n/**\n * Shared ref for locked values. Written by `TagValues` during render so that `Item` can read\n * it synchronously and prevent deselection of locked values from the popover.\n * Using a ref (instead of state) avoids re-renders and keeps the write safe in render.\n */\nconst LockedValuesContext = createContext<{ current: string[] }>({ current: [] });\n\n/**\n * Bridges keyboard-nav state between `TagValues` and `Input`, which are siblings in the tree\n * and cannot communicate via a context that either one provides — it must come from a shared\n * ancestor (`Root`). Both refs are written by one side and read by the other:\n * - `onInputKeyDownRef`: written by `TagValues`, called by `Input` on keydown\n * - `inputRef`: written by `Input` (registers its DOM node), read by `TagValues` (to focus it)\n */\ntype TagBridgeContextValue = {\n\tonInputKeyDownRef: { current: ((event: KeyboardEvent<HTMLInputElement>) => void) | undefined };\n\tinputRef: { current: HTMLInputElement | null };\n};\n\nconst TagBridgeContext = createContext<TagBridgeContextValue>({\n\tonInputKeyDownRef: { current: undefined },\n\tinputRef: { current: null },\n});\n\ntype MultiSelectProps = Primitive.ComboboxProviderProps<string[]>;\n\n/**\n * Root component for a multi-select combobox. Provides state management for\n * selecting multiple values with typeahead filtering.\n *\n * Use MultiSelect when the user can choose multiple values from a list, with selected\n * items rendered as removable tags/chips. For single selection, use Combobox (with search)\n * or Select (without).\n *\n * When composing with `Field.Item`, wrap `MultiSelect.Root` in `Field.Control`.\n * `Field.Control` flows the generated `id`, `name`, `aria-describedby`,\n * `aria-errormessage`, and `aria-invalid` through to the focusable\n * `MultiSelect.Input` via `FieldControlContext`.\n *\n * @see https://mantle.ngrok.com/components/multi-select#multiselectroot\n *\n * @example\n * ```tsx\n * <MultiSelect.Root>\n * <MultiSelect.Trigger>\n * <MultiSelect.TagValues />\n * <MultiSelect.Input placeholder=\"Select items...\" />\n * </MultiSelect.Trigger>\n * <MultiSelect.Content>\n * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n * <MultiSelect.Item value=\"banana\">Banana</MultiSelect.Item>\n * </MultiSelect.Content>\n * </MultiSelect.Root>\n * ```\n */\nconst Root = ({ children, defaultSelectedValue = EMPTY_ARRAY, ...props }: MultiSelectProps) => {\n\tconst triggerRef = useRef<HTMLDivElement | null>(null);\n\tconst onInputKeyDownRef = useRef<((event: KeyboardEvent<HTMLInputElement>) => void) | undefined>(\n\t\tundefined,\n\t);\n\tconst inputRef = useRef<HTMLInputElement | null>(null);\n\tconst lockedValuesRef = useRef<string[]>([]);\n\tconst tagBridge = useMemo(() => ({ onInputKeyDownRef, inputRef }), []);\n\n\treturn (\n\t\t<TriggerRefContext.Provider value={triggerRef}>\n\t\t\t<TagBridgeContext.Provider value={tagBridge}>\n\t\t\t\t<LockedValuesContext.Provider value={lockedValuesRef}>\n\t\t\t\t\t<Primitive.ComboboxProvider<string[]>\n\t\t\t\t\t\tdefaultSelectedValue={defaultSelectedValue}\n\t\t\t\t\t\t{...props}\n\t\t\t\t\t>\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</Primitive.ComboboxProvider>\n\t\t\t\t</LockedValuesContext.Provider>\n\t\t\t</TagBridgeContext.Provider>\n\t\t</TriggerRefContext.Provider>\n\t);\n};\nRoot.displayName = \"MultiSelect\";\n\ntype MultiSelectTriggerProps = ComponentPropsWithoutRef<\"div\"> & WithValidation;\n\n/**\n * The trigger container for the multi-select. Wraps the input and selected\n * value tags in a styled container that looks like a form input.\n *\n * @see https://mantle.ngrok.com/components/multi-select#multiselecttrigger\n *\n * @example\n * ```tsx\n * <MultiSelect.Root>\n * <MultiSelect.Trigger>\n * <MultiSelect.TagValues />\n * <MultiSelect.Input placeholder=\"Select items...\" />\n * </MultiSelect.Trigger>\n * <MultiSelect.Content>\n * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n * </MultiSelect.Content>\n * </MultiSelect.Root>\n * ```\n */\nconst Trigger = forwardRef<HTMLDivElement, MultiSelectTriggerProps>(\n\t(\n\t\t{\n\t\t\t\"aria-invalid\": _ariaInvalid,\n\t\t\tclassName,\n\t\t\tchildren,\n\t\t\tonKeyDown,\n\t\t\tonMouseDown,\n\t\t\tvalidation: _validation,\n\t\t\t...props\n\t\t},\n\t\tref,\n\t) => {\n\t\tconst triggerRef = useContext(TriggerRefContext);\n\t\tconst { inputRef } = useContext(TagBridgeContext);\n\t\tconst store = Primitive.useComboboxContext();\n\t\tconst fieldValidation = useFieldValidation();\n\t\tconst { validation } = parseValidation({\n\t\t\t\"aria-invalid\": _ariaInvalid,\n\t\t\tvalidation: _validation ?? fieldValidation,\n\t\t});\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\trole=\"group\"\n\t\t\t\tdata-slot=\"multi-select-trigger\"\n\t\t\t\tclassName={cx(\n\t\t\t\t\t\"cursor-text select-none font-sans text-sm\",\n\t\t\t\t\t\"border-form bg-form text-strong flex min-h-9 w-full flex-wrap items-center gap-1 rounded-md border px-3 py-1 has-[[data-slot=multi-select-tag]]:px-1\",\n\t\t\t\t\t\"has-focus:outline-hidden has-focus-within:ring-4 has-aria-expanded:ring-4\",\n\t\t\t\t\t\"has-focus-within:border-accent-600 has-focus-within:ring-focus-accent has-aria-expanded:border-accent-600 has-aria-expanded:ring-focus-accent\",\n\t\t\t\t\t\"data-validation-success:border-success-600 data-validation-success:has-focus-within:border-success-600 data-validation-success:has-focus-within:ring-focus-success data-validation-success:has-aria-expanded:border-success-600 data-validation-success:has-aria-expanded:ring-focus-success\",\n\t\t\t\t\t\"data-validation-warning:border-warning-600 data-validation-warning:has-focus-within:border-warning-600 data-validation-warning:has-focus-within:ring-focus-warning data-validation-warning:has-aria-expanded:border-warning-600 data-validation-warning:has-aria-expanded:ring-focus-warning\",\n\t\t\t\t\t\"data-validation-error:border-danger-600 data-validation-error:has-focus-within:border-danger-600 data-validation-error:has-focus-within:ring-focus-danger data-validation-error:has-aria-expanded:border-danger-600 data-validation-error:has-aria-expanded:ring-focus-danger\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tdata-validation={validation || undefined}\n\t\t\t\tonKeyDown={(event) => {\n\t\t\t\t\tif (event.key === \"Escape\" && store?.getState().open) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tstore.hide();\n\t\t\t\t\t}\n\t\t\t\t\tonKeyDown?.(event);\n\t\t\t\t}}\n\t\t\t\tonMouseDown={(event) => {\n\t\t\t\t\t// When clicking on non-interactive areas (padding, flex gaps between tags), prevent the\n\t\t\t\t\t// default mousedown behavior (which would cause text selection) and explicitly focus the\n\t\t\t\t\t// input. Clicks on buttons, the input itself, or tag spans are handled by those elements.\n\t\t\t\t\tif (\n\t\t\t\t\t\tevent.target instanceof HTMLElement &&\n\t\t\t\t\t\t!event.target.closest(\"button, input, [role='option']\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tinputRef.current?.focus();\n\t\t\t\t\t}\n\t\t\t\t\tonMouseDown?.(event);\n\t\t\t\t}}\n\t\t\t\tref={composeRefs(triggerRef, ref)}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t);\n\t},\n);\nTrigger.displayName = \"MultiSelectTrigger\";\n\ntype TagProps = Omit<ComponentProps<\"span\">, \"children\"> & {\n\t/**\n\t * The value to display in the tag label.\n\t */\n\tvalue: string;\n\t/**\n\t * Called when the remove button is clicked.\n\t */\n\tonRemove?: () => void;\n\t/**\n\t * When true, the tag cannot be removed. The remove button is disabled and\n\t * Delete/Backspace key presses are ignored while the tag is focused.\n\t */\n\tlocked?: boolean;\n};\n\n/**\n * The default tag rendered inside `MultiSelect.TagValues` for each selected value.\n * Displays the value label with a remove button and full keyboard navigation support.\n *\n * Use this when building a custom `TagValues`-like component and you want the\n * default tag chrome with consistent styling.\n *\n * @see https://mantle.ngrok.com/components/multi-select#multiselecttag\n *\n * @example\n * ```tsx\n * <MultiSelect.Root>\n * <MultiSelect.Trigger>\n * <MultiSelect.TagValues>\n * {(props) => <MultiSelect.Tag key={props.value} {...props} />}\n * </MultiSelect.TagValues>\n * <MultiSelect.Input placeholder=\"Select items...\" />\n * </MultiSelect.Trigger>\n * <MultiSelect.Content>\n * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n * </MultiSelect.Content>\n * </MultiSelect.Root>\n * ```\n */\nconst Tag = forwardRef<HTMLSpanElement, TagProps>(\n\t({ className, value, onRemove, locked = false, onKeyDown, ...props }, ref) => {\n\t\tconst internalRef = useRef<HTMLSpanElement | null>(null);\n\n\t\treturn (\n\t\t\t<span\n\t\t\t\tref={composeRefs(internalRef, ref)}\n\t\t\t\trole=\"option\"\n\t\t\t\taria-selected\n\t\t\t\ttabIndex={-1}\n\t\t\t\tdata-slot=\"multi-select-tag\"\n\t\t\t\tdata-locked={locked || undefined}\n\t\t\t\tclassName={cx(\n\t\t\t\t\t\"cursor-default bg-neutral-500/10 border border-neutral-500/20 rounded-xs text-strong inline-flex items-center gap-1 pl-2 pr-0.5 py-0.5 text-sm font-normal\",\n\t\t\t\t\t\"focus-visible:outline-hidden focus-visible:border-accent-600/50 focus-visible:ring-3 focus-visible:ring-focus-accent\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tonKeyDown={(event) => {\n\t\t\t\t\tif (locked && (event.key === \"Backspace\" || event.key === \"Delete\")) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tshakeElement(event.currentTarget);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tonKeyDown?.(event);\n\t\t\t\t}}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{value}\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-label={`Remove ${value}`}\n\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\taria-disabled={locked || undefined}\n\t\t\t\t\tclassName={cx(\n\t\t\t\t\t\t\"cursor-pointer text-strong/40 hover:bg-neutral-500/15 hover:text-strong rounded-xs p-0.5\",\n\t\t\t\t\t\t\"aria-disabled:cursor-default aria-disabled:hover:bg-transparent aria-disabled:hover:text-strong/40\",\n\t\t\t\t\t)}\n\t\t\t\t\tonClick={(event) => {\n\t\t\t\t\t\t// Prevent the click from bubbling to the trigger, which would reopen or refocus the combobox\n\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\tif (locked) {\n\t\t\t\t\t\t\t// Shake the tag to signal that removal is blocked\n\t\t\t\t\t\t\tconst tagElement = internalRef.current;\n\t\t\t\t\t\t\tif (tagElement) {\n\t\t\t\t\t\t\t\tshakeElement(tagElement);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tonRemove?.();\n\t\t\t\t\t}}\n\t\t\t\t\tonMouseDown={(event) => {\n\t\t\t\t\t\t// Prevent the input from losing focus on click, which would close the popover before the remove fires\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<Icon svg={locked ? <LockIcon /> : <XIcon weight=\"bold\" />} className=\"size-4\" />\n\t\t\t\t</button>\n\t\t\t</span>\n\t\t);\n\t},\n);\nTag.displayName = \"MultiSelectTag\";\n\n/**\n * Props passed to the children render function of `MultiSelect.TagValues`.\n * Spread these onto `MultiSelect.Tag` (or your own tag component) to\n * get the value, remove handler, locked state, and ref-based keyboard-nav\n * registration all wired up automatically.\n *\n * Pre-wired handlers included:\n * - `onKeyDown` — arrow-key nav between tags, Backspace/Delete to remove\n * - `onClick` — focuses the tag and ensures the popover opens/stays open\n */\ntype TagRenderProps = TagProps & {\n\t/** Ref callback — forward this to the tag element to enable keyboard navigation between tags. */\n\tref: (node: HTMLSpanElement | null) => void;\n};\n\ntype MultiSelectTagValuesProps = {\n\t/**\n\t * Values that cannot be removed. Locked tags have their remove button disabled,\n\t * respond to Backspace/Delete key presses with a shake animation, and shake when\n\t * Backspace is pressed on an empty input.\n\t *\n\t * The `locked` state is also forwarded to the render function via `props.locked`\n\t * so custom tag components receive it automatically.\n\t */\n\tlockedValues?: string[];\n\t/**\n\t * Optional render function for each tag. Receives `{ value, onRemove, locked, ref }` —\n\t * spread these onto `MultiSelect.Tag` (or your own element) for full keyboard-nav support.\n\t * When omitted, the default `MultiSelect.Tag` is rendered for each selected value.\n\t *\n\t * @example\n\t * ```tsx\n\t * <MultiSelect.TagValues lockedValues={[\"global\"]}>\n\t * {(props) => (\n\t * <MultiSelect.Tag key={props.value} {...props} />\n\t * )}\n\t * </MultiSelect.TagValues>\n\t * ```\n\t */\n\tchildren?: (props: TagRenderProps) => ReactNode;\n};\n\n/**\n * Renders the selected values as removable tags. Place this inside\n * `MultiSelect.Trigger`, followed by `MultiSelect.Input`.\n *\n * @see https://mantle.ngrok.com/components/multi-select#multiselecttagvalues\n *\n * @example\n * ```tsx\n * <MultiSelect.Root>\n * <MultiSelect.Trigger>\n * <MultiSelect.TagValues />\n * <MultiSelect.Input placeholder=\"Select items...\" />\n * </MultiSelect.Trigger>\n * <MultiSelect.Content>\n * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n * </MultiSelect.Content>\n * </MultiSelect.Root>\n * ```\n */\nconst TagValues = ({ children, lockedValues = EMPTY_ARRAY }: MultiSelectTagValuesProps) => {\n\tconst store = Primitive.useComboboxContext();\n\tconst rawSelectedValue = Primitive.useStoreState(store, \"selectedValue\");\n\tconst selectedValues = isStringArray(rawSelectedValue) ? rawSelectedValue : undefined;\n\tconst selectedArray = selectedValues ?? EMPTY_ARRAY;\n\t// Keep refs in sync so requestAnimationFrame callbacks always read fresh state\n\t// instead of closing over stale values from the render they were scheduled in.\n\tconst selectedArrayRef = useRef<string[]>(selectedArray);\n\tselectedArrayRef.current = selectedArray;\n\t// Use the shared LockedValuesContext ref so Item can also read locked values\n\t// without a separate prop. Writing a ref during render is safe here because\n\t// refs are mutable and don't trigger re-renders.\n\tconst lockedValuesRef = useContext(LockedValuesContext);\n\tlockedValuesRef.current = lockedValues;\n\tconst lockedValuesSet = useMemo(() => new Set(lockedValues), [lockedValues]);\n\tconst tagRefs = useRef<Map<string, HTMLSpanElement>>(new Map());\n\tconst { onInputKeyDownRef, inputRef } = useContext(TagBridgeContext);\n\t// Track pending rAF IDs so we can cancel them on unmount and avoid calling\n\t// focus() on detached DOM nodes if the component unmounts mid-frame.\n\tconst pendingRafsRef = useRef<Set<number>>(new Set());\n\tuseEffect(\n\t\t() => () => {\n\t\t\tpendingRafsRef.current.forEach(cancelAnimationFrame);\n\t\t},\n\t\t[],\n\t);\n\tconst raf = (callback: () => void): void => {\n\t\tconst id = requestAnimationFrame(() => {\n\t\t\t// Remove the id once the rAF has fired so the set doesn't grow unbounded.\n\t\t\tpendingRafsRef.current.delete(id);\n\t\t\tcallback();\n\t\t});\n\t\tpendingRafsRef.current.add(id);\n\t};\n\n\tconst removeValue = (value: string) => {\n\t\tif (store) {\n\t\t\tconst selected = store.getState().selectedValue;\n\t\t\tif (!isStringArray(selected)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstore.setSelectedValue(selected.filter((v) => v !== value));\n\t\t}\n\t};\n\n\tconst focusTag = (index: number) => {\n\t\tconst value = selectedArrayRef.current[index];\n\t\tif (value == null) {\n\t\t\treturn;\n\t\t}\n\t\tconst tagElement = tagRefs.current.get(value);\n\t\tif (tagElement) {\n\t\t\ttagElement.focus();\n\t\t\t// Keep the popover open while a tag is focused. Ariakit closes the\n\t\t\t// popover when the combobox input loses focus, so we reopen it here.\n\t\t\tstore?.show();\n\t\t}\n\t};\n\n\tconst focusInput = () => {\n\t\tinputRef.current?.focus();\n\t};\n\n\tconst handleTagKeyDown = (event: KeyboardEvent<HTMLSpanElement>, index: number) => {\n\t\tconst value = selectedArray[index];\n\t\tswitch (event.key) {\n\t\t\tcase \"ArrowLeft\": {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tif (index > 0) {\n\t\t\t\t\tfocusTag(index - 1);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"ArrowRight\": {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tif (index < selectedArray.length - 1) {\n\t\t\t\t\tfocusTag(index + 1);\n\t\t\t\t} else {\n\t\t\t\t\tfocusInput();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"Backspace\":\n\t\t\tcase \"Delete\": {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tif (value != null) {\n\t\t\t\t\t// Respect locked values: shake instead of removing when locked.\n\t\t\t\t\tif (lockedValuesSet.has(value)) {\n\t\t\t\t\t\tconst tagElement = tagRefs.current.get(value);\n\t\t\t\t\t\tif (tagElement) {\n\t\t\t\t\t\t\tshakeElement(tagElement);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tremoveValue(value);\n\t\t\t\t\t// After removal, the array shifts. Focus the next logical tag or the input.\n\t\t\t\t\tif (event.key === \"Backspace\") {\n\t\t\t\t\t\tif (index > 0) {\n\t\t\t\t\t\t\t// Focus the previous tag (will have same index - 1 after removal)\n\t\t\t\t\t\t\t// We need to wait for the next render, so use requestAnimationFrame\n\t\t\t\t\t\t\tconst prevIndex = index - 1;\n\t\t\t\t\t\t\traf(() => focusTag(prevIndex));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\traf(() => {\n\t\t\t\t\t\t\t\tif (selectedArrayRef.current.length > 0) {\n\t\t\t\t\t\t\t\t\tfocusTag(0);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tfocusInput();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Delete: move focus right\n\t\t\t\t\t\traf(() => {\n\t\t\t\t\t\t\t// index stays the same since the item at `index` was removed and the next one slides in\n\t\t\t\t\t\t\tif (index < selectedArrayRef.current.length) {\n\t\t\t\t\t\t\t\tfocusTag(index);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tfocusInput();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"ArrowUp\":\n\t\t\tcase \"ArrowDown\": {\n\t\t\t\t// Don't scroll the page. Instead, focus the input and forward the key\n\t\t\t\t// to Ariakit so it navigates the popover list.\n\t\t\t\tevent.preventDefault();\n\t\t\t\tfocusInput();\n\t\t\t\tinputRef.current?.dispatchEvent(\n\t\t\t\t\tnew KeyboardEvent(\"keydown\", {\n\t\t\t\t\t\tkey: event.key,\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcancelable: true,\n\t\t\t\t\t\tshiftKey: event.shiftKey,\n\t\t\t\t\t\tctrlKey: event.ctrlKey,\n\t\t\t\t\t\tmetaKey: event.metaKey,\n\t\t\t\t\t\taltKey: event.altKey,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\t// If a printable character is typed while a tag is focused, jump to input\n\t\t\t\tif (event.key.length === 1 && !event.ctrlKey && !event.metaKey) {\n\t\t\t\t\tfocusInput();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t};\n\n\tconst handleInputKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n\t\tif (\n\t\t\tevent.key === \"ArrowLeft\" &&\n\t\t\tevent.currentTarget.selectionStart === 0 &&\n\t\t\tevent.currentTarget.selectionEnd === 0 &&\n\t\t\tselectedArray.length > 0\n\t\t) {\n\t\t\tevent.preventDefault();\n\t\t\tfocusTag(selectedArray.length - 1);\n\t\t\treturn;\n\t\t}\n\t\tif (event.key === \"Backspace\" && event.currentTarget.value === \"\" && selectedArray.length > 0) {\n\t\t\tconst lastValue = selectedArray[selectedArray.length - 1];\n\t\t\tif (lastValue != null) {\n\t\t\t\tif (lockedValuesRef.current.includes(lastValue)) {\n\t\t\t\t\t// The last tag is locked — shake it to signal that removal is blocked.\n\t\t\t\t\tconst tagElement = tagRefs.current.get(lastValue);\n\t\t\t\t\tif (tagElement) {\n\t\t\t\t\t\tshakeElement(tagElement);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tremoveValue(lastValue);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t// Write the latest handler into the bridge ref so Input can call it via onKeyDown.\n\t// Assigned directly during render (safe — refs are mutable and don't trigger re-renders).\n\tonInputKeyDownRef.current = handleInputKeyDown;\n\n\treturn (\n\t\t<>\n\t\t\t{selectedArray.map((value, index) => {\n\t\t\t\tconst tagOptionProps: TagRenderProps = {\n\t\t\t\t\tvalue,\n\t\t\t\t\tlocked: lockedValuesSet.has(value),\n\t\t\t\t\tonRemove: () => {\n\t\t\t\t\t\t// Respect locked values: shake instead of removing when locked.\n\t\t\t\t\t\t// This guards custom tag renderers that call onRemove directly.\n\t\t\t\t\t\tif (lockedValuesSet.has(value)) {\n\t\t\t\t\t\t\tconst tagElement = tagRefs.current.get(value);\n\t\t\t\t\t\t\tif (tagElement) {\n\t\t\t\t\t\t\t\tshakeElement(tagElement);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tremoveValue(value);\n\t\t\t\t\t},\n\t\t\t\t\tref: (node: HTMLSpanElement | null) => {\n\t\t\t\t\t\tif (node) {\n\t\t\t\t\t\t\ttagRefs.current.set(value, node);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttagRefs.current.delete(value);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tonKeyDown: (event: KeyboardEvent<HTMLSpanElement>) => handleTagKeyDown(event, index),\n\t\t\t\t\t// Ensure the popover opens/stays open when a tag is clicked,\n\t\t\t\t\t// including when the component was fully blurred before the click.\n\t\t\t\t\tonClick: () => focusTag(index),\n\t\t\t\t};\n\n\t\t\t\tif (children) {\n\t\t\t\t\treturn children(tagOptionProps);\n\t\t\t\t}\n\n\t\t\t\treturn <Tag key={value} {...tagOptionProps} />;\n\t\t\t})}\n\t\t</>\n\t);\n};\nTagValues.displayName = \"MultiSelectTagValues\";\n\ntype MultiSelectInputProps = Omit<Primitive.ComboboxProps, \"render\"> & {\n\t/**\n\t * Called with the raw string value whenever the input text changes.\n\t * Use this to drive external filtering (e.g. with matchSorter) without\n\t * having to unwrap the DOM event. A convenience alternative to `onChange`.\n\t */\n\tonValueChange?: (value: string) => void;\n};\n\n/**\n * The combobox input for filtering items. Place this inside `MultiSelect.Trigger`,\n * after `MultiSelect.TagValues`.\n *\n * `MultiSelect.Input` is the focusable element of the multi-select. When the\n * surrounding `MultiSelect.Root` is wrapped in `Field.Control`, the generated\n * `id`, `aria-invalid`, `aria-describedby`, and `aria-errormessage` flow onto\n * the input here via `FieldControlContext`.\n *\n * @see https://mantle.ngrok.com/components/multi-select#multiselectinput\n *\n * @example\n * ```tsx\n * <MultiSelect.Root>\n * <MultiSelect.Trigger>\n * <MultiSelect.TagValues />\n * <MultiSelect.Input placeholder=\"Select items...\" />\n * </MultiSelect.Trigger>\n * <MultiSelect.Content>\n * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n * </MultiSelect.Content>\n * </MultiSelect.Root>\n * ```\n */\nconst Input = forwardRef<ComponentRef<\"input\">, MultiSelectInputProps>(\n\t(\n\t\t{ className, onBlur, onChange, onFocus, onKeyDown, onValueChange, placeholder, ...props },\n\t\tref,\n\t) => {\n\t\tconst store = Primitive.useComboboxContext();\n\t\tconst { onInputKeyDownRef, inputRef } = useContext(TagBridgeContext);\n\t\tconst fieldControl = useContext(FieldControlContext);\n\t\tconst rawSelectedValue = Primitive.useStoreState(store, \"selectedValue\");\n\t\tconst selectedValues = isStringArray(rawSelectedValue) ? rawSelectedValue : undefined;\n\t\tconst hasSelectedValues = (selectedValues?.length ?? 0) > 0;\n\n\t\treturn (\n\t\t\t<Primitive.Combobox\n\t\t\t\tautoSelect\n\t\t\t\tdata-slot=\"multi-select-input\"\n\t\t\t\tclassName={cx(\n\t\t\t\t\t\"pointer-coarse:text-base min-w-20 flex-1 select-text border-0 bg-transparent text-sm outline-hidden\",\n\t\t\t\t\t\"placeholder:select-none placeholder:text-placeholder\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tonChange={(event) => {\n\t\t\t\t\tonValueChange?.(event.target.value);\n\t\t\t\t\tonChange?.(event);\n\t\t\t\t}}\n\t\t\t\tonKeyDown={(event) => {\n\t\t\t\t\tonInputKeyDownRef.current?.(event);\n\t\t\t\t\tonKeyDown?.(event);\n\t\t\t\t}}\n\t\t\t\tonBlur={(event) => {\n\t\t\t\t\t// When focus moves from the input to a tag, Ariakit would normally\n\t\t\t\t\t// close the popover because the combobox input lost focus. Keep it\n\t\t\t\t\t// open so the user can see the list while navigating tags.\n\t\t\t\t\tif (\n\t\t\t\t\t\tevent.relatedTarget instanceof HTMLElement &&\n\t\t\t\t\t\tevent.relatedTarget.closest('[data-slot=\"multi-select-tag\"]')\n\t\t\t\t\t) {\n\t\t\t\t\t\tstore?.show();\n\t\t\t\t\t}\n\t\t\t\t\tonBlur?.(event);\n\t\t\t\t}}\n\t\t\t\tonFocus={(event) => {\n\t\t\t\t\t// Ariakit doesn't always open the popover on focus when the input is\n\t\t\t\t\t// already mounted (e.g. returning focus from a tag). Force it open.\n\t\t\t\t\tstore?.show();\n\t\t\t\t\tonFocus?.(event);\n\t\t\t\t}}\n\t\t\t\tplaceholder={hasSelectedValues ? undefined : placeholder}\n\t\t\t\t// Register the input's DOM node in the bridge so TagValues can focus it for keyboard nav.\n\t\t\t\tref={composeRefs(inputRef, ref)}\n\t\t\t\t{...props}\n\t\t\t\t{...(fieldControl\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t\"aria-describedby\": fieldControl[\"aria-describedby\"],\n\t\t\t\t\t\t\t\"aria-errormessage\": fieldControl[\"aria-errormessage\"],\n\t\t\t\t\t\t\t\"aria-invalid\": fieldControl[\"aria-invalid\"],\n\t\t\t\t\t\t\tid: fieldControl.id,\n\t\t\t\t\t\t\tname: fieldControl.name,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined)}\n\t\t\t/>\n\t\t);\n\t},\n);\nInput.displayName = \"MultiSelectInput\";\n\ntype MultiSelectContentProps = Omit<Primitive.ComboboxPopoverProps, \"render\"> & WithAsChild;\n\n/**\n * Renders a popover that contains multi-select content, such as items, groups,\n * and separators. Opens below the trigger.\n *\n * @see https://mantle.ngrok.com/components/multi-select#multiselectcontent\n *\n * @example\n * ```tsx\n * <MultiSelect.Root>\n * <MultiSelect.Trigger>\n * <MultiSelect.TagValues />\n * <MultiSelect.Input placeholder=\"Select items...\" />\n * </MultiSelect.Trigger>\n * <MultiSelect.Content>\n * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n * <MultiSelect.Item value=\"banana\">Banana</MultiSelect.Item>\n * </MultiSelect.Content>\n * </MultiSelect.Root>\n * ```\n */\nconst Content = forwardRef<ComponentRef<\"div\">, MultiSelectContentProps>(\n\t(\n\t\t{\n\t\t\tasChild = false,\n\t\t\tbackdrop = false,\n\t\t\tchildren,\n\t\t\tclassName,\n\t\t\tmodal = true,\n\t\t\tportalElement,\n\t\t\tsameWidth = true,\n\t\t\tunmountOnHide = true,\n\t\t\t...props\n\t\t},\n\t\tref,\n\t) => {\n\t\tconst triggerRef = useContext(TriggerRefContext);\n\n\t\tconst getAnchorRect = useCallback(() => {\n\t\t\treturn triggerRef.current?.getBoundingClientRect() ?? null;\n\t\t}, [triggerRef]);\n\n\t\tconst getPortalElement = useCallback(\n\t\t\t(element: HTMLElement) => {\n\t\t\t\tif (typeof portalElement === \"function\") {\n\t\t\t\t\treturn portalElement(element);\n\t\t\t\t}\n\n\t\t\t\treturn (\n\t\t\t\t\tportalElement ??\n\t\t\t\t\ttriggerRef.current?.closest<HTMLElement>(\"[data-mantle-modal-content]\") ??\n\t\t\t\t\telement.ownerDocument.body\n\t\t\t\t);\n\t\t\t},\n\t\t\t[portalElement, triggerRef],\n\t\t);\n\n\t\tconst hideOnInteractOutside = useCallback(\n\t\t\t(event: Event) => {\n\t\t\t\t// Keep the popover open when interacting with any part of the trigger\n\t\t\t\t// (tags, buttons, input, padding). Ariakit would otherwise close on any\n\t\t\t\t// mousedown outside the popover — including tag clicks.\n\t\t\t\tif (event.target instanceof Node && triggerRef.current?.contains(event.target)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t},\n\t\t\t[triggerRef],\n\t\t);\n\n\t\treturn (\n\t\t\t<Primitive.ComboboxPopover\n\t\t\t\tdata-slot=\"multi-select-content\"\n\t\t\t\tclassName={cx(\n\t\t\t\t\t\"border-popover bg-popover relative z-50 max-h-96 min-w-32 scrollbar overflow-y-scroll overflow-x-hidden overscroll-y-none rounded-md border shadow-md pt-1 pb-1 has-data-content-footer:pb-0 font-sans flex flex-col gap-px focus:outline-hidden\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tbackdrop={backdrop}\n\t\t\t\tgetAnchorRect={getAnchorRect}\n\t\t\t\tgutter={4}\n\t\t\t\thideOnInteractOutside={hideOnInteractOutside}\n\t\t\t\tmodal={modal}\n\t\t\t\tportalElement={getPortalElement}\n\t\t\t\tref={ref}\n\t\t\t\trender={\n\t\t\t\t\tasChild ? ({ ref, ...childProps }) => <Slot ref={ref} {...childProps} /> : undefined\n\t\t\t\t}\n\t\t\t\tsameWidth={sameWidth}\n\t\t\t\tunmountOnHide={unmountOnHide}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Primitive.ComboboxPopover>\n\t\t);\n\t},\n);\nContent.displayName = \"MultiSelectContent\";\n\ntype MultiSelectItemProps = Omit<Primitive.ComboboxItemProps, \"render\"> & WithAsChild;\n\n/**\n * Renders a selectable item inside a `MultiSelect.Content` component.\n * Items display a checkbox indicator when selected.\n *\n * @see https://mantle.ngrok.com/components/multi-select#multiselectitem\n *\n * @example\n * ```tsx\n * <MultiSelect.Root>\n * <MultiSelect.Trigger>\n * <MultiSelect.TagValues />\n * <MultiSelect.Input placeholder=\"Select items...\" />\n * </MultiSelect.Trigger>\n * <MultiSelect.Content>\n * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n * <MultiSelect.Item value=\"banana\">Banana</MultiSelect.Item>\n * </MultiSelect.Content>\n * </MultiSelect.Root>\n * ```\n */\nconst Item = forwardRef<ComponentRef<\"div\">, MultiSelectItemProps>(\n\t(\n\t\t{ asChild = false, children, className, focusOnHover = true, value, onClick, ...props },\n\t\tref,\n\t) => {\n\t\tconst lockedValuesRef = useContext(LockedValuesContext);\n\t\tconst isLocked = value != null && lockedValuesRef.current.includes(value);\n\n\t\treturn (\n\t\t\t<Primitive.ComboboxItem\n\t\t\t\tdata-slot=\"multi-select-item\"\n\t\t\t\tclassName={cx(\n\t\t\t\t\t\"relative mx-1 cursor-pointer rounded-md pl-2 pr-8 py-1.5 text-strong text-sm font-normal flex min-w-0 items-center gap-2\",\n\t\t\t\t\t\"[[role=option]+&]:mt-px\",\n\t\t\t\t\t\"data-active-item:bg-active-menu-item\",\n\t\t\t\t\t\"aria-disabled:opacity-50\",\n\t\t\t\t\t\"aria-selected:bg-selected-menu-item aria-selected:data-active-item:bg-active-selected-menu-item\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tfocusOnHover={focusOnHover}\n\t\t\t\tonClick={(event) => {\n\t\t\t\t\t// Prevent Ariakit from toggling off a locked value.\n\t\t\t\t\t// Ariakit checks event.defaultPrevented before executing its selection logic.\n\t\t\t\t\tif (isLocked) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tonClick?.(event);\n\t\t\t\t}}\n\t\t\t\tref={ref}\n\t\t\t\trender={\n\t\t\t\t\tasChild ? ({ ref, ...childProps }) => <Slot ref={ref} {...childProps} /> : undefined\n\t\t\t\t}\n\t\t\t\tresetValueOnSelect\n\t\t\t\tvalue={value}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t\t<Primitive.ComboboxItemCheck className=\"absolute right-2 flex h-3.5 w-3.5 items-center justify-center\">\n\t\t\t\t\t<Icon svg={<CheckIcon weight=\"bold\" />} className=\"size-4 text-accent-600\" />\n\t\t\t\t</Primitive.ComboboxItemCheck>\n\t\t\t</Primitive.ComboboxItem>\n\t\t);\n\t},\n);\nItem.displayName = \"MultiSelectItem\";\n\ntype MultiSelectGroupProps = Omit<Primitive.ComboboxGroupProps, \"render\"> & WithAsChild;\n\n/**\n * Renders a group for MultiSelect.Item elements.\n *\n * @see https://mantle.ngrok.com/components/multi-select#multiselectgroup\n *\n * @example\n * ```tsx\n * <MultiSelect.Root>\n * <MultiSelect.Trigger>\n * <MultiSelect.TagValues />\n * <MultiSelect.Input placeholder=\"Select items...\" />\n * </MultiSelect.Trigger>\n * <MultiSelect.Content>\n * <MultiSelect.Group>\n * <MultiSelect.GroupLabel>Fruits</MultiSelect.GroupLabel>\n * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n * <MultiSelect.Item value=\"banana\">Banana</MultiSelect.Item>\n * </MultiSelect.Group>\n * </MultiSelect.Content>\n * </MultiSelect.Root>\n * ```\n */\nconst Group = forwardRef<ComponentRef<\"div\">, MultiSelectGroupProps>(\n\t({ asChild = false, children, ...props }, ref) => {\n\t\treturn (\n\t\t\t<Primitive.ComboboxGroup\n\t\t\t\tdata-slot=\"multi-select-group\"\n\t\t\t\tclassName=\"mx-1\"\n\t\t\t\tref={ref}\n\t\t\t\trender={\n\t\t\t\t\tasChild ? ({ ref, ...childProps }) => <Slot ref={ref} {...childProps} /> : undefined\n\t\t\t\t}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Primitive.ComboboxGroup>\n\t\t);\n\t},\n);\nGroup.displayName = \"MultiSelectGroup\";\n\ntype MultiSelectGroupLabelProps = Omit<Primitive.ComboboxGroupLabelProps, \"render\"> & WithAsChild;\n\n/**\n * Renders a label in a multi-select group.\n *\n * @see https://mantle.ngrok.com/components/multi-select#multiselectgrouplabel\n *\n * @example\n * ```tsx\n * <MultiSelect.Root>\n * <MultiSelect.Trigger>\n * <MultiSelect.TagValues />\n * <MultiSelect.Input placeholder=\"Select items...\" />\n * </MultiSelect.Trigger>\n * <MultiSelect.Content>\n * <MultiSelect.Group>\n * <MultiSelect.GroupLabel>Fruits</MultiSelect.GroupLabel>\n * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n * </MultiSelect.Group>\n * </MultiSelect.Content>\n * </MultiSelect.Root>\n * ```\n */\nconst GroupLabel = forwardRef<ComponentRef<\"div\">, MultiSelectGroupLabelProps>(\n\t({ asChild = false, children, className, ...props }, ref) => {\n\t\treturn (\n\t\t\t<Primitive.ComboboxGroupLabel\n\t\t\t\tdata-slot=\"multi-select-group-label\"\n\t\t\t\tclassName={cx(\"text-muted px-2 py-1 text-xs font-medium\", className)}\n\t\t\t\tref={ref}\n\t\t\t\trender={\n\t\t\t\t\tasChild ? ({ ref, ...childProps }) => <Slot ref={ref} {...childProps} /> : undefined\n\t\t\t\t}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Primitive.ComboboxGroupLabel>\n\t\t);\n\t},\n);\nGroupLabel.displayName = \"MultiSelectGroupLabel\";\n\ntype MultiSelectGroupDescriptionProps = ComponentPropsWithoutRef<\"p\">;\n\n/**\n * Renders a description below a `MultiSelect.GroupLabel` inside a `MultiSelect.Group`.\n * Provides context about the group's purpose or constraints.\n *\n * @see https://mantle.ngrok.com/components/multi-select#multiselectgroupdescription\n *\n * @example\n * ```tsx\n * <MultiSelect.Root>\n * <MultiSelect.Trigger>\n * <MultiSelect.TagValues />\n * <MultiSelect.Input placeholder=\"Select regions...\" />\n * </MultiSelect.Trigger>\n * <MultiSelect.Content>\n * <MultiSelect.Group>\n * <MultiSelect.GroupLabel>Regional Aliases</MultiSelect.GroupLabel>\n * <MultiSelect.GroupDescription>\n * Include all points of presence that are geographically within the region.\n * </MultiSelect.GroupDescription>\n * <MultiSelect.Item value=\"global\">global</MultiSelect.Item>\n * </MultiSelect.Group>\n * </MultiSelect.Content>\n * </MultiSelect.Root>\n * ```\n */\nconst GroupDescription = forwardRef<HTMLParagraphElement, MultiSelectGroupDescriptionProps>(\n\t({ className, children, ...props }, ref) => {\n\t\treturn (\n\t\t\t<p\n\t\t\t\tdata-slot=\"multi-select-group-description\"\n\t\t\t\tclassName={cx(\"text-muted px-2 pb-1 text-xs\", className)}\n\t\t\t\tref={ref}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</p>\n\t\t);\n\t},\n);\nGroupDescription.displayName = \"MultiSelectGroupDescription\";\n\n/**\n * Renders a separator between MultiSelect.Items or MultiSelect.Groups.\n *\n * @see https://mantle.ngrok.com/components/multi-select#multiselectseparator\n *\n * @example\n * ```tsx\n * <MultiSelect.Root>\n * <MultiSelect.Trigger>\n * <MultiSelect.TagValues />\n * <MultiSelect.Input placeholder=\"Select items...\" />\n * </MultiSelect.Trigger>\n * <MultiSelect.Content>\n * <MultiSelect.Group>\n * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n * </MultiSelect.Group>\n * <MultiSelect.Separator />\n * <MultiSelect.Group>\n * <MultiSelect.Item value=\"carrot\">Carrot</MultiSelect.Item>\n * </MultiSelect.Group>\n * </MultiSelect.Content>\n * </MultiSelect.Root>\n * ```\n */\nconst MultiSelectSeparatorComponent = forwardRef<\n\tComponentRef<\"div\">,\n\tComponentPropsWithoutRef<typeof Separator>\n>(({ className, ...props }, ref) => (\n\t<Separator\n\t\tdata-slot=\"multi-select-separator\"\n\t\tref={ref}\n\t\tclassName={cx(\"my-1 w-auto\", className)}\n\t\t{...props}\n\t/>\n));\nMultiSelectSeparatorComponent.displayName = \"MultiSelectSeparator\";\n\ntype MultiSelectEmptyProps = ComponentPropsWithoutRef<\"div\">;\n\n/**\n * Renders a message when no items match the current filter.\n *\n * @see https://mantle.ngrok.com/components/multi-select#multiselectempty\n *\n * @example\n * ```tsx\n * <MultiSelect.Root>\n * <MultiSelect.Trigger>\n * <MultiSelect.TagValues />\n * <MultiSelect.Input placeholder=\"Select items...\" />\n * </MultiSelect.Trigger>\n * <MultiSelect.Content>\n * {matches.length === 0 && (\n * <MultiSelect.Empty>No results found</MultiSelect.Empty>\n * )}\n * </MultiSelect.Content>\n * </MultiSelect.Root>\n * ```\n */\nconst Empty = forwardRef<HTMLDivElement, MultiSelectEmptyProps>(\n\t({ className, children, ...props }, ref) => {\n\t\treturn (\n\t\t\t<div\n\t\t\t\tdata-slot=\"multi-select-empty\"\n\t\t\t\tclassName={cx(\"mx-1 text-muted px-2 py-6 text-center text-sm\", className)}\n\t\t\t\tref={ref}\n\t\t\t\trole=\"presentation\"\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t);\n\t},\n);\nEmpty.displayName = \"MultiSelectEmpty\";\n\ntype MultiSelectContentFooterProps = ComponentPropsWithoutRef<\"div\">;\n\n/**\n * Renders a sticky footer pinned to the bottom inside `MultiSelect.Content`,\n * with a separator border at the top.\n *\n * @see https://mantle.ngrok.com/components/multi-select#multiselectcontentfooter\n *\n * @example\n * ```tsx\n * <MultiSelect.Root>\n * <MultiSelect.Trigger>\n * <MultiSelect.TagValues />\n * <MultiSelect.Input placeholder=\"Select items...\" />\n * </MultiSelect.Trigger>\n * <MultiSelect.Content>\n * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n * <MultiSelect.ContentFooter>\n * <p>Upgrade to unlock more options.</p>\n * <Button>Upgrade</Button>\n * </MultiSelect.ContentFooter>\n * </MultiSelect.Content>\n * </MultiSelect.Root>\n * ```\n */\nconst ContentFooter = forwardRef<HTMLDivElement, MultiSelectContentFooterProps>(\n\t({ className, children, ...props }, ref) => {\n\t\treturn (\n\t\t\t<div\n\t\t\t\tref={ref}\n\t\t\t\tdata-slot=\"multi-select-content-footer\"\n\t\t\t\tdata-content-footer\n\t\t\t\tclassName={cx(\"bg-popover sticky bottom-0 border-t border-popover\", className)}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t);\n\t},\n);\nContentFooter.displayName = \"MultiSelectContentFooter\";\n\n/**\n * A multi-select combobox that allows users to select multiple values with\n * typeahead filtering. Selected values are displayed as removable tags.\n *\n * Built on top of Ariakit's Combobox primitives with full keyboard support\n * and WAI-ARIA compliance.\n *\n * Use MultiSelect when the user can choose multiple values from a list, with selected\n * items rendered as removable tags/chips. For single selection, use Combobox (with search)\n * or Select (without).\n *\n * @see https://mantle.ngrok.com/components/multi-select\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/combobox/\n * @see https://ariakit.org/components/combobox\n *\n * @example\n * Composition:\n * ```\n * MultiSelect.Root\n * ├── MultiSelect.Trigger\n * │ ├── MultiSelect.TagValues\n * │ └── MultiSelect.Input\n * └── MultiSelect.Content\n * ├── MultiSelect.Group\n * │ ├── MultiSelect.GroupLabel\n * │ ├── MultiSelect.GroupDescription\n * │ └── MultiSelect.Item\n * ├── MultiSelect.Separator\n * ├── MultiSelect.Empty\n * └── MultiSelect.ContentFooter\n * ```\n *\n * @example\n * ```tsx\n * <MultiSelect.Root>\n * <MultiSelect.Trigger>\n * <MultiSelect.TagValues />\n * <MultiSelect.Input placeholder=\"Select items...\" />\n * </MultiSelect.Trigger>\n * <MultiSelect.Content>\n * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n * <MultiSelect.Item value=\"banana\">Banana</MultiSelect.Item>\n * <MultiSelect.Item value=\"cherry\">Cherry</MultiSelect.Item>\n * </MultiSelect.Content>\n * </MultiSelect.Root>\n * ```\n */\nconst MultiSelect = {\n\t/**\n\t * Root component for a multi-select combobox. Provides state management for\n\t * selecting multiple values with typeahead filtering.\n\t *\n\t * Use MultiSelect when the user can choose multiple values from a list, with selected\n\t * items rendered as removable tags/chips. For single selection, use Combobox (with search)\n\t * or Select (without).\n\t *\n\t * @see https://mantle.ngrok.com/components/multi-select#multiselectroot\n\t *\n\t * @example\n\t * ```tsx\n\t * <MultiSelect.Root>\n\t * <MultiSelect.Trigger>\n\t * <MultiSelect.TagValues />\n\t * <MultiSelect.Input placeholder=\"Select items...\" />\n\t * </MultiSelect.Trigger>\n\t * <MultiSelect.Content>\n\t * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n\t * </MultiSelect.Content>\n\t * </MultiSelect.Root>\n\t * ```\n\t */\n\tRoot,\n\t/**\n\t * The trigger container for the multi-select. Wraps the tags and input\n\t * in a styled container.\n\t *\n\t * @see https://mantle.ngrok.com/components/multi-select#multiselecttrigger\n\t *\n\t * @example\n\t * ```tsx\n\t * <MultiSelect.Root>\n\t * <MultiSelect.Trigger>\n\t * <MultiSelect.TagValues />\n\t * <MultiSelect.Input placeholder=\"Select items...\" />\n\t * </MultiSelect.Trigger>\n\t * <MultiSelect.Content>\n\t * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n\t * </MultiSelect.Content>\n\t * </MultiSelect.Root>\n\t * ```\n\t */\n\tTrigger,\n\t/**\n\t * Renders the selected values as removable tags. Place this inside\n\t * `MultiSelect.Trigger`, followed by `MultiSelect.Input`.\n\t *\n\t * Use `lockedValues` to prevent specific tags from being removed. Locked tags\n\t * have their remove button disabled and shake when Backspace is pressed.\n\t *\n\t * @see https://mantle.ngrok.com/components/multi-select#multiselecttagvalues\n\t *\n\t * @example\n\t * ```tsx\n\t * <MultiSelect.Root>\n\t * <MultiSelect.Trigger>\n\t * <MultiSelect.TagValues lockedValues={[\"global\"]} />\n\t * <MultiSelect.Input placeholder=\"Select items...\" />\n\t * </MultiSelect.Trigger>\n\t * <MultiSelect.Content>\n\t * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n\t * </MultiSelect.Content>\n\t * </MultiSelect.Root>\n\t * ```\n\t *\n\t * @example\n\t * Custom tags via children render function — `locked` is forwarded via props.\n\t * ```tsx\n\t * <MultiSelect.Root>\n\t * <MultiSelect.Trigger>\n\t * <MultiSelect.TagValues lockedValues={[\"global\"]}>\n\t * {(props) => <MultiSelect.Tag key={props.value} {...props} />}\n\t * </MultiSelect.TagValues>\n\t * <MultiSelect.Input placeholder=\"Select items...\" />\n\t * </MultiSelect.Trigger>\n\t * <MultiSelect.Content>\n\t * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n\t * </MultiSelect.Content>\n\t * </MultiSelect.Root>\n\t * ```\n\t */\n\tTagValues,\n\t/**\n\t * The combobox input for filtering items. Place this inside\n\t * `MultiSelect.Trigger`, after `MultiSelect.TagValues`.\n\t *\n\t * @see https://mantle.ngrok.com/components/multi-select#multiselectinput\n\t *\n\t * @example\n\t * ```tsx\n\t * <MultiSelect.Root>\n\t * <MultiSelect.Trigger>\n\t * <MultiSelect.TagValues />\n\t * <MultiSelect.Input placeholder=\"Select items...\" />\n\t * </MultiSelect.Trigger>\n\t * <MultiSelect.Content>\n\t * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n\t * </MultiSelect.Content>\n\t * </MultiSelect.Root>\n\t * ```\n\t */\n\tInput,\n\t/**\n\t * The default tag rendered inside `MultiSelect.TagValues` for each selected value.\n\t * Displays the value label with a remove button and keyboard navigation support.\n\t *\n\t * @see https://mantle.ngrok.com/components/multi-select#multiselecttag\n\t *\n\t * @example\n\t * ```tsx\n\t * <MultiSelect.Root>\n\t * <MultiSelect.Trigger>\n\t * <MultiSelect.TagValues>\n\t * {(props) => <MultiSelect.Tag key={props.value} {...props} />}\n\t * </MultiSelect.TagValues>\n\t * <MultiSelect.Input placeholder=\"Select items...\" />\n\t * </MultiSelect.Trigger>\n\t * <MultiSelect.Content>\n\t * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n\t * </MultiSelect.Content>\n\t * </MultiSelect.Root>\n\t * ```\n\t */\n\tTag,\n\t/**\n\t * Renders a popover that contains multi-select content.\n\t *\n\t * @see https://mantle.ngrok.com/components/multi-select#multiselectcontent\n\t *\n\t * @example\n\t * ```tsx\n\t * <MultiSelect.Root>\n\t * <MultiSelect.Trigger>\n\t * <MultiSelect.TagValues />\n\t * <MultiSelect.Input placeholder=\"Select items...\" />\n\t * </MultiSelect.Trigger>\n\t * <MultiSelect.Content>\n\t * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n\t * <MultiSelect.Item value=\"banana\">Banana</MultiSelect.Item>\n\t * </MultiSelect.Content>\n\t * </MultiSelect.Root>\n\t * ```\n\t */\n\tContent,\n\t/**\n\t * Renders a sticky footer pinned to the bottom inside `MultiSelect.Content`,\n\t * with a separator border at the top.\n\t *\n\t * @see https://mantle.ngrok.com/components/multi-select#multiselectcontentfooter\n\t *\n\t * @example\n\t * ```tsx\n\t * <MultiSelect.Root>\n\t * <MultiSelect.Trigger>\n\t * <MultiSelect.TagValues />\n\t * <MultiSelect.Input placeholder=\"Select items...\" />\n\t * </MultiSelect.Trigger>\n\t * <MultiSelect.Content>\n\t * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n\t * <MultiSelect.ContentFooter>\n\t * <p>Upgrade to unlock more options.</p>\n\t * </MultiSelect.ContentFooter>\n\t * </MultiSelect.Content>\n\t * </MultiSelect.Root>\n\t * ```\n\t */\n\tContentFooter,\n\t/**\n\t * Renders a selectable item with a checkbox indicator inside a `MultiSelect.Content`.\n\t *\n\t * @see https://mantle.ngrok.com/components/multi-select#multiselectitem\n\t *\n\t * @example\n\t * ```tsx\n\t * <MultiSelect.Root>\n\t * <MultiSelect.Trigger>\n\t * <MultiSelect.TagValues />\n\t * <MultiSelect.Input placeholder=\"Select items...\" />\n\t * </MultiSelect.Trigger>\n\t * <MultiSelect.Content>\n\t * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n\t * <MultiSelect.Item value=\"banana\">Banana</MultiSelect.Item>\n\t * </MultiSelect.Content>\n\t * </MultiSelect.Root>\n\t * ```\n\t */\n\tItem,\n\t/**\n\t * Renders a group for MultiSelect.Item elements.\n\t *\n\t * @see https://mantle.ngrok.com/components/multi-select#multiselectgroup\n\t *\n\t * @example\n\t * ```tsx\n\t * <MultiSelect.Root>\n\t * <MultiSelect.Trigger>\n\t * <MultiSelect.TagValues />\n\t * <MultiSelect.Input placeholder=\"Select items...\" />\n\t * </MultiSelect.Trigger>\n\t * <MultiSelect.Content>\n\t * <MultiSelect.Group>\n\t * <MultiSelect.GroupLabel>Fruits</MultiSelect.GroupLabel>\n\t * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n\t * </MultiSelect.Group>\n\t * </MultiSelect.Content>\n\t * </MultiSelect.Root>\n\t * ```\n\t */\n\tGroup,\n\t/**\n\t * Renders a label in a multi-select group.\n\t *\n\t * @see https://mantle.ngrok.com/components/multi-select#multiselectgrouplabel\n\t *\n\t * @example\n\t * ```tsx\n\t * <MultiSelect.Root>\n\t * <MultiSelect.Trigger>\n\t * <MultiSelect.TagValues />\n\t * <MultiSelect.Input placeholder=\"Select items...\" />\n\t * </MultiSelect.Trigger>\n\t * <MultiSelect.Content>\n\t * <MultiSelect.Group>\n\t * <MultiSelect.GroupLabel>Fruits</MultiSelect.GroupLabel>\n\t * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n\t * </MultiSelect.Group>\n\t * </MultiSelect.Content>\n\t * </MultiSelect.Root>\n\t * ```\n\t */\n\tGroupLabel,\n\t/**\n\t * Renders a description below a `MultiSelect.GroupLabel` inside a `MultiSelect.Group`.\n\t *\n\t * @see https://mantle.ngrok.com/components/multi-select#multiselectgroupdescription\n\t *\n\t * @example\n\t * ```tsx\n\t * <MultiSelect.Root>\n\t * <MultiSelect.Trigger>\n\t * <MultiSelect.TagValues />\n\t * <MultiSelect.Input placeholder=\"Select regions...\" />\n\t * </MultiSelect.Trigger>\n\t * <MultiSelect.Content>\n\t * <MultiSelect.Group>\n\t * <MultiSelect.GroupLabel>Regional Aliases</MultiSelect.GroupLabel>\n\t * <MultiSelect.GroupDescription>\n\t * Include all points of presence within the region.\n\t * </MultiSelect.GroupDescription>\n\t * <MultiSelect.Item value=\"global\">global</MultiSelect.Item>\n\t * </MultiSelect.Group>\n\t * </MultiSelect.Content>\n\t * </MultiSelect.Root>\n\t * ```\n\t */\n\tGroupDescription,\n\t/**\n\t * Renders a separator between items or groups.\n\t *\n\t * @see https://mantle.ngrok.com/components/multi-select#multiselectseparator\n\t *\n\t * @example\n\t * ```tsx\n\t * <MultiSelect.Root>\n\t * <MultiSelect.Trigger>\n\t * <MultiSelect.TagValues />\n\t * <MultiSelect.Input placeholder=\"Select items...\" />\n\t * </MultiSelect.Trigger>\n\t * <MultiSelect.Content>\n\t * <MultiSelect.Group>\n\t * <MultiSelect.Item value=\"apple\">Apple</MultiSelect.Item>\n\t * </MultiSelect.Group>\n\t * <MultiSelect.Separator />\n\t * <MultiSelect.Group>\n\t * <MultiSelect.Item value=\"carrot\">Carrot</MultiSelect.Item>\n\t * </MultiSelect.Group>\n\t * </MultiSelect.Content>\n\t * </MultiSelect.Root>\n\t * ```\n\t */\n\tSeparator: MultiSelectSeparatorComponent,\n\t/**\n\t * Renders a message when no items match the current filter.\n\t *\n\t * @see https://mantle.ngrok.com/components/multi-select#multiselectempty\n\t *\n\t * @example\n\t * ```tsx\n\t * <MultiSelect.Root>\n\t * <MultiSelect.Trigger>\n\t * <MultiSelect.TagValues />\n\t * <MultiSelect.Input placeholder=\"Select items...\" />\n\t * </MultiSelect.Trigger>\n\t * <MultiSelect.Content>\n\t * {matches.length === 0 && (\n\t * <MultiSelect.Empty>No results found</MultiSelect.Empty>\n\t * )}\n\t * </MultiSelect.Content>\n\t * </MultiSelect.Root>\n\t * ```\n\t */\n\tEmpty,\n} as const;\n\nexport {\n\t//,\n\tMultiSelect,\n};\n\n/**\n * Shakes an element left-right to signal that an action was blocked\n * (e.g. pressing Backspace/Delete on a locked tag). No-ops when the user\n * has enabled reduced motion in their OS/browser accessibility settings.\n */\nfunction shakeElement(element: HTMLElement): void {\n\t// Skip the animation when the user has opted into reduced motion.\n\t// Called from event handlers only, so reading the media query imperatively\n\t// is safe and gives the freshest value without any hook plumbing.\n\tif (getPrefersReducedMotion()) {\n\t\treturn;\n\t}\n\n\telement.animate(\n\t\t[\n\t\t\t{ transform: \"translateX(0)\" },\n\t\t\t{ transform: \"translateX(-4px)\" },\n\t\t\t{ transform: \"translateX(4px)\" },\n\t\t\t{ transform: \"translateX(-4px)\" },\n\t\t\t{ transform: \"translateX(4px)\" },\n\t\t\t{ transform: \"translateX(0)\" },\n\t\t],\n\t\t{ duration: 300, easing: \"ease-in-out\" },\n\t);\n}\n"],"mappings":"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"}
|
package/dist/otp-input.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"otp-input.js","names":["AsChildSlot"],"sources":["../src/components/otp-input/otp-input.tsx"],"sourcesContent":["\"use client\";\n\nimport { MinusIcon } from \"@phosphor-icons/react/Minus\";\nimport { OTPInput, OTPInputContext } from \"input-otp\";\nimport type { ComponentProps, ComponentRef, ReactNode } from \"react\";\nimport { forwardRef, useContext } from \"react\";\nimport type { WithAsChild } from \"../../types/as-child.js\";\nimport { $cssProperties } from \"../../types/index.js\";\nimport { cx } from \"../../utils/cx/cx.js\";\nimport { FieldControlContext } from \"../field/field-context.js\";\nimport { parseValidation, useFieldValidation } from \"../field/validation.js\";\nimport type { Validation, WithValidation } from \"../field/validation.js\";\nimport { Slot as AsChildSlot } from \"../slot/index.js\";\n\ntype OtpState = \"idle\" | \"caret\" | \"range\" | \"all\";\n\n/**\n * The color token name (`danger` / `success` / `warning`) that backs each\n * validation value. The `Validation` vocabulary (`\"error\"` / `\"success\"` /\n * `\"warning\"`) doesn't exactly match the color-token vocabulary — the\n * `error` validation maps to the `danger` color hue.\n */\ntype ValidationHue = \"danger\" | \"success\" | \"warning\";\n\nconst validationHues = {\n\terror: \"danger\",\n\tsuccess: \"success\",\n\twarning: \"warning\",\n} as const satisfies Record<Exclude<Validation, false>, ValidationHue>;\n\nconst validationBorderColor = <T extends ValidationHue = ValidationHue>(hue: T) =>\n\t`var(--color-${hue}-600)`;\n\nconst validationRingColor = <T extends ValidationHue = ValidationHue>(hue: T) =>\n\t`var(--ring-color-focus-${hue})`;\n\n/**\n * Map the count of active slots to a discrete `data-otp-state` value used by\n * descendant CSS selectors. Split out from the rendering component so the\n * decision tree reads as a flat `if`/`else` chain rather than a nested\n * ternary.\n */\nconst computeOtpState = ({\n\ttotalActive,\n\ttotal,\n}: {\n\ttotalActive: number;\n\ttotal: number;\n}): OtpState => {\n\tif (totalActive === 0) {\n\t\treturn \"idle\";\n\t}\n\tif (totalActive === 1) {\n\t\treturn \"caret\";\n\t}\n\tif (totalActive === total) {\n\t\treturn \"all\";\n\t}\n\treturn \"range\";\n};\n\n/**\n * Bridge component that lives inside `<OTPInput>` (so it can read\n * `OTPInputContext`) and exposes the current selection state as a DOM data\n * attribute. Descendant `OtpInput.Group` / `OtpInput.Slot` parts read this\n * via Tailwind's `group-data-*` selector, so all conditional styling lives\n * in CSS — no React context.\n *\n * `data-otp-state` is one of:\n * - `\"idle\"` — no slot active (input not focused)\n * - `\"caret\"` — exactly one slot active (typing caret)\n * - `\"range\"` — multiple but not all slots active (partial selection)\n * - `\"all\"` — every slot active (cmd+a / select-all)\n */\nconst MantleOtpBridge = ({\n\tchildren,\n\tvalidation,\n}: {\n\tchildren: ReactNode;\n\tvalidation?: Validation;\n}) => {\n\tconst inputOtpContext = useContext(OTPInputContext);\n\tconst total = inputOtpContext.slots.length;\n\tconst totalActive = inputOtpContext.slots.reduce(\n\t\t(count, slot) => count + (slot.isActive ? 1 : 0),\n\t\t0,\n\t);\n\tconst otpState = computeOtpState({ totalActive, total });\n\n\t// Map the validation hue to two CSS custom properties — descendant\n\t// slot/group classes reference these vars instead of having one\n\t// branch per validation value. When no validation is set, the vars\n\t// are left undefined and the validation utilities (gated on\n\t// `group-data-validation`) don't apply.\n\tconst hue = validation ? validationHues[validation] : undefined;\n\tconst validationStyle = hue\n\t\t? $cssProperties({\n\t\t\t\t\"--otp-validation-border\": validationBorderColor(hue),\n\t\t\t\t\"--otp-validation-ring\": validationRingColor(hue),\n\t\t\t})\n\t\t: undefined;\n\n\t// `display: contents` keeps this element in the DOM tree (so `group/`\n\t// ancestor selectors resolve) without producing a layout box.\n\treturn (\n\t\t<div\n\t\t\tclassName=\"group/otp contents\"\n\t\t\tdata-otp-state={otpState}\n\t\t\tdata-validation={validation || undefined}\n\t\t\tstyle={validationStyle}\n\t\t>\n\t\t\t{children}\n\t\t</div>\n\t);\n};\n\n// Drop the `render` / `children?: never` branch of input-otp's discriminated\n// union — `OtpInput.Root` always wraps its children in `MantleOtpBridge`,\n// so consumers compose with `OtpInput.Group` / `OtpInput.Slot` children\n// rather than a render prop.\ntype OtpInputRootProps = Omit<ComponentProps<typeof OTPInput>, \"render\" | \"children\"> &\n\tWithValidation & {\n\t\tchildren?: ReactNode;\n\t};\n\n/**\n * The root of the OTP input. Renders an accessible single hidden input that\n * captures keystrokes, paste events, and autofill, and exposes per-slot state\n * (active, char, fake caret) to descendant `OtpInput.Slot` parts via context.\n *\n * Wraps the `input-otp` library by Guilherme Rodz.\n *\n * Pass `validation=\"error\"` (or `\"success\"` / `\"warning\"`) to recolor each\n * group's outer borders and the active focus ring with the matching validation hue.\n * `validation=\"error\"` also sets `aria-invalid` on the underlying input so\n * assistive tech announces the failure state.\n *\n * When composing with `Field.Item`, wrap `OtpInput.Root` in `Field.Control`.\n * `Field.Control` flows the generated `id`, `aria-invalid`, `aria-describedby`,\n * and `aria-errormessage` through to the underlying focusable input via\n * `FieldControlContext`.\n *\n * @see https://mantle.ngrok.com/components/otp-input\n *\n * @example\n * ```tsx\n * <OtpInput.Root maxLength={6}>\n * <OtpInput.Group>\n * <OtpInput.Slot index={0} />\n * <OtpInput.Slot index={1} />\n * <OtpInput.Slot index={2} />\n * </OtpInput.Group>\n * <OtpInput.Separator />\n * <OtpInput.Group>\n * <OtpInput.Slot index={3} />\n * <OtpInput.Slot index={4} />\n * <OtpInput.Slot index={5} />\n * </OtpInput.Group>\n * </OtpInput.Root>\n * ```\n */\n// `OtpInput.Root` does not support `asChild`: the underlying `OTPInput`\n// owns its hidden `<input>` and its render contract — swapping the element\n// would break input-otp's internal focus and selection management.\nconst Root = forwardRef<ComponentRef<typeof OTPInput>, OtpInputRootProps>(\n\t(\n\t\t{\n\t\t\t\"aria-invalid\": ariaInvalid,\n\t\t\tchildren,\n\t\t\tclassName,\n\t\t\tcontainerClassName,\n\t\t\tvalidation: _validation,\n\t\t\t...props\n\t\t},\n\t\tref,\n\t) => {\n\t\tconst fieldValidation = useFieldValidation();\n\t\tconst fieldControl = useContext(FieldControlContext);\n\t\tconst { ariaInvalid: resolvedAriaInvalid, validation } = parseValidation({\n\t\t\t\"aria-invalid\": ariaInvalid,\n\t\t\tdefaultAriaInvalid: false,\n\t\t\tvalidation: _validation ?? fieldValidation,\n\t\t});\n\n\t\treturn (\n\t\t\t<OTPInput\n\t\t\t\tref={ref}\n\t\t\t\taria-invalid={resolvedAriaInvalid}\n\t\t\t\tdata-slot=\"otp-input\"\n\t\t\t\tcontainerClassName={cx(\n\t\t\t\t\t\"flex items-center gap-2 has-disabled:opacity-50\",\n\t\t\t\t\tcontainerClassName,\n\t\t\t\t)}\n\t\t\t\tclassName={cx(\"disabled:cursor-not-allowed\", className)}\n\t\t\t\t{...props}\n\t\t\t\t{...(fieldControl\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t\"aria-describedby\": fieldControl[\"aria-describedby\"],\n\t\t\t\t\t\t\t\"aria-errormessage\": fieldControl[\"aria-errormessage\"],\n\t\t\t\t\t\t\tid: fieldControl.id,\n\t\t\t\t\t\t\tname: fieldControl.name,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined)}\n\t\t\t>\n\t\t\t\t<MantleOtpBridge validation={validation}>{children}</MantleOtpBridge>\n\t\t\t</OTPInput>\n\t\t);\n\t},\n);\nRoot.displayName = \"OtpInput\";\n\ntype OtpInputGroupProps = ComponentProps<\"div\"> & WithAsChild;\n\n/**\n * Groups one or more `OtpInput.Slot` parts into a visually-connected segment.\n * Slots inside a group share rounded corners on the outer edges and join with\n * shared borders between adjacent slots.\n *\n * @see https://mantle.ngrok.com/components/otp-input\n *\n * @example\n * ```tsx\n * <OtpInput.Root maxLength={6}>\n * <OtpInput.Group>\n * <OtpInput.Slot index={0} />\n * <OtpInput.Slot index={1} />\n * <OtpInput.Slot index={2} />\n * </OtpInput.Group>\n * <OtpInput.Separator />\n * <OtpInput.Group>\n * <OtpInput.Slot index={3} />\n * <OtpInput.Slot index={4} />\n * <OtpInput.Slot index={5} />\n * </OtpInput.Group>\n * </OtpInput.Root>\n * ```\n */\nconst Group = forwardRef<HTMLDivElement, OtpInputGroupProps>(\n\t({ asChild, children, className, ...props }, ref) => {\n\t\tconst Comp = asChild ? AsChildSlot : \"div\";\n\n\t\treturn (\n\t\t\t<Comp\n\t\t\t\tref={ref}\n\t\t\t\tdata-slot=\"otp-input-group\"\n\t\t\t\tclassName={cx(\n\t\t\t\t\t\"relative flex items-center rounded-md\",\n\t\t\t\t\t// A \"range\" selection within this group means two or more\n\t\t\t\t\t// slots are simultaneously active. CSS `:has()` with the\n\t\t\t\t\t// general sibling combinator catches that without us\n\t\t\t\t\t// having to count: if any active slot is preceded by\n\t\t\t\t\t// another active slot at the same nesting level, the\n\t\t\t\t\t// group has at least 2 actives → draw the ring.\n\t\t\t\t\t\"has-[[data-active]~[data-active]]:ring-focus-accent has-[[data-active]~[data-active]]:ring-4\",\n\t\t\t\t\t// Validation override for the group-level range/all ring.\n\t\t\t\t\t// `--otp-validation-ring` is set on the bridge based on\n\t\t\t\t\t// the validation value, so a single class covers\n\t\t\t\t\t// error/success/warning instead of one per hue.\n\t\t\t\t\t\"group-data-validation/otp:has-[[data-active]~[data-active]]:ring-(--otp-validation-ring)\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Comp>\n\t\t);\n\t},\n);\nGroup.displayName = \"OtpInputGroup\";\n\ntype OtpInputSlotProps = ComponentProps<\"div\"> & {\n\t/**\n\t * The zero-based index of the character slot to render. Must be a valid\n\t * index within the parent `OtpInput.Root`'s `maxLength`.\n\t */\n\tindex: number;\n};\n\n/**\n * Renders a single character slot for the OTP input. Reads its display state\n * (the typed character, active/focused state, and fake caret position) from\n * the nearest `OtpInput.Root` via context — so this part must always be\n * rendered inside an `OtpInput.Root`.\n *\n * @see https://mantle.ngrok.com/components/otp-input\n *\n * @example\n * ```tsx\n * <OtpInput.Root maxLength={6}>\n * <OtpInput.Group>\n * <OtpInput.Slot index={0} />\n * <OtpInput.Slot index={1} />\n * <OtpInput.Slot index={2} />\n * </OtpInput.Group>\n * <OtpInput.Separator />\n * <OtpInput.Group>\n * <OtpInput.Slot index={3} />\n * <OtpInput.Slot index={4} />\n * <OtpInput.Slot index={5} />\n * </OtpInput.Group>\n * </OtpInput.Root>\n * ```\n */\n// `OtpInput.Slot` does not support `asChild`: the slot reads context-driven\n// state (char, fake caret, active) from `OTPInputContext` and renders that\n// state into a fixed visual structure. Letting consumers swap the element\n// would lose the caret overlay and the active-ring focus styling.\nconst OtpInputSlotImpl = forwardRef<HTMLDivElement, OtpInputSlotProps>(\n\t({ className, index, ...props }, ref) => {\n\t\tconst context = useContext(OTPInputContext);\n\t\tconst slot = context.slots[index];\n\t\tconst char = slot?.char ?? null;\n\t\tconst hasFakeCaret = slot?.hasFakeCaret ?? false;\n\t\tconst isActive = slot?.isActive ?? false;\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\tref={ref}\n\t\t\t\tdata-slot=\"otp-input-slot\"\n\t\t\t\tdata-active={isActive ? \"\" : undefined}\n\t\t\t\tclassName={cx(\n\t\t\t\t\t\"border-form bg-form text-strong relative flex h-10 w-10 items-center justify-center border-y border-r text-sm shadow-sm outline-hidden transition-all duration-150 ease-out\",\n\t\t\t\t\t\"first:rounded-l-md first:border-l last:rounded-r-md\",\n\t\t\t\t\t// When this slot is immediately followed by the caret\n\t\t\t\t\t// slot, hide our `border-r` so the active slot's\n\t\t\t\t\t// `border-l` is the only line at the boundary — without\n\t\t\t\t\t// this, the two adjacent 1px borders read as a doubled\n\t\t\t\t\t// edge. We use an arbitrary `&:has(+ ...)` variant\n\t\t\t\t\t// because Tailwind's `has-[...]` shorthand doesn't\n\t\t\t\t\t// parse the nested bracketed attribute selector here.\n\t\t\t\t\t\"[&:has(+[data-active])]:group-data-[otp-state=caret]/otp:border-r-transparent\",\n\t\t\t\t\t// Per-slot ring renders only in `caret` state (single\n\t\t\t\t\t// active slot). When more than one slot is active, the\n\t\t\t\t\t// surrounding `OtpInput.Group` draws a single ring\n\t\t\t\t\t// around the whole group — see Group's `:has()` rule.\n\t\t\t\t\t// We also recolor the slot's own borders to accent and\n\t\t\t\t\t// fill in `border-l` (groups normally only render\n\t\t\t\t\t// `border-l` on `:first-child`), so the slot reads as\n\t\t\t\t\t// one cohesive highlighted box rather than a ring with\n\t\t\t\t\t// a gray box inside.\n\t\t\t\t\t\"data-active:group-data-[otp-state=caret]/otp:border-accent-600\",\n\t\t\t\t\t\"data-active:group-data-[otp-state=caret]/otp:border-l\",\n\t\t\t\t\t\"data-active:group-data-[otp-state=caret]/otp:ring-focus-accent\",\n\t\t\t\t\t\"data-active:group-data-[otp-state=caret]/otp:z-20\",\n\t\t\t\t\t\"data-active:group-data-[otp-state=caret]/otp:ring-4\",\n\t\t\t\t\t// Select-all: tint *every* border on the slot accent.\n\t\t\t\t\t// Tinting only the outside edges leaves the internal\n\t\t\t\t\t// vertical divider (gray `border-r`) meeting the\n\t\t\t\t\t// accent top/bottom borders at the corner, producing a\n\t\t\t\t\t// visible 1px miter spike. Coloring all borders the\n\t\t\t\t\t// same accent-600 hue makes the corner blend\n\t\t\t\t\t// seamlessly while still keeping the slot grid\n\t\t\t\t\t// readable at full opacity.\n\t\t\t\t\t\"group-data-[otp-state=all]/otp:border-accent-600\",\n\t\t\t\t\t// Validation overrides. Only the *outer* edges of the\n\t\t\t\t\t// group are tinted (top + bottom on every slot, left on\n\t\t\t\t\t// the first slot, right on the last slot) so adjacent\n\t\t\t\t\t// slots still join with a neutral divider — matching how\n\t\t\t\t\t// `Input` tints the container border, not the internal\n\t\t\t\t\t// elements. The all-state and caret-active overrides\n\t\t\t\t\t// still recolor every border so a fully-active slot or\n\t\t\t\t\t// select-all reads as a solid tinted box. The bridge\n\t\t\t\t\t// sets `--otp-validation-{border,ring}` per validation\n\t\t\t\t\t// value, so a single set of classes covers\n\t\t\t\t\t// error/success/warning.\n\t\t\t\t\t\"group-data-validation/otp:border-y-(--otp-validation-border)\",\n\t\t\t\t\t\"group-data-validation/otp:first:border-l-(--otp-validation-border)\",\n\t\t\t\t\t\"group-data-validation/otp:last:border-r-(--otp-validation-border)\",\n\t\t\t\t\t\"group-data-validation/otp:data-active:group-data-[otp-state=caret]/otp:border-(--otp-validation-border)\",\n\t\t\t\t\t\"group-data-validation/otp:data-active:group-data-[otp-state=caret]/otp:ring-(--otp-validation-ring)\",\n\t\t\t\t\t\"group-data-validation/otp:group-data-[otp-state=all]/otp:border-(--otp-validation-border)\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{char}\n\t\t\t\t{hasFakeCaret && (\n\t\t\t\t\t<div className=\"pointer-events-none absolute inset-0 flex items-center justify-center\">\n\t\t\t\t\t\t<div className=\"bg-strong h-4 w-px animate-pulse\" />\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t);\n\t},\n);\nOtpInputSlotImpl.displayName = \"OtpInputSlot\";\n\ntype OtpInputSeparatorProps = ComponentProps<\"div\"> &\n\tWithAsChild & {\n\t\t/**\n\t\t * If `true`, the separator will be rendered with `role=\"separator\"` so\n\t\t * assistive tech announces it as a divider between OTP groups.\n\t\t * If `false`, the separator is purely decorative and is removed from\n\t\t * the accessibility tree — preferred inside an OTP control where the\n\t\t * minus icon is just visual chrome between slot groups.\n\t\t *\n\t\t * @default false\n\t\t */\n\t\tsemantic?: boolean;\n\t};\n\n/**\n * A visual separator between two `OtpInput.Group` segments. Renders a minus\n * icon by default; pass `children` to override the visual.\n *\n * @see https://mantle.ngrok.com/components/otp-input\n *\n * @example\n * ```tsx\n * <OtpInput.Root maxLength={6}>\n * <OtpInput.Group>\n * <OtpInput.Slot index={0} />\n * <OtpInput.Slot index={1} />\n * <OtpInput.Slot index={2} />\n * </OtpInput.Group>\n * <OtpInput.Separator />\n * <OtpInput.Group>\n * <OtpInput.Slot index={3} />\n * <OtpInput.Slot index={4} />\n * <OtpInput.Slot index={5} />\n * </OtpInput.Group>\n * </OtpInput.Root>\n * ```\n */\nconst Separator = forwardRef<HTMLDivElement, OtpInputSeparatorProps>(\n\t({ asChild, children, className, semantic = false, ...props }, ref) => {\n\t\tconst Comp = asChild ? AsChildSlot : \"div\";\n\t\tconst semanticProps = semantic ? { role: \"separator\" } : { \"aria-hidden\": true, role: \"none\" };\n\n\t\treturn (\n\t\t\t<Comp\n\t\t\t\tref={ref}\n\t\t\t\tdata-slot=\"otp-input-separator\"\n\t\t\t\tclassName={cx(\"text-muted flex items-center\", className)}\n\t\t\t\t{...semanticProps}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children ?? <MinusIcon weight=\"bold\" />}\n\t\t\t</Comp>\n\t\t);\n\t},\n);\nSeparator.displayName = \"OtpInputSeparator\";\n\n/**\n * Compound component for capturing one-time passcodes (OTP). Combines a\n * single hidden input (handling paste, autofill, and IME) with a row of\n * styled character slots.\n *\n * @see https://mantle.ngrok.com/components/otp-input\n *\n * @example\n * Composition:\n * ```\n * OtpInput.Root\n * ├── OtpInput.Group\n * │ └── OtpInput.Slot\n * ├── OtpInput.Separator\n * └── OtpInput.Group\n * └── OtpInput.Slot\n * ```\n *\n * @example\n * ```tsx\n * <OtpInput.Root maxLength={6}>\n * <OtpInput.Group>\n * <OtpInput.Slot index={0} />\n * <OtpInput.Slot index={1} />\n * <OtpInput.Slot index={2} />\n * </OtpInput.Group>\n * <OtpInput.Separator />\n * <OtpInput.Group>\n * <OtpInput.Slot index={3} />\n * <OtpInput.Slot index={4} />\n * <OtpInput.Slot index={5} />\n * </OtpInput.Group>\n * </OtpInput.Root>\n * ```\n */\nconst OtpInput = {\n\t/**\n\t * The root of the OTP input. Wraps the hidden input that captures\n\t * keystrokes, paste, and autofill, and provides per-slot state to\n\t * descendant `OtpInput.Slot` parts.\n\t *\n\t * @see https://mantle.ngrok.com/components/otp-input\n\t *\n\t * @example\n\t * ```tsx\n\t * <OtpInput.Root maxLength={6}>\n\t * <OtpInput.Group>\n\t * <OtpInput.Slot index={0} />\n\t * <OtpInput.Slot index={1} />\n\t * <OtpInput.Slot index={2} />\n\t * </OtpInput.Group>\n\t * <OtpInput.Separator />\n\t * <OtpInput.Group>\n\t * <OtpInput.Slot index={3} />\n\t * <OtpInput.Slot index={4} />\n\t * <OtpInput.Slot index={5} />\n\t * </OtpInput.Group>\n\t * </OtpInput.Root>\n\t * ```\n\t */\n\tRoot,\n\t/**\n\t * Groups one or more `OtpInput.Slot` parts into a visually-connected\n\t * segment with shared rounded corners and joined borders.\n\t *\n\t * @see https://mantle.ngrok.com/components/otp-input\n\t *\n\t * @example\n\t * ```tsx\n\t * <OtpInput.Root maxLength={6}>\n\t * <OtpInput.Group>\n\t * <OtpInput.Slot index={0} />\n\t * <OtpInput.Slot index={1} />\n\t * <OtpInput.Slot index={2} />\n\t * </OtpInput.Group>\n\t * <OtpInput.Separator />\n\t * <OtpInput.Group>\n\t * <OtpInput.Slot index={3} />\n\t * <OtpInput.Slot index={4} />\n\t * <OtpInput.Slot index={5} />\n\t * </OtpInput.Group>\n\t * </OtpInput.Root>\n\t * ```\n\t */\n\tGroup,\n\t/**\n\t * A single character slot. Must be rendered inside an `OtpInput.Root`.\n\t * Reads its character, active state, and fake caret position from the\n\t * root via context.\n\t *\n\t * @see https://mantle.ngrok.com/components/otp-input\n\t *\n\t * @example\n\t * ```tsx\n\t * <OtpInput.Root maxLength={6}>\n\t * <OtpInput.Group>\n\t * <OtpInput.Slot index={0} />\n\t * <OtpInput.Slot index={1} />\n\t * <OtpInput.Slot index={2} />\n\t * </OtpInput.Group>\n\t * <OtpInput.Separator />\n\t * <OtpInput.Group>\n\t * <OtpInput.Slot index={3} />\n\t * <OtpInput.Slot index={4} />\n\t * <OtpInput.Slot index={5} />\n\t * </OtpInput.Group>\n\t * </OtpInput.Root>\n\t * ```\n\t */\n\tSlot: OtpInputSlotImpl,\n\t/**\n\t * A visual separator between two `OtpInput.Group` segments. Renders a\n\t * minus icon by default; pass `children` to override.\n\t *\n\t * @see https://mantle.ngrok.com/components/otp-input\n\t *\n\t * @example\n\t * ```tsx\n\t * <OtpInput.Root maxLength={6}>\n\t * <OtpInput.Group>\n\t * <OtpInput.Slot index={0} />\n\t * <OtpInput.Slot index={1} />\n\t * <OtpInput.Slot index={2} />\n\t * </OtpInput.Group>\n\t * <OtpInput.Separator />\n\t * <OtpInput.Group>\n\t * <OtpInput.Slot index={3} />\n\t * <OtpInput.Slot index={4} />\n\t * <OtpInput.Slot index={5} />\n\t * </OtpInput.Group>\n\t * </OtpInput.Root>\n\t * ```\n\t */\n\tSeparator,\n} as const;\n\nexport {\n\t//,\n\tOtpInput,\n};\n\nexport {\n\t//,\n\tREGEXP_ONLY_CHARS,\n\tREGEXP_ONLY_DIGITS,\n\tREGEXP_ONLY_DIGITS_AND_CHARS,\n} from \"input-otp\";\n"],"mappings":"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"}
|
package/dist/pagination.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.js","names":[],"sources":["../src/components/pagination/cursor-pagination.tsx","../src/components/pagination/use-offset-pagination.tsx"],"sourcesContent":["\"use client\";\n\nimport { CaretLeftIcon } from \"@phosphor-icons/react/CaretLeft\";\nimport { CaretRightIcon } from \"@phosphor-icons/react/CaretRight\";\nimport {\n\ttype ComponentProps,\n\ttype ComponentRef,\n\tcreateContext,\n\tforwardRef,\n\tuseContext,\n\tuseMemo,\n\tuseState,\n} from \"react\";\nimport invariant from \"tiny-invariant\";\nimport type { WithAsChild } from \"../../types/as-child.js\";\nimport { cx } from \"../../utils/cx/cx.js\";\nimport { ButtonGroup, IconButton } from \"../button/index.js\";\nimport { Select } from \"../select/select.js\";\nimport { Separator } from \"../separator/separator.js\";\nimport { Slot } from \"../slot/index.js\";\n\ntype CursorPaginationContextValue = {\n\t/**\n\t * The default number of items per page.\n\t */\n\tdefaultPageSize: number;\n\t/**\n\t * The current number of items per page.\n\t */\n\tpageSize: number;\n\t/**\n\t * A function to set the number of items per page.\n\t */\n\tsetPageSize: (value: number) => void;\n};\n\nconst CursorPaginationContext = createContext<CursorPaginationContextValue | undefined>(undefined);\n\ntype CursorPaginationProps = ComponentProps<\"div\"> & {\n\t/**\n\t * The default number of items per page.\n\t */\n\tdefaultPageSize: number;\n};\n\n/**\n * A pagination component for use with cursor-based pagination.\n *\n * Cursor-based pagination is a way of loading data in chunks by using a cursor\n * from the last item on the current page to know where to start the next set,\n * making sure nothing is missed or repeated. Like a linked list, but for chunks\n * of data. It doesn't let you jump to a specific page or know how many total pages\n * there are, but it's more efficient for large or real-time data sets.\n *\n * @see https://mantle.ngrok.com/components/pagination#cursorpaginationroot\n *\n * @example\n * ```tsx\n * <CursorPagination defaultPageSize={10}>\n * <CursorPagination.Buttons\n * hasNextPage={hasNext}\n * hasPreviousPage={hasPrevious}\n * onNextPage={handleNext}\n * onPreviousPage={handlePrevious}\n * />\n * <CursorPagination.PageSizeSelect />\n * </CursorPagination>\n * ```\n */\nconst Root = forwardRef<HTMLDivElement, CursorPaginationProps>(\n\t({ className, children, defaultPageSize, ...props }, ref) => {\n\t\tconst [pageSize, setPageSize] = useState<number>(defaultPageSize);\n\t\tconst contextValue = useMemo(\n\t\t\t() => ({ defaultPageSize, pageSize, setPageSize }),\n\t\t\t[defaultPageSize, pageSize],\n\t\t);\n\n\t\treturn (\n\t\t\t<CursorPaginationContext.Provider value={contextValue}>\n\t\t\t\t<div\n\t\t\t\t\tdata-slot=\"cursor-pagination\"\n\t\t\t\t\tclassName={cx(\"inline-flex items-center justify-between gap-2\", className)}\n\t\t\t\t\tref={ref}\n\t\t\t\t\t{...props}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t</CursorPaginationContext.Provider>\n\t\t);\n\t},\n);\nRoot.displayName = \"CursorPagination\";\n\ntype CursorButtonsProps = Omit<ComponentProps<typeof ButtonGroup>, \"appearance\"> & {\n\t/**\n\t * Whether there is a next page of data to load.\n\t */\n\thasNextPage: boolean;\n\t/**\n\t * Whether there is a previous page of data to load.\n\t */\n\thasPreviousPage: boolean;\n\t/**\n\t * A callback that is called when the next page button is clicked.\n\t */\n\tonNextPage?: () => void;\n\t/**\n\t * A callback that is called when the previous page button is clicked.\n\t */\n\tonPreviousPage?: () => void;\n};\n\n/**\n * A pair of buttons for navigating between pages of data when using cursor-based pagination.\n *\n * @see https://mantle.ngrok.com/components/pagination#cursorpaginationbuttons\n *\n * @example\n * ```tsx\n * <CursorPagination.Buttons\n * hasNextPage={hasNext}\n * hasPreviousPage={hasPrevious}\n * onNextPage={() => loadNextPage()}\n * onPreviousPage={() => loadPreviousPage()}\n * />\n * ```\n */\nconst Buttons = forwardRef<ComponentRef<typeof ButtonGroup>, CursorButtonsProps>(\n\t({ hasNextPage, hasPreviousPage, onNextPage, onPreviousPage, ...props }, ref) => {\n\t\t// TODO(cody): this _feels_ like a good spot for left and right arrow keys to navigate between pages when focused on the buttons\n\n\t\treturn (\n\t\t\t<ButtonGroup data-slot=\"cursor-pagination-buttons\" appearance=\"panel\" ref={ref} {...props}>\n\t\t\t\t<IconButton\n\t\t\t\t\tdata-slot=\"cursor-pagination-previous\"\n\t\t\t\t\tappearance=\"ghost\"\n\t\t\t\t\tdisabled={!hasPreviousPage}\n\t\t\t\t\ticon={<CaretLeftIcon />}\n\t\t\t\t\tlabel=\"Previous page\"\n\t\t\t\t\tonClick={onPreviousPage}\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t/>\n\t\t\t\t<Separator\n\t\t\t\t\tdata-slot=\"cursor-pagination-separator\"\n\t\t\t\t\torientation=\"vertical\"\n\t\t\t\t\tclassName=\"min-h-5\"\n\t\t\t\t/>\n\t\t\t\t<IconButton\n\t\t\t\t\tdata-slot=\"cursor-pagination-next\"\n\t\t\t\t\tappearance=\"ghost\"\n\t\t\t\t\tdisabled={!hasNextPage}\n\t\t\t\t\ticon={<CaretRightIcon />}\n\t\t\t\t\tlabel=\"Next page\"\n\t\t\t\t\tonClick={onNextPage}\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t/>\n\t\t\t</ButtonGroup>\n\t\t);\n\t},\n);\nButtons.displayName = \"CursorButtons\";\n\nconst defaultPageSizes = [5, 10, 20, 50, 100] as const;\n\ntype CursorPageSizeSelectProps = Omit<ComponentProps<typeof Select.Trigger>, \"children\"> & {\n\t/**\n\t * A list of page sizes to choose from. The default page size must be included in this list.\n\t */\n\tpageSizes?: typeof defaultPageSizes | readonly number[];\n\t/**\n\t * A callback that is called when the page size is changed.\n\t */\n\tonChangePageSize?: (value: number) => void;\n};\n\n/**\n * A select input for changing the number of items per page when using cursor-based pagination.\n *\n * @see https://mantle.ngrok.com/components/pagination#cursorpaginationpagesizeselect\n *\n * @example\n * ```tsx\n * <CursorPagination.PageSizeSelect\n * pageSizes={[10, 20, 50, 100]}\n * onChangePageSize={(size) => console.log('Page size changed to:', size)}\n * />\n * ```\n */\nconst PageSizeSelect = forwardRef<ComponentRef<typeof Select.Trigger>, CursorPageSizeSelectProps>(\n\t({ className, pageSizes = defaultPageSizes, onChangePageSize, ...rest }, ref) => {\n\t\tconst ctx = useContext(CursorPaginationContext);\n\n\t\tinvariant(ctx, \"CursorPageSizeSelect must be used as a child of a CursorPagination component\");\n\n\t\tinvariant(\n\t\t\tpageSizes.includes(ctx.defaultPageSize),\n\t\t\t\"CursorPagination.defaultPageSize must be included in CursorPageSizeSelect.pageSizes\",\n\t\t);\n\n\t\tinvariant(\n\t\t\tpageSizes.includes(ctx.pageSize),\n\t\t\t\"CursorPagination.pageSize must be included in CursorPageSizeSelect.pageSizes\",\n\t\t);\n\n\t\treturn (\n\t\t\t<Select.Root\n\t\t\t\tdefaultValue={`${ctx.pageSize}`}\n\t\t\t\tonValueChange={(value) => {\n\t\t\t\t\tlet newPageSize = Number.parseInt(value, 10);\n\t\t\t\t\tif (Number.isNaN(newPageSize)) {\n\t\t\t\t\t\tnewPageSize = ctx.defaultPageSize;\n\t\t\t\t\t}\n\t\t\t\t\tctx.setPageSize(newPageSize);\n\t\t\t\t\tonChangePageSize?.(newPageSize);\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<Select.Trigger\n\t\t\t\t\tref={ref}\n\t\t\t\t\tdata-slot=\"cursor-pagination-page-size-select\"\n\t\t\t\t\tclassName={cx(\"w-auto min-w-36\", className)}\n\t\t\t\t\tvalue={ctx.pageSize}\n\t\t\t\t\t{...rest}\n\t\t\t\t>\n\t\t\t\t\t<Select.Value />\n\t\t\t\t</Select.Trigger>\n\t\t\t\t<Select.Content width=\"trigger\">\n\t\t\t\t\t{pageSizes.map((size) => (\n\t\t\t\t\t\t<Select.Item key={size} value={`${size}`}>\n\t\t\t\t\t\t\t{size} per page\n\t\t\t\t\t\t</Select.Item>\n\t\t\t\t\t))}\n\t\t\t\t</Select.Content>\n\t\t\t</Select.Root>\n\t\t);\n\t},\n);\nPageSizeSelect.displayName = \"CursorPageSizeSelect\";\n\ntype CursorPageSizeValueProps = Omit<ComponentProps<\"span\">, \"children\"> & WithAsChild;\n\n/**\n * Displays the current page size when using cursor-based pagination as a read-only value.\n *\n * @see https://mantle.ngrok.com/components/pagination#cursorpaginationpagesizevalue\n *\n * @example\n * ```tsx\n * <div className=\"flex items-center gap-2\">\n * <span>Items per page:</span>\n * <CursorPagination.PageSizeValue />\n * </div>\n * ```\n */\nfunction PageSizeValue({ asChild = false, className, ...props }: CursorPageSizeValueProps) {\n\tconst ctx = useContext(CursorPaginationContext);\n\n\tinvariant(ctx, \"CursorPageSizeValue must be used as a child of a CursorPagination component\");\n\n\tconst Component = asChild ? Slot : \"span\";\n\n\treturn (\n\t\t<Component\n\t\t\tdata-slot=\"cursor-pagination-page-size-value\"\n\t\t\tclassName={cx(\"text-muted text-sm font-normal\", className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{ctx.pageSize} per page\n\t\t</Component>\n\t);\n}\nPageSizeValue.displayName = \"CursorPageSizeValue\";\n\n/**\n * A pagination component for use with cursor-based pagination.\n *\n * Cursor-based pagination is a way of loading data in chunks by using a cursor\n * from the last item on the current page to know where to start the next set,\n * making sure nothing is missed or repeated. Like a linked list, but for chunks\n * of data. It doesn't let you jump to a specific page or know how many total pages\n * there are, but it's more efficient for large or real-time data sets.\n *\n * @see https://mantle.ngrok.com/components/pagination\n *\n * @example\n * Composition:\n * ```\n * CursorPagination.Root\n * ├── CursorPagination.PageSizeSelect\n * ├── CursorPagination.PageSizeValue\n * └── CursorPagination.Buttons\n * ```\n *\n * @example\n * ```tsx\n * <CursorPagination defaultPageSize={10}>\n * <CursorPagination.Buttons\n * hasNextPage={hasNext}\n * hasPreviousPage={hasPrevious}\n * onNextPage={handleNext}\n * onPreviousPage={handlePrevious}\n * />\n * <CursorPagination.PageSizeSelect />\n * </CursorPagination>\n * ```\n */\nconst CursorPagination = {\n\t/**\n\t * The root container of the cursor pagination component.\n\t *\n\t * @see https://mantle.ngrok.com/components/pagination#cursorpaginationroot\n\t *\n\t * @example\n\t * ```tsx\n\t * <CursorPagination.Root defaultPageSize={10}>\n\t * <CursorPagination.Buttons\n\t * hasNextPage={hasNext}\n\t * hasPreviousPage={hasPrevious}\n\t * onNextPage={handleNext}\n\t * onPreviousPage={handlePrevious}\n\t * />\n\t * <CursorPagination.PageSizeSelect />\n\t * </CursorPagination.Root>\n\t * ```\n\t */\n\tRoot,\n\t/**\n\t * A pair of buttons for navigating between pages of data when using cursor-based pagination.\n\t *\n\t * @see https://mantle.ngrok.com/components/pagination#cursorpaginationbuttons\n\t *\n\t * @example\n\t * ```tsx\n\t * <CursorPagination.Buttons\n\t * hasNextPage={hasNext}\n\t * hasPreviousPage={hasPrevious}\n\t * onNextPage={() => loadNextPage()}\n\t * onPreviousPage={() => loadPreviousPage()}\n\t * />\n\t * ```\n\t */\n\tButtons,\n\t/**\n\t * A select input for changing the number of items per page when using cursor-based pagination.\n\t *\n\t * @see https://mantle.ngrok.com/components/pagination#cursorpaginationpagesizeselect\n\t *\n\t * @example\n\t * ```tsx\n\t * <CursorPagination.PageSizeSelect\n\t * pageSizes={[10, 20, 50, 100]}\n\t * onChangePageSize={(size) => console.log('Page size changed to:', size)}\n\t * />\n\t * ```\n\t */\n\tPageSizeSelect,\n\t/**\n\t * Displays the current page size when using cursor-based pagination as a read-only value.\n\t *\n\t * @see https://mantle.ngrok.com/components/pagination#cursorpaginationpagesizevalue\n\t *\n\t * @example\n\t * ```tsx\n\t * <div className=\"flex items-center gap-2\">\n\t * <span>Items per page:</span>\n\t * <CursorPagination.PageSizeValue />\n\t * </div>\n\t * ```\n\t */\n\tPageSizeValue,\n} as const;\n\nexport {\n\t//,\n\tCursorPagination,\n};\n\nexport type {\n\t//,\n\tCursorButtonsProps,\n\tCursorPageSizeSelectProps,\n\tCursorPageSizeValueProps,\n\tCursorPaginationProps,\n};\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\ntype UseOffsetPaginationProps = {\n\t/**\n\t * The total number of items in the list to be paginated.\n\t */\n\tlistSize: number;\n\t/**\n\t * The number of items per page.\n\t */\n\tpageSize: number;\n};\n\ntype OffsetPaginationState = {\n\t/**\n\t * The current page number, 1-indexed (starting at 1).\n\t */\n\tcurrentPage: number;\n\t/**\n\t * Whether there is a previous page.\n\t */\n\thasPreviousPage: boolean;\n\t/**\n\t * Whether there is a next page.\n\t */\n\thasNextPage: boolean;\n\t/**\n\t * Go to a specific page.\n\t */\n\tgoToPage: (page: number) => void;\n\t/**\n\t * Go to the first page.\n\t */\n\tgoToFirstPage: () => void;\n\t/**\n\t * Go to the last page.\n\t */\n\tgoToLastPage: () => void;\n\t/**\n\t * Go to the next page.\n\t */\n\tnextPage: () => void;\n\t/**\n\t * The offset of the current page in the list.\n\t */\n\toffset: number;\n\t/**\n\t * The number of items per page.\n\t */\n\tpageSize: number;\n\t/**\n\t * Go to the previous page.\n\t */\n\tpreviousPage: () => void;\n\t/**\n\t * Set the number of items per page. This will reset the current page to the first page.\n\t */\n\tsetPageSize: (size: number) => void;\n\t/**\n\t * The total number of pages.\n\t */\n\ttotalPages: number;\n};\n\n/**\n * A headless hook for managing offset-based pagination state\n *\n * @example\n * ```tsx\n * const pagination = useOffsetPagination({\n * listSize: 150,\n * pageSize: 10\n * });\n *\n * return (\n * <div>\n * <p>Page {pagination.currentPage} of {pagination.totalPages}</p>\n * <button onClick={pagination.previousPage} disabled={!pagination.hasPreviousPage}>\n * Previous\n * </button>\n * <button onClick={pagination.nextPage} disabled={!pagination.hasNextPage}>\n * Next\n * </button>\n * </div>\n * );\n * ```\n */\nfunction useOffsetPagination({\n\tlistSize,\n\tpageSize,\n}: UseOffsetPaginationProps): OffsetPaginationState {\n\tconst [currentPage, setCurrentPage] = useState(1);\n\tconst [currentPageSize, setCurrentPageSize] = useState(pageSize);\n\n\t// Reset the current page to 1 when the page size prop changes\n\tuseEffect(() => {\n\t\tsetCurrentPageSize(pageSize);\n\t\tsetCurrentPage(1);\n\t}, [pageSize]);\n\n\t// Reset the current page to 1 when the list size prop changes\n\tuseEffect(() => {\n\t\tsetCurrentPage(1);\n\t}, [listSize]);\n\n\tconst totalPages = Math.ceil(listSize / currentPageSize);\n\tconst offset = (currentPage - 1) * currentPageSize;\n\n\tconst hasPreviousPage = currentPage > 1;\n\tconst hasNextPage = currentPage < totalPages;\n\n\tfunction goToPage(page: number) {\n\t\tconst clampedPage = Math.max(1, Math.min(page, totalPages));\n\t\tsetCurrentPage(clampedPage);\n\t}\n\n\tfunction nextPage() {\n\t\tif (hasNextPage) {\n\t\t\tsetCurrentPage((prev) => Math.min(prev + 1, totalPages));\n\t\t}\n\t}\n\n\tfunction previousPage() {\n\t\tif (hasPreviousPage) {\n\t\t\tsetCurrentPage((prev) => Math.max(prev - 1, 1));\n\t\t}\n\t}\n\n\tfunction setPageSize(size: number) {\n\t\tsetCurrentPageSize(size);\n\t\tsetCurrentPage(1); // reset to the first page when page size changes\n\t}\n\n\tfunction goToLastPage() {\n\t\tsetCurrentPage(totalPages);\n\t}\n\n\tfunction goToFirstPage() {\n\t\tsetCurrentPage(1);\n\t}\n\n\treturn {\n\t\tcurrentPage,\n\t\tgoToFirstPage,\n\t\tgoToLastPage,\n\t\tgoToPage,\n\t\thasNextPage,\n\t\thasPreviousPage,\n\t\tnextPage,\n\t\toffset,\n\t\tpageSize: currentPageSize,\n\t\tpreviousPage,\n\t\tsetPageSize,\n\t\ttotalPages,\n\t};\n}\n\n/**\n * Get a paginated slice of a list based on the current offset pagination state.\n *\n * @example\n * ```tsx\n * const data = ['a', 'b', 'c', 'd', 'e', 'f'];\n * const pagination = useOffsetPagination({ listSize: data.length, pageSize: 2 });\n * const currentPageData = getOffsetPaginatedSlice(data, pagination);\n * // Returns: ['a', 'b'] for page 1, ['c', 'd'] for page 2, etc.\n * ```\n */\nfunction getOffsetPaginatedSlice<T>(list: readonly T[], pagination: OffsetPaginationState): T[] {\n\treturn list.slice(pagination.offset, pagination.offset + pagination.pageSize);\n}\n\nexport {\n\t//,\n\tgetOffsetPaginatedSlice,\n\tuseOffsetPagination,\n};\n\nexport type {\n\t//,\n\tOffsetPaginationState,\n\tUseOffsetPaginationProps,\n};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"popover-DponNBot.js","names":[],"sources":["../src/components/popover/popover.tsx"],"sourcesContent":["import * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport { forwardRef } from \"react\";\nimport type { ComponentPropsWithoutRef, ComponentRef } from \"react\";\nimport { cx } from \"../../utils/cx/cx.js\";\n\n/**\n * A floating overlay that displays rich content in a portal, triggered by a button.\n * This is the root, stateful component that manages the open/closed state of the popover.\n *\n * @see https://mantle.ngrok.com/components/popover#popoverroot\n *\n * @example\n * ```tsx\n * <Popover.Root>\n * <Popover.Trigger asChild>\n * <Button type=\"button\" appearance=\"outlined\">\n * Open Popover\n * </Button>\n * </Popover.Trigger>\n * <Popover.Content>\n * <p>This is the popover content.</p>\n * </Popover.Content>\n * </Popover.Root>\n * ```\n */\nconst Root = PopoverPrimitive.Root;\nRoot.displayName = \"Popover\";\n\n/**\n * The trigger button that opens the popover.\n *\n * @see https://mantle.ngrok.com/components/popover#popovertrigger\n *\n * @example\n * ```tsx\n * <Popover.Root>\n * <Popover.Trigger asChild>\n * <Button type=\"button\" appearance=\"outlined\">\n * Open Popover\n * </Button>\n * </Popover.Trigger>\n * <Popover.Content>\n * <p>This is the popover content.</p>\n * </Popover.Content>\n * </Popover.Root>\n * ```\n */\nconst Trigger = PopoverPrimitive.Trigger;\nTrigger.displayName = \"PopoverTrigger\";\n\n/**\n * An optional element to position the PopoverContent against. If this part is not used, the content will position alongside the PopoverTrigger.\n *\n * @see https://mantle.ngrok.com/components/popover#popoveranchor\n *\n * @example\n * ```tsx\n * <Popover.Root>\n * <Popover.Trigger asChild>\n * <Button type=\"button\" appearance=\"outlined\">\n * Open Popover\n * </Button>\n * </Popover.Trigger>\n * <Popover.Anchor asChild>\n * <div>Anchor element</div>\n * </Popover.Anchor>\n * <Popover.Content>\n * <p>This is the popover content.</p>\n * </Popover.Content>\n * </Popover.Root>\n * ```\n */\nconst Anchor = PopoverPrimitive.Anchor;\nAnchor.displayName = \"PopoverAnchor\";\n\n/**\n * A button that closes an open popover.\n *\n * @see https://mantle.ngrok.com/components/popover#popoverclose\n *\n * @example\n * ```tsx\n * <Popover.Root>\n * <Popover.Trigger asChild>\n * <Button type=\"button\" appearance=\"outlined\">\n * Open Popover\n * </Button>\n * </Popover.Trigger>\n * <Popover.Content>\n * <p>This is the popover content.</p>\n * <Popover.Close asChild>\n * <Button type=\"button\">Close</Button>\n * </Popover.Close>\n * </Popover.Content>\n * </Popover.Root>\n * ```\n */\nconst Close = PopoverPrimitive.Close;\nClose.displayName = \"PopoverClose\";\n\ntype PopoverContentProps = ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> & {\n\t/**\n\t * The preferred width of the `PopoverContent` as a tailwind `max-w-` class.\n\t *\n\t * By default, a `Popover`'s content width is responsive with a default\n\t * preferred width: the maximum width of the `PopoverContent`\n\t *\n\t * @default `max-w-72`\n\t */\n\tpreferredWidth?: `max-w-${string}`;\n};\n\n/**\n * The content to render inside the popover.\n *\n * @see https://mantle.ngrok.com/components/popover#popovercontent\n *\n * @example\n * ```tsx\n * <Popover.Root>\n * <Popover.Trigger asChild>\n * <Button type=\"button\" appearance=\"outlined\">\n * Open Popover\n * </Button>\n * </Popover.Trigger>\n * <Popover.Content>\n * <p>This is the popover content.</p>\n * </Popover.Content>\n * </Popover.Root>\n * ```\n */\nconst Content = forwardRef<ComponentRef<\"div\">, PopoverContentProps>(\n\t(\n\t\t{\n\t\t\t//,\n\t\t\talign = \"center\",\n\t\t\tclassName,\n\t\t\tonClick,\n\t\t\tpreferredWidth = \"max-w-72\",\n\t\t\tsideOffset = 4,\n\t\t\t...props\n\t\t},\n\t\tref,\n\t) => (\n\t\t<PopoverPrimitive.Portal>\n\t\t\t<PopoverPrimitive.Content\n\t\t\t\talign={align}\n\t\t\t\tdata-slot=\"popover-content\"\n\t\t\t\tclassName={cx(\n\t\t\t\t\t\"text-popover-foreground border-popover bg-popover 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 data-state-closed:animate-out data-state-closed:fade-out-0 data-state-closed:zoom-out-95 data-state-open:animate-in data-state-open:fade-in-0 data-state-open:zoom-in-95 z-50 rounded-md border p-4 shadow-md outline-hidden\",\n\t\t\t\t\tpreferredWidth,\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tonClick={(event) => {\n\t\t\t\t\t/**\n\t\t\t\t\t * Prevent the click event from propagating up to parent/containing elements\n\t\t\t\t\t * of the PopoverContent\n\t\t\t\t\t */\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\tonClick?.(event);\n\t\t\t\t}}\n\t\t\t\tref={ref}\n\t\t\t\tsideOffset={sideOffset}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t</PopoverPrimitive.Portal>\n\t),\n);\nContent.displayName = \"PopoverContent\";\n\n/**\n * A floating overlay that displays rich content in a portal, triggered by a button.\n *\n * Use `Popover` for INTERACTIVE overlay content — small forms, settings\n * menus, color pickers, action lists. The user opens it deliberately\n * (click/tap or focus + space). For short, non-interactive label hints\n * triggered by hover, use `Tooltip` instead. For non-essential preview\n * content shown on hover, use `HoverCard`.\n *\n * `Popover` is a non-modal dialog by default: focus moves into the content\n * when it opens, `Escape` closes and returns focus to the trigger, clicking\n * outside dismisses, and the page (body and any scroll containers) continues\n * to scroll normally. Pass `modal` on `Popover.Root` to trap focus inside\n * the content, block interaction with the rest of the page, and lock body\n * scroll while the popover is open.\n *\n * @see https://mantle.ngrok.com/components/popover\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/\n *\n * @example\n * Composition:\n * ```\n * Popover.Root\n * ├── Popover.Trigger\n * ├── Popover.Anchor\n * └── Popover.Content\n * └── Popover.Close\n * ```\n *\n * @example\n * ```tsx\n * <Popover.Root>\n * <Popover.Trigger asChild>\n * <Button type=\"button\" appearance=\"outlined\">\n * Open Popover\n * </Button>\n * </Popover.Trigger>\n * <Popover.Content>\n * <p>This is the popover content.</p>\n * </Popover.Content>\n * </Popover.Root>\n * ```\n */\nconst Popover = {\n\t/**\n\t * The root, stateful component that manages the open/closed state of the popover.\n\t *\n\t * @see https://mantle.ngrok.com/components/popover#popoverroot\n\t *\n\t * @example\n\t * ```tsx\n\t * <Popover.Root>\n\t * <Popover.Trigger asChild>\n\t * <Button>Open popover</Button>\n\t * </Popover.Trigger>\n\t * <Popover.Content>\n\t * <p>This is the popover content.</p>\n\t * </Popover.Content>\n\t * </Popover.Root>\n\t * ```\n\t */\n\tRoot,\n\t/**\n\t * An optional element to position the PopoverContent against. If not used, content positions alongside the trigger.\n\t *\n\t * @see https://mantle.ngrok.com/components/popover#popoveranchor\n\t *\n\t * @example\n\t * ```tsx\n\t * <Popover.Root>\n\t * <Popover.Anchor asChild>\n\t * <div>Position relative to this element</div>\n\t * </Popover.Anchor>\n\t * <Popover.Trigger asChild>\n\t * <Button type=\"button\" appearance=\"outlined\">Open Popover</Button>\n\t * </Popover.Trigger>\n\t * <Popover.Content>\n\t * <p>This popover is positioned relative to the anchor.</p>\n\t * <Popover.Close asChild>\n\t * <Button type=\"button\">Close</Button>\n\t * </Popover.Close>\n\t * </Popover.Content>\n\t * </Popover.Root>\n\t * ```\n\t */\n\tAnchor,\n\t/**\n\t * A button that closes an open popover. Can be placed anywhere within the popover content.\n\t *\n\t * @see https://mantle.ngrok.com/components/popover#popoverclose\n\t *\n\t * @example\n\t * ```tsx\n\t * <Popover.Root>\n\t * <Popover.Trigger asChild>\n\t * <Button type=\"button\">Settings</Button>\n\t * </Popover.Trigger>\n\t * <Popover.Content>\n\t * <div className=\"flex items-center justify-between\">\n\t * <Text>Settings Panel</Text>\n\t * <Popover.Close asChild>\n\t * <Button type=\"button\" appearance=\"ghost\" size=\"sm\">✕</Button>\n\t * </Popover.Close>\n\t * </div>\n\t * <Text>Configure your preferences here.</Text>\n\t * </Popover.Content>\n\t * </Popover.Root>\n\t * ```\n\t */\n\tClose,\n\t/**\n\t * The content to render inside the popover. Appears in a portal with rich styling and animations.\n\t *\n\t * @see https://mantle.ngrok.com/components/popover#popovercontent\n\t *\n\t * @example\n\t * ```tsx\n\t * <Popover.Root>\n\t * <Popover.Trigger asChild>\n\t * <Button type=\"button\">Show Info</Button>\n\t * </Popover.Trigger>\n\t * <Popover.Content side=\"top\" align=\"center\">\n\t * <div className=\"space-y-2\">\n\t * <Text weight=\"strong\">Additional Information</Text>\n\t * <Text>This is the content inside the popover.</Text>\n\t * <Button type=\"button\" size=\"sm\">Action</Button>\n\t * </div>\n\t * </Popover.Content>\n\t * </Popover.Root>\n\t * ```\n\t */\n\tContent,\n\t/**\n\t * The trigger button that opens the popover when clicked or focused.\n\t *\n\t * @see https://mantle.ngrok.com/components/popover#popovertrigger\n\t *\n\t * @example\n\t * ```tsx\n\t * <Popover.Root>\n\t * <Popover.Trigger asChild>\n\t * <Button type=\"button\" appearance=\"outlined\">\n\t * Options\n\t * </Button>\n\t * </Popover.Trigger>\n\t * <Popover.Content>\n\t * <div className=\"space-y-2\">\n\t * <Button type=\"button\" variant=\"ghost\">Edit</Button>\n\t * <Button type=\"button\" variant=\"ghost\">Delete</Button>\n\t * </div>\n\t * </Popover.Content>\n\t * </Popover.Root>\n\t * ```\n\t */\n\tTrigger,\n} as const;\n\nexport {\n\t//,\n\tPopover,\n};\n"],"mappings":"0JAyBA,MAAM,EAAO,EAAiB,KAC9B,EAAK,YAAc,UAqBnB,MAAM,EAAU,EAAiB,QACjC,EAAQ,YAAc,iBAwBtB,MAAM,EAAS,EAAiB,OAChC,EAAO,YAAc,gBAwBrB,MAAM,EAAQ,EAAiB,MAC/B,EAAM,YAAc,eAiCpB,MAAM,EAAU,GAEd,CAEC,QAAQ,SACR,YACA,UACA,iBAAiB,WACjB,aAAa,EACb,GAAG,GAEJ,IAEA,EAAC,EAAiB,OAAlB,CAAA,SACC,EAAC,EAAiB,QAAlB,CACQ,QACP,YAAU,kBACV,UAAW,EACV,qaACA,EACA,CACD,EACA,QAAU,GAAU,CAKnB,EAAM,gBAAgB,EACtB,IAAU,CAAK,CAChB,EACK,MACO,aACZ,GAAI,CACJ,CAAA,CACuB,CAAA,CAE3B,EACA,EAAQ,YAAc,iBA6CtB,MAAM,EAAU,CAkBf,OAwBA,SAwBA,QAsBA,UAuBA,SACD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"primitive-Cn3h4DJg.js","names":[],"sources":["../src/components/dialog/primitive.tsx"],"sourcesContent":["\"use client\";\n\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport {\n\ttype ComponentPropsWithoutRef,\n\ttype ComponentRef,\n\tcreateContext,\n\tforwardRef,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseState,\n} from \"react\";\nimport { Slot } from \"../slot/index.js\";\nimport { preventCloseOnPromptInteraction } from \"../toast/toast.js\";\nimport { parseBooleanish } from \"../../types/booleanish.js\";\n\ntype DialogPrimitiveContentProps = ComponentPropsWithoutRef<typeof DialogPrimitive.Content>;\n\ntype InternalDialogContextValue = {\n\thasDescription: boolean;\n\tsetHasDescription: (value: boolean) => void;\n};\n\nconst InternalDialogContext = createContext<InternalDialogContextValue>({\n\thasDescription: false,\n\tsetHasDescription: () => {},\n});\n\nfunction Root(props: ComponentPropsWithoutRef<typeof DialogPrimitive.Root>) {\n\tconst [hasDescription, setHasDescription] = useState(false);\n\tconst contextValue = useMemo(() => ({ hasDescription, setHasDescription }), [hasDescription]);\n\n\treturn (\n\t\t<InternalDialogContext.Provider value={contextValue}>\n\t\t\t<DialogPrimitive.Root {...props} />\n\t\t</InternalDialogContext.Provider>\n\t);\n}\nRoot.displayName = \"DialogPrimitiveRoot\";\n\nconst Trigger = DialogPrimitive.Trigger;\nTrigger.displayName = \"DialogPrimitiveTrigger\";\n\nconst Portal = DialogPrimitive.Portal;\nPortal.displayName = \"DialogPrimitivePortal\";\n\nconst Close = DialogPrimitive.Close;\nClose.displayName = \"DialogPrimitiveClose\";\n\nconst Overlay = forwardRef<\n\tComponentRef<typeof DialogPrimitive.Overlay>,\n\tComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>((props, ref) => (\n\t<DialogPrimitive.Overlay\n\t\t/**\n\t\t * Mark the overlay with a data attribute so we can target it, e.g. in\n\t\t * event handlers\n\t\t */\n\t\tdata-overlay\n\t\tref={ref}\n\t\t{...props}\n\t/>\n));\nOverlay.displayName = \"DialogPrimitiveOverlay\";\n\nconst Content = forwardRef<ComponentRef<\"div\">, DialogPrimitiveContentProps>(\n\t({ onEscapeKeyDown, onInteractOutside, onPointerDownOutside, ...props }, ref) => {\n\t\tconst ctx = useContext(InternalDialogContext);\n\n\t\treturn (\n\t\t\t<DialogPrimitive.Content\n\t\t\t\tref={ref}\n\t\t\t\tonEscapeKeyDown={(event) => {\n\t\t\t\t\tpreventCloseOnNestedPopupEscape(event);\n\t\t\t\t\tonEscapeKeyDown?.(event);\n\t\t\t\t}}\n\t\t\t\tonInteractOutside={(event) => {\n\t\t\t\t\tpreventCloseOnPromptInteraction(event);\n\t\t\t\t\tonInteractOutside?.(event);\n\t\t\t\t}}\n\t\t\t\tonPointerDownOutside={(event) => {\n\t\t\t\t\tpreventCloseOnPromptInteraction(event);\n\t\t\t\t\tonPointerDownOutside?.(event);\n\t\t\t\t}}\n\t\t\t\t// If there's no description, we remove the default applied aria-describedby attribute from radix dialog\n\t\t\t\t{...(!ctx.hasDescription ? { \"aria-describedby\": undefined } : {})}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t},\n);\nContent.displayName = \"DialogPrimitiveContent\";\n\nconst Title = DialogPrimitive.Title;\n\n/**\n * An accessible description for the dialog primitive.\n * This is a low-level primitive used by higher-level dialog components.\n * Renders as a `div` by default, but can be changed to any other element using the `asChild` prop.\n */\nconst Description = forwardRef<\n\tComponentRef<\"div\">,\n\tComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ asChild, children, ...props }, ref) => {\n\tconst ctx = useContext(InternalDialogContext);\n\n\tuseEffect(() => {\n\t\tctx.setHasDescription(true);\n\t\treturn () => ctx.setHasDescription(false);\n\t}, [ctx]);\n\n\tconst Component = asChild ? Slot : \"div\";\n\n\treturn (\n\t\t<DialogPrimitive.Description ref={ref} asChild>\n\t\t\t<Component {...props}>{children}</Component>\n\t\t</DialogPrimitive.Description>\n\t);\n});\nDescription.displayName = \"DialogPrimitiveDescription\";\n\n/**\n * Type guard to check if the event target is the overlay component\n */\nfunction isDialogOverlayTarget(target: EventTarget | null): boolean {\n\tif (target instanceof HTMLElement) {\n\t\treturn target.hasAttribute(\"data-overlay\");\n\t}\n\treturn false;\n}\n\nexport {\n\t//,\n\tRoot,\n\tTrigger,\n\tPortal,\n\tClose,\n\tOverlay,\n\tContent,\n\tDescription,\n\tTitle,\n\tisDialogOverlayTarget,\n};\n\n/**\n * Prevents the parent dialog/sheet/alert-dialog from closing on Escape when a\n * nested popup owner inside the same modal content is currently expanded.\n *\n * Flow:\n * - If focus is outside the nested popup owner, Escape closes the parent modal.\n * - If focus is inside the nested popup owner and its controlled popup is open,\n * the first Escape closes only the nested popup and keeps the parent modal open.\n * - Once the nested popup has closed, a subsequent Escape closes the parent modal.\n */\nfunction preventCloseOnNestedPopupEscape(\n\tevent: Parameters<NonNullable<DialogPrimitiveContentProps[\"onEscapeKeyDown\"]>>[0],\n): void {\n\tif (!isParentNode(event.currentTarget)) {\n\t\treturn;\n\t}\n\n\tconst currentTarget = event.currentTarget;\n\tconst activeElement =\n\t\tcurrentTarget instanceof Document\n\t\t\t? currentTarget.activeElement\n\t\t\t: (currentTarget.ownerDocument?.activeElement ?? null);\n\n\tconst owner = getExpandedPopupOwner(event.target) ?? getExpandedPopupOwner(activeElement);\n\n\tconst popup = owner ? getControlledPopup(owner) : null;\n\n\tif (\n\t\towner != null &&\n\t\tparseBooleanish(owner.getAttribute(\"aria-expanded\")) &&\n\t\tpopup != null &&\n\t\tcurrentTarget.contains(owner) &&\n\t\tcurrentTarget.contains(popup) &&\n\t\t// Only block closing if the popup is actively open. Always-visible lists\n\t\t// without open/close state (e.g. cmdk) carry neither attribute and should\n\t\t// never block the dialog from closing.\n\t\t// - Ariakit sets `data-open=\"true\"` when its popover is open.\n\t\t// - Radix sets `data-state=\"open\"` when its popup is open.\n\t\t(popup.getAttribute(\"data-open\") === \"true\" || popup.getAttribute(\"data-state\") === \"open\")\n\t) {\n\t\tevent.preventDefault();\n\t}\n}\n\n/**\n * Finds the nearest expanded popup owner for a node using ARIA relationships.\n *\n * A matching owner must expose `aria-expanded=\"true\"` and `aria-controls`, which\n * lets nested controls like comboboxes and input-attached popovers signal that an\n * inner surface is currently open.\n */\nfunction getExpandedPopupOwner(node: EventTarget | null): HTMLElement | null {\n\tif (!isHTMLElement(node)) {\n\t\treturn null;\n\t}\n\n\tconst owner = node.closest<HTMLElement>(\"[aria-expanded='true'][aria-controls]\");\n\treturn owner;\n}\n\n/**\n * Resolves the popup element controlled by an expanded owner via `aria-controls`.\n */\nfunction getControlledPopup(owner: HTMLElement): HTMLElement | null {\n\tconst popupId = owner.getAttribute(\"aria-controls\");\n\tif (!popupId) {\n\t\treturn null;\n\t}\n\n\tconst popup = owner.ownerDocument.getElementById(popupId);\n\treturn popup instanceof HTMLElement ? popup : null;\n}\n\n/**\n * Narrows an event target to an HTMLElement so DOM traversal helpers can be used safely.\n */\nfunction isHTMLElement(value: EventTarget | null): value is HTMLElement {\n\treturn value instanceof HTMLElement;\n}\n\n/**\n * Narrows an event target to a queryable DOM parent node, such as an Element or Document.\n */\nfunction isParentNode(value: EventTarget | null): value is ParentNode & Node {\n\treturn value instanceof Node && \"querySelector\" in value;\n}\n"],"mappings":"wTAwBA,MAAM,EAAwB,EAA0C,CACvE,eAAgB,GAChB,sBAAyB,CAAC,CAC3B,CAAC,EAED,SAAS,EAAK,EAA8D,CAC3E,GAAM,CAAC,EAAgB,GAAqB,EAAS,EAAK,EACpD,EAAe,OAAe,CAAE,iBAAgB,mBAAkB,GAAI,CAAC,CAAc,CAAC,EAE5F,OACC,EAAC,EAAsB,SAAvB,CAAgC,MAAO,WACtC,EAAC,EAAgB,KAAjB,CAAsB,GAAI,CAAQ,CAAA,CACH,CAAA,CAElC,CACA,EAAK,YAAc,sBAEnB,MAAM,EAAU,EAAgB,QAChC,EAAQ,YAAc,yBAEtB,MAAM,EAAS,EAAgB,OAC/B,EAAO,YAAc,wBAErB,MAAM,EAAQ,EAAgB,MAC9B,EAAM,YAAc,uBAEpB,MAAM,EAAU,GAGb,EAAO,IACT,EAAC,EAAgB,QAAjB,CAKC,eAAA,GACK,MACL,GAAI,CACJ,CAAA,CACD,EACD,EAAQ,YAAc,yBAEtB,MAAM,EAAU,GACd,CAAE,kBAAiB,oBAAmB,uBAAsB,GAAG,GAAS,IAAQ,CAChF,IAAM,EAAM,EAAW,CAAqB,EAE5C,OACC,EAAC,EAAgB,QAAjB,CACM,MACL,gBAAkB,GAAU,CAC3B,EAAgC,CAAK,EACrC,IAAkB,CAAK,CACxB,EACA,kBAAoB,GAAU,CAC7B,EAAgC,CAAK,EACrC,IAAoB,CAAK,CAC1B,EACA,qBAAuB,GAAU,CAChC,EAAgC,CAAK,EACrC,IAAuB,CAAK,CAC7B,EAEA,GAAM,EAAI,eAAqD,CAAC,EAArC,CAAE,mBAAoB,IAAA,EAAU,EAC3D,GAAI,CACJ,CAAA,CAEH,CACD,EACA,EAAQ,YAAc,yBAEtB,MAAM,EAAQ,EAAgB,MAOxB,EAAc,GAGjB,CAAE,UAAS,WAAU,GAAG,GAAS,IAAQ,CAC3C,IAAM,EAAM,EAAW,CAAqB,EAE5C,OACC,EAAI,kBAAkB,EAAI,MACb,EAAI,kBAAkB,EAAK,GACtC,CAAC,CAAG,CAAC,EAER,IAAM,EAAY,EAAU,EAAO,MAEnC,OACC,EAAC,EAAgB,YAAjB,CAAkC,MAAK,QAAA,YACtC,EAAC,EAAD,CAAW,GAAI,EAAQ,UAAoB,CAAA,CACf,CAAA,CAE/B,CAAC,EACD,EAAY,YAAc,6BAK1B,SAAS,EAAsB,EAAqC,CAInE,OAHI,aAAkB,YACd,EAAO,aAAa,cAAc,EAEnC,EACR,CAyBA,SAAS,EACR,EACO,CACP,GAAI,CAAC,EAAa,EAAM,aAAa,EACpC,OAGD,IAAM,EAAgB,EAAM,cACtB,EACL,aAAyB,SACtB,EAAc,cACb,EAAc,eAAe,eAAiB,KAE7C,EAAQ,EAAsB,EAAM,MAAM,GAAK,EAAsB,CAAa,EAElF,EAAQ,EAAQ,EAAmB,CAAK,EAAI,KAGjD,GAAS,MACT,EAAgB,EAAM,aAAa,eAAe,CAAC,GACnD,GAAS,MACT,EAAc,SAAS,CAAK,GAC5B,EAAc,SAAS,CAAK,IAM3B,EAAM,aAAa,WAAW,IAAM,QAAU,EAAM,aAAa,YAAY,IAAM,SAEpF,EAAM,eAAe,CAEvB,CASA,SAAS,EAAsB,EAA8C,CAM5E,OALK,EAAc,CAAI,EAIT,EAAK,QAAqB,uCAC7B,EAJH,IAKT,CAKA,SAAS,EAAmB,EAAwC,CACnE,IAAM,EAAU,EAAM,aAAa,eAAe,EAClD,GAAI,CAAC,EACJ,OAAO,KAGR,IAAM,EAAQ,EAAM,cAAc,eAAe,CAAO,EACxD,OAAO,aAAiB,YAAc,EAAQ,IAC/C,CAKA,SAAS,EAAc,EAAiD,CACvE,OAAO,aAAiB,WACzB,CAKA,SAAS,EAAa,EAAuD,CAC5E,OAAO,aAAiB,MAAQ,kBAAmB,CACpD"}
|