@cloudflare/kumo 2.0.4 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/ai/component-registry.json +24 -1
- package/ai/component-registry.md +57 -0
- package/dist/.build-complete +1 -1
- package/dist/chunks/SankeyChart-i4vgcatj89zpgpl9.js +626 -0
- package/dist/chunks/SankeyChart-i4vgcatj89zpgpl9.js.map +1 -0
- package/dist/chunks/{autocomplete-hbs51xgjf9iglbmq.js → autocomplete-1hi2rgzo10bczkfa.js} +4 -4
- package/dist/chunks/{autocomplete-hbs51xgjf9iglbmq.js.map → autocomplete-1hi2rgzo10bczkfa.js.map} +1 -1
- package/dist/chunks/{breadcrumbs-er08s9swoctwoj69.js → breadcrumbs-davmangc0urzivbs.js} +2 -2
- package/dist/chunks/{breadcrumbs-er08s9swoctwoj69.js.map → breadcrumbs-davmangc0urzivbs.js.map} +1 -1
- package/dist/chunks/{button-fe5rvewji3e5xd7m.js → button-n859eyw550yi2b9z.js} +2 -2
- package/dist/chunks/{button-fe5rvewji3e5xd7m.js.map → button-n859eyw550yi2b9z.js.map} +1 -1
- package/dist/chunks/{checkbox-l7kc0vcs0o7a6fgn.js → checkbox-dfl2fr8nchh43qfc.js} +3 -3
- package/dist/chunks/{checkbox-l7kc0vcs0o7a6fgn.js.map → checkbox-dfl2fr8nchh43qfc.js.map} +1 -1
- package/dist/chunks/{clipboard-text-je4e2q880wngmmuc.js → clipboard-text-ic9k5qjkljlr9z3b.js} +4 -4
- package/dist/chunks/{clipboard-text-je4e2q880wngmmuc.js.map → clipboard-text-ic9k5qjkljlr9z3b.js.map} +1 -1
- package/dist/chunks/{collapsible-nlp2jvcyuzxmq28o.js → collapsible-jvebgqfqljzokj8h.js} +2 -2
- package/dist/chunks/{collapsible-nlp2jvcyuzxmq28o.js.map → collapsible-jvebgqfqljzokj8h.js.map} +1 -1
- package/dist/chunks/{combobox-ck95wketqoqbxjwb.js → combobox-f5nyw45yiwx5f69l.js} +26 -23
- package/dist/chunks/{combobox-ck95wketqoqbxjwb.js.map → combobox-f5nyw45yiwx5f69l.js.map} +1 -1
- package/dist/chunks/{command-palette-kgiso245exdons4r.js → command-palette-ezbzp2fpbbo97ogf.js} +12 -12
- package/dist/chunks/command-palette-ezbzp2fpbbo97ogf.js.map +1 -0
- package/dist/chunks/{dialog-mqpvaidy0vnjwrfp.js → dialog-n6uc2s99xwdn2pnb.js} +3 -3
- package/dist/chunks/{dialog-mqpvaidy0vnjwrfp.js.map → dialog-n6uc2s99xwdn2pnb.js.map} +1 -1
- package/dist/chunks/{dropdown-gp5iptj1niq14lpv.js → dropdown-mftv4iv9nzhprg81.js} +2 -2
- package/dist/chunks/{dropdown-gp5iptj1niq14lpv.js.map → dropdown-mftv4iv9nzhprg81.js.map} +1 -1
- package/dist/chunks/{empty-bmacg9ap2gjmyqiw.js → empty-mmtirqntk6enx51o.js} +2 -2
- package/dist/chunks/{empty-bmacg9ap2gjmyqiw.js.map → empty-mmtirqntk6enx51o.js.map} +1 -1
- package/dist/chunks/{field-hmucpi6d4sqci1zu.js → field-mil8efu3x0s68eed.js} +3 -3
- package/dist/chunks/{field-hmucpi6d4sqci1zu.js.map → field-mil8efu3x0s68eed.js.map} +1 -1
- package/dist/chunks/{input-area-dpgn5810c269jwbu.js → input-area-hl1rdb9xcrqyt8xw.js} +4 -4
- package/dist/chunks/{input-area-dpgn5810c269jwbu.js.map → input-area-hl1rdb9xcrqyt8xw.js.map} +1 -1
- package/dist/chunks/{input-group-k1xa9cu8ochl1arh.js → input-group-5luo0442jgsie018.js} +5 -5
- package/dist/chunks/{input-group-k1xa9cu8ochl1arh.js.map → input-group-5luo0442jgsie018.js.map} +1 -1
- package/dist/chunks/{input-k2ychlh2zo6hsocz.js → input-kmztt6h4mzy101ho.js} +3 -3
- package/dist/chunks/{input-k2ychlh2zo6hsocz.js.map → input-kmztt6h4mzy101ho.js.map} +1 -1
- package/dist/chunks/{label-ni6chzu01wns3cs2.js → label-d14ibjmcbk1qmyrt.js} +3 -3
- package/dist/chunks/{label-ni6chzu01wns3cs2.js.map → label-d14ibjmcbk1qmyrt.js.map} +1 -1
- package/dist/chunks/{layer-card-ikm31xemd70w3lru.js → layer-card-eomdoafn3sfpih1d.js} +18 -17
- package/dist/chunks/layer-card-eomdoafn3sfpih1d.js.map +1 -0
- package/dist/chunks/{link-m9hlspftl34nseme.js → link-ihastr6a2dmo1so5.js} +39 -25
- package/dist/chunks/link-ihastr6a2dmo1so5.js.map +1 -0
- package/dist/chunks/link-provider-mn2voeohon7cj9o4.js.map +1 -1
- package/dist/chunks/{menubar-hwev159bm4rw9ixk.js → menubar-f6xelkurau8cl60f.js} +2 -2
- package/dist/chunks/{menubar-hwev159bm4rw9ixk.js.map → menubar-f6xelkurau8cl60f.js.map} +1 -1
- package/dist/chunks/{meter-n34a7yb8c3rim26i.js → meter-g1ja8cwtum0frcdj.js} +2 -2
- package/dist/chunks/{meter-n34a7yb8c3rim26i.js.map → meter-g1ja8cwtum0frcdj.js.map} +1 -1
- package/dist/chunks/{pagination-l9inbujoqp5swmyg.js → pagination-kmtbb3twehv79tm8.js} +3 -3
- package/dist/chunks/{pagination-l9inbujoqp5swmyg.js.map → pagination-kmtbb3twehv79tm8.js.map} +1 -1
- package/dist/chunks/{popover-iayd9ya5yhujz6ve.js → popover-f3t99000mahsnjzc.js} +2 -2
- package/dist/chunks/{popover-iayd9ya5yhujz6ve.js.map → popover-f3t99000mahsnjzc.js.map} +1 -1
- package/dist/chunks/{radio-f95mt237ru8fyc03.js → radio-me5m5ei86beum5bo.js} +2 -2
- package/dist/chunks/{radio-f95mt237ru8fyc03.js.map → radio-me5m5ei86beum5bo.js.map} +1 -1
- package/dist/chunks/{select-n6u3p44qgtb0in3z.js → select-brzswxbhhf1ktx9t.js} +5 -5
- package/dist/chunks/{select-n6u3p44qgtb0in3z.js.map → select-brzswxbhhf1ktx9t.js.map} +1 -1
- package/dist/chunks/{sensitive-input-yoawqvvvmtdod430.js → sensitive-input-gyf5hhgyolt07y1p.js} +4 -4
- package/dist/chunks/{sensitive-input-yoawqvvvmtdod430.js.map → sensitive-input-gyf5hhgyolt07y1p.js.map} +1 -1
- package/dist/chunks/{sidebar-jjptencqv1jgztgu.js → sidebar-o8y71x814ptc0xpf.js} +3 -3
- package/dist/chunks/{sidebar-jjptencqv1jgztgu.js.map → sidebar-o8y71x814ptc0xpf.js.map} +1 -1
- package/dist/chunks/{surface-k0e8mq1x00b7i8r6.js → surface-ivrb4btwdoq91ytl.js} +2 -2
- package/dist/chunks/{surface-k0e8mq1x00b7i8r6.js.map → surface-ivrb4btwdoq91ytl.js.map} +1 -1
- package/dist/chunks/{switch-dsnh8onvu1sxzdoe.js → switch-c0avfhj6n85inmtb.js} +3 -3
- package/dist/chunks/{switch-dsnh8onvu1sxzdoe.js.map → switch-c0avfhj6n85inmtb.js.map} +1 -1
- package/dist/chunks/{table-ngrghrfy9qsk6091.js → table-htqdo9dgy8c6hwuq.js} +2 -2
- package/dist/chunks/{table-ngrghrfy9qsk6091.js.map → table-htqdo9dgy8c6hwuq.js.map} +1 -1
- package/dist/chunks/{tabs-mkhf1uemgr3ij0ps.js → tabs-fdkhdhv8kvnpp8nt.js} +2 -2
- package/dist/chunks/{tabs-mkhf1uemgr3ij0ps.js.map → tabs-fdkhdhv8kvnpp8nt.js.map} +1 -1
- package/dist/chunks/{toast-ksnnyrf2o8yfvc3m.js → toast-evn3ce20j18hpyqt.js} +3 -3
- package/dist/chunks/{toast-ksnnyrf2o8yfvc3m.js.map → toast-evn3ce20j18hpyqt.js.map} +1 -1
- package/dist/chunks/{tooltip-odudhkxe282wxinq.js → tooltip-fjxy4s4l75hjxp1x.js} +9 -5
- package/dist/chunks/{tooltip-odudhkxe282wxinq.js.map → tooltip-fjxy4s4l75hjxp1x.js.map} +1 -1
- package/dist/chunks/{vendor-base-ui-ie71jahf0czyf58j.js → vendor-base-ui-epfrwb4nfbd4btaz.js} +17 -17
- package/dist/chunks/{vendor-base-ui-ie71jahf0czyf58j.js.map → vendor-base-ui-epfrwb4nfbd4btaz.js.map} +1 -1
- package/dist/code.js +1 -1
- package/dist/components/autocomplete.js +1 -1
- package/dist/components/breadcrumbs.js +1 -1
- package/dist/components/button.js +1 -1
- package/dist/components/chart.js +3 -2
- package/dist/components/checkbox.js +1 -1
- package/dist/components/clipboard-text.js +1 -1
- package/dist/components/collapsible.js +1 -1
- package/dist/components/combobox.js +1 -1
- package/dist/components/command-palette.js +1 -1
- package/dist/components/dialog.js +1 -1
- package/dist/components/dropdown.js +1 -1
- package/dist/components/empty.js +1 -1
- package/dist/components/field.js +1 -1
- package/dist/components/input-group.js +1 -1
- package/dist/components/input.js +3 -3
- package/dist/components/label.js +1 -1
- package/dist/components/layer-card.js +1 -1
- package/dist/components/link.js +1 -1
- package/dist/components/menubar.js +1 -1
- package/dist/components/meter.js +1 -1
- package/dist/components/pagination.js +1 -1
- package/dist/components/popover.js +1 -1
- package/dist/components/radio.js +1 -1
- package/dist/components/select.js +1 -1
- package/dist/components/sensitive-input.js +1 -1
- package/dist/components/sidebar.js +1 -1
- package/dist/components/surface.js +1 -1
- package/dist/components/switch.js +1 -1
- package/dist/components/table.js +1 -1
- package/dist/components/tabs.js +1 -1
- package/dist/components/toast.js +2 -2
- package/dist/components/tooltip.js +1 -1
- package/dist/index.js +109 -108
- package/dist/primitives/accordion.js +1 -1
- package/dist/primitives/alert-dialog.js +1 -1
- package/dist/primitives/autocomplete.js +1 -1
- package/dist/primitives/avatar.js +1 -1
- package/dist/primitives/button.js +1 -1
- package/dist/primitives/checkbox-group.js +1 -1
- package/dist/primitives/checkbox.js +1 -1
- package/dist/primitives/collapsible.js +1 -1
- package/dist/primitives/combobox.js +1 -1
- package/dist/primitives/context-menu.js +1 -1
- package/dist/primitives/csp-provider.js +1 -1
- package/dist/primitives/dialog.js +1 -1
- package/dist/primitives/direction-provider.js +1 -1
- package/dist/primitives/drawer.js +1 -1
- package/dist/primitives/field.js +1 -1
- package/dist/primitives/fieldset.js +1 -1
- package/dist/primitives/form.js +1 -1
- package/dist/primitives/input.js +1 -1
- package/dist/primitives/menu.js +1 -1
- package/dist/primitives/menubar.js +1 -1
- package/dist/primitives/meter.js +1 -1
- package/dist/primitives/navigation-menu.js +1 -1
- package/dist/primitives/number-field.js +1 -1
- package/dist/primitives/otp-field.js +1 -1
- package/dist/primitives/popover.js +1 -1
- package/dist/primitives/preview-card.js +1 -1
- package/dist/primitives/progress.js +1 -1
- package/dist/primitives/radio-group.js +1 -1
- package/dist/primitives/radio.js +1 -1
- package/dist/primitives/scroll-area.js +1 -1
- package/dist/primitives/select.js +1 -1
- package/dist/primitives/separator.js +1 -1
- package/dist/primitives/slider.js +1 -1
- package/dist/primitives/switch.js +1 -1
- package/dist/primitives/tabs.js +1 -1
- package/dist/primitives/toast.js +1 -1
- package/dist/primitives/toggle-group.js +1 -1
- package/dist/primitives/toggle.js +1 -1
- package/dist/primitives/toolbar.js +1 -1
- package/dist/primitives/tooltip.js +1 -1
- package/dist/primitives.js +1 -1
- package/dist/src/components/chart/Color.d.ts +11 -0
- package/dist/src/components/chart/Color.d.ts.map +1 -1
- package/dist/src/components/chart/SankeyChart.d.ts +89 -0
- package/dist/src/components/chart/SankeyChart.d.ts.map +1 -0
- package/dist/src/components/chart/index.d.ts +1 -0
- package/dist/src/components/chart/index.d.ts.map +1 -1
- package/dist/src/components/combobox/combobox.d.ts +3 -0
- package/dist/src/components/combobox/combobox.d.ts.map +1 -1
- package/dist/src/components/layer-card/layer-card.d.ts +4 -7
- package/dist/src/components/layer-card/layer-card.d.ts.map +1 -1
- package/dist/src/components/link/link.d.ts +12 -1
- package/dist/src/components/link/link.d.ts.map +1 -1
- package/dist/src/components/tooltip/tooltip.d.ts.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/utils/link-provider.d.ts +54 -0
- package/dist/src/utils/link-provider.d.ts.map +1 -1
- package/dist/styles/kumo-standalone.css +1 -1
- package/package.json +2 -2
- package/dist/chunks/Legend-ibjxhfm9pn2vrb6f.js +0 -430
- package/dist/chunks/Legend-ibjxhfm9pn2vrb6f.js.map +0 -1
- package/dist/chunks/command-palette-kgiso245exdons4r.js.map +0 -1
- package/dist/chunks/layer-card-ikm31xemd70w3lru.js.map +0 -1
- package/dist/chunks/link-m9hlspftl34nseme.js.map +0 -1
package/dist/chunks/{input-group-k1xa9cu8ochl1arh.js.map → input-group-5luo0442jgsie018.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-group-k1xa9cu8ochl1arh.js","sources":["../../src/components/input-group/context.ts","../../src/components/input-group/input-group-input.tsx","../../src/components/input-group/input-group-button.tsx","../../src/components/input-group/input-group-addon.tsx","../../src/components/input-group/input-group-suffix.tsx","../../src/components/input-group/input-group.tsx"],"sourcesContent":["import {\n Children,\n createContext,\n isValidElement,\n useContext,\n type HTMLAttributes,\n type ReactNode,\n} from \"react\";\nimport type { KumoInputSize } from \"../input/input\";\nimport type { FieldProps } from \"../field/field\";\n\n// Spacing model\n//\n// Each element type has a fixed outer padding. The container uses has-[] CSS\n// to reduce the input's padding on sides that touch an addon.\n//\n// Input outer: px-3 (12px base) — full padding when at the edge\n// Input seam: pl-2 / pr-2 (8px base) — applied by container has-[]\n// Addon outer: pl-2 / pr-2 (8px base) — on the container-edge side\n// Addon seam: nothing — input owns the gap entirely\n//\n// has-[] rules on the container override [&_input]:pl-{seam} when a start\n// addon is present, and [&_input]:pr-{seam} when an end addon is present.\n\nexport interface InputGroupSizeTokens {\n /** Full outer padding — matches standalone Input (e.g. px-3). */\n inputOuter: string;\n /**\n * Directional outer padding for Addon at the container edge.\n *\n * These MUST be static pl-/pr- strings (not derived at runtime via\n * `\"px-N\".replace(…)`) so Tailwind JIT can detect them during its\n * source-file scan. Dynamic string construction produces class names\n * that never appear as literals, so Tailwind never generates the CSS.\n */\n addonOuterStart: string;\n addonOuterEnd: string;\n /**\n * Reduced outer padding when the Addon contains a Button.\n * Buttons have their own internal padding, so the Addon can use\n * less outer padding to keep the visual gap balanced.\n */\n addonButtonOuterStart: string;\n addonButtonOuterEnd: string;\n /** pr- for suffix when no end addon. */\n suffixPad: string;\n fontSize: string;\n /** Icon size in px. */\n iconSize: number;\n}\n\nexport const INPUT_GROUP_SIZE: Record<KumoInputSize, InputGroupSizeTokens> = {\n xs: {\n inputOuter: \"px-1.5\",\n addonOuterStart: \"pl-1.5\",\n addonOuterEnd: \"pr-1.5\",\n addonButtonOuterStart: \"pl-1\",\n addonButtonOuterEnd: \"pr-1\",\n suffixPad: \"pr-1.5\",\n fontSize: \"text-xs\",\n iconSize: 10,\n },\n sm: {\n inputOuter: \"px-2\",\n addonOuterStart: \"pl-1.5\",\n addonOuterEnd: \"pr-1.5\",\n addonButtonOuterStart: \"pl-1\",\n addonButtonOuterEnd: \"pr-1\",\n suffixPad: \"pr-2\",\n fontSize: \"text-xs\",\n iconSize: 13,\n },\n base: {\n inputOuter: \"px-3\",\n addonOuterStart: \"pl-2\",\n addonOuterEnd: \"pr-2\",\n addonButtonOuterStart: \"pl-1\",\n addonButtonOuterEnd: \"pr-1\",\n suffixPad: \"pr-3\",\n fontSize: \"text-base\",\n iconSize: 18,\n },\n lg: {\n inputOuter: \"px-4\",\n addonOuterStart: \"pl-2.5\",\n addonOuterEnd: \"pr-2.5\",\n addonButtonOuterStart: \"pl-1.5\",\n addonButtonOuterEnd: \"pr-1.5\",\n suffixPad: \"pr-4\",\n fontSize: \"text-base\",\n iconSize: 20,\n },\n};\n\n// Build the has-[] container classes that reduce input padding when addons\n// are present. These are static strings so Tailwind JIT can detect them.\nexport const INPUT_GROUP_HAS_CLASSES: Record<KumoInputSize, string> = {\n xs: [\n \"has-[[data-slot=input-group-addon-start]]:[&_input]:pl-1\",\n \"has-[[data-slot=input-group-addon-end]]:[&_input]:pr-1\",\n ].join(\" \"),\n sm: [\n \"has-[[data-slot=input-group-addon-start]]:[&_input]:pl-1.5\",\n \"has-[[data-slot=input-group-addon-end]]:[&_input]:pr-1.5\",\n ].join(\" \"),\n base: [\n \"has-[[data-slot=input-group-addon-start]]:[&_input]:pl-2\",\n \"has-[[data-slot=input-group-addon-end]]:[&_input]:pr-2\",\n ].join(\" \"),\n lg: [\n \"has-[[data-slot=input-group-addon-start]]:[&_input]:pl-2.5\",\n \"has-[[data-slot=input-group-addon-end]]:[&_input]:pr-2.5\",\n ].join(\" \"),\n};\n\n// Context\n\n/**\n * Props for `InputGroup.Root`. Focus mode is auto-detected from children\n * (see `detectFocusMode`), so it is not part of the public or internal API.\n */\nexport interface InputGroupRootPropsInternal\n extends HTMLAttributes<HTMLElement>,\n Partial<\n Pick<\n FieldProps,\n \"label\" | \"description\" | \"error\" | \"required\" | \"labelTooltip\"\n >\n > {\n size?: KumoInputSize | undefined;\n disabled?: boolean;\n}\n\n/** Public InputGroup.Root props — identical to the internal type. */\nexport type InputGroupRootProps = InputGroupRootPropsInternal;\n\nexport interface InputGroupContextValue {\n size?: KumoInputSize;\n focusMode: \"container\" | \"individual\" | \"hybrid\";\n disabled: boolean;\n error?: FieldProps[\"error\"];\n /** Auto-generated id for the input element; used by the invisible label overlay. */\n inputId: string;\n}\n\nexport const InputGroupContext = createContext<InputGroupContextValue | null>(\n null,\n);\n\n/**\n * Set to `true` by `InputGroup.Addon` so that `InputGroup.Button` can detect\n * whether it's wrapped in an Addon. Ghost buttons should always live inside\n * an Addon for correct spacing.\n */\nexport const InputGroupAddonContext = createContext(false);\n\n/**\n * Reads InputGroupContext and warns in development when the context is null\n * (i.e. when a sub-component is rendered outside of `<InputGroup>`).\n */\nexport function useInputGroupContext(componentName: string) {\n const context = useContext(InputGroupContext);\n if (process.env.NODE_ENV !== \"production\" && !context) {\n console.warn(\n `<InputGroup.${componentName}> must be used within <InputGroup>. Falling back to default values.`,\n );\n }\n return context;\n}\n\n/**\n * Partitions InputGroup children for hybrid focus mode.\n *\n * Container zone: Addon, Input, Suffix, text nodes — everything that should\n * share a single container-style border.\n *\n * Individual zone: Direct `InputGroup.Button` elements that manage their own\n * border and focus ring.\n *\n * Uses `displayName` comparison to identify elements, avoiding circular\n * imports between `context.ts` and the sub-component files.\n */\nexport function partitionChildren(children: ReactNode): {\n containerZone: ReactNode[];\n individualZone: ReactNode[];\n} {\n const containerZone: ReactNode[] = [];\n const individualZone: ReactNode[] = [];\n\n Children.forEach(children, (child) => {\n if (\n isValidElement(child) &&\n (child.type as { displayName?: string })?.displayName ===\n \"InputGroup.Button\"\n ) {\n individualZone.push(child);\n } else {\n containerZone.push(child);\n }\n });\n\n return { containerZone, individualZone };\n}\n\n/**\n * Analyzes the direct children of `InputGroup` to determine the focus mode.\n *\n * Returns `\"hybrid\"` when BOTH an `InputGroup.Addon` AND a non-ghost direct\n * `InputGroup.Button` are present. In hybrid mode, Addon+Input share a\n * container-style border while Buttons get individual borders.\n *\n * Returns `\"individual\"` when a non-ghost direct `InputGroup.Button` is\n * present WITHOUT any `InputGroup.Addon`. This signals a toolbar/pagination\n * layout where each element manages its own focus ring.\n *\n * Returns `\"container\"` (default) in all other cases — the container owns a\n * single shared focus ring.\n *\n * Uses `displayName` comparison to identify elements, avoiding circular\n * imports between `context.ts` and the sub-component files.\n */\nexport function detectFocusMode(\n children: ReactNode,\n): \"container\" | \"individual\" | \"hybrid\" {\n let hasNonGhostDirectButton = false;\n let hasAddon = false;\n\n Children.forEach(children, (child) => {\n if (!isValidElement(child)) return;\n\n // Identify components by displayName to avoid circular imports.\n const type = child.type;\n const displayName =\n typeof type === \"function\" || typeof type === \"object\"\n ? (type as { displayName?: string }).displayName\n : undefined;\n\n if (displayName === \"InputGroup.Addon\") {\n hasAddon = true;\n return;\n }\n\n if (displayName !== \"InputGroup.Button\") return;\n\n // A direct-child Button is by definition NOT inside an Addon (Addon's\n // children are children of the Addon element, not of InputGroup).\n // Check whether the variant is explicitly non-ghost.\n const variant = (child.props as { variant?: string }).variant;\n if (variant !== undefined && variant !== \"ghost\") {\n hasNonGhostDirectButton = true;\n }\n });\n\n if (hasNonGhostDirectButton && hasAddon) return \"hybrid\";\n if (hasNonGhostDirectButton) return \"individual\";\n return \"container\";\n}\n","import { forwardRef } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Input as InputExternal, type InputProps } from \"../input/input\";\nimport { useInputGroupContext, INPUT_GROUP_SIZE } from \"./context\";\n\n/** Props for InputGroup.Input — omits Field props since InputGroup handles them. */\nexport type InputGroupInputProps = Omit<\n InputProps,\n \"label\" | \"labelTooltip\" | \"description\" | \"error\" | \"size\" | \"disabled\"\n>;\n\n/**\n * Text input that inherits size, disabled, and error state from InputGroup context.\n * Automatically sets `aria-invalid` when parent has an error.\n */\nexport const Input = forwardRef<HTMLInputElement, InputGroupInputProps>(\n (props, ref) => {\n const context = useInputGroupContext(\"Input\");\n\n // Warn when props that belong on <InputGroup> are passed directly\n if (process.env.NODE_ENV !== \"production\" && context) {\n if ((props as any).size !== undefined) {\n console.warn(\n \"InputGroup.Input: Set `size` on <InputGroup> instead of <InputGroup.Input>.\",\n );\n }\n if ((props as any).disabled !== undefined) {\n console.warn(\n \"InputGroup.Input: Set `disabled` on <InputGroup> instead of <InputGroup.Input>.\",\n );\n }\n if ((props as any).label !== undefined) {\n console.warn(\n \"InputGroup.Input: Use the `label` prop on <InputGroup> instead of <InputGroup.Input>.\",\n );\n }\n if ((props as any).description !== undefined) {\n console.warn(\n \"InputGroup.Input: Use <InputGroup.Suffix> instead of passing `description` to <InputGroup.Input>.\",\n );\n }\n }\n\n const size = context?.size ?? \"base\";\n const tokens = INPUT_GROUP_SIZE[size];\n const isIndividual = context?.focusMode === \"individual\";\n\n // Auto-set aria-invalid when error is present in context\n const hasError = Boolean(context?.error);\n\n // Use explicit id if provided, otherwise fall back to context id\n // (links the input to the invisible label overlay for click-to-focus).\n const inputId = props.id ?? context?.inputId;\n\n return (\n <InputExternal\n ref={ref}\n size={context?.size}\n disabled={context?.disabled || (props as any).disabled}\n aria-invalid={hasError || props[\"aria-invalid\"]}\n {...props}\n id={inputId}\n className={cn(\n // Base input layout: fill height, allow shrinking, strip native border/radius\n \"flex h-full min-w-0 grow items-center rounded-none border-0 bg-transparent font-sans\",\n // Always use full outer padding — the container's has-[] rules reduce\n // pl/pr to inputSeam on sides that touch an addon.\n tokens.inputOuter,\n // Truncate overflowing text with \"…\" instead of expanding the input\n \"text-ellipsis\",\n // Individual mode: each element owns its own border instead of sharing a container ring\n isIndividual\n ? [\n // Own border replaces the container's shared ring\n \"relative ring-0 border border-kumo-line\",\n // Inherit border-radius only on outer edges; inner edges are flat\n \"first:rounded-l-[inherit] last:rounded-r-[inherit]\",\n // Collapse double borders between adjacent elements\n \"not-first:border-l-0\",\n // Hovered element renders above idle siblings to show full border\n \"hover:z-[1] hover:border-kumo-line\",\n // Focused element renders above hovered siblings for focus indicator\n \"focus:z-[2] focus:border-kumo-line focus:outline focus:-outline-offset-1\",\n ].join(\" \")\n : // Container mode: kill all focus indicators — the container handles them\n // z-[1] lifts the input above the invisible label overlay so cursor/selection work\n \"relative z-[1] ring-0! shadow-none outline-none focus:ring-0! focus:outline-none\",\n props.className,\n )}\n />\n );\n },\n);\nInput.displayName = \"InputGroup.Input\";\n","import React, {\n forwardRef,\n useContext,\n type PropsWithChildren,\n type ReactNode,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { type ButtonProps, Button as ButtonExternal } from \"../button/button\";\nimport { Tooltip, type KumoTooltipSide } from \"../tooltip/tooltip\";\nimport type { KumoInputSize } from \"../input/input\";\nimport {\n INPUT_GROUP_SIZE,\n InputGroupAddonContext,\n useInputGroupContext,\n} from \"./context\";\n\n/**\n * In container mode, buttons render \"one size down\" so they stay visually\n * subordinate to the input. In individual mode the size passes through\n * unchanged (pagination / toolbar buttons should match the input height).\n */\nconst COMPACT_BUTTON_SIZE: Record<KumoInputSize, KumoInputSize> = {\n xs: \"xs\",\n sm: \"xs\",\n base: \"sm\",\n lg: \"base\",\n};\n\nexport type InputGroupButtonProps = ButtonProps & {\n /**\n * When provided, wraps the button in a `Tooltip` showing this content on hover.\n * Automatically sets `aria-label` from a string value when no `aria-label` is set.\n *\n * @example\n * ```tsx\n * <InputGroup.Addon align=\"end\">\n * <InputGroup.Button tooltip=\"Query language help\" aria-label=\"Query language help\">\n * <QuestionIcon size={16} />\n * </InputGroup.Button>\n * </InputGroup.Addon>\n * ```\n */\n tooltip?: ReactNode;\n /**\n * Preferred side for the tooltip popup.\n * @default \"bottom\"\n */\n tooltipSide?: KumoTooltipSide;\n};\n\n/**\n * Button for secondary actions rendered inside `InputGroup.Addon`\n * (toggle, copy, help).\n *\n * In `focusMode=\"container\"` (default), renders as a compact ghost button\n * subordinate to the input. In `focusMode=\"individual\"`, renders as a full\n * standalone button with its own focus ring, matching toolbar/pagination usage.\n *\n * Pass a `tooltip` prop to show a tooltip on hover.\n */\nexport const Button = forwardRef<\n HTMLButtonElement,\n PropsWithChildren<InputGroupButtonProps>\n>(\n (\n {\n children,\n className,\n variant,\n size,\n disabled,\n tooltip,\n tooltipSide = \"bottom\",\n icon,\n ...props\n }: PropsWithChildren<InputGroupButtonProps>,\n ref: React.ForwardedRef<HTMLButtonElement>,\n ) => {\n const context = useInputGroupContext(\"Button\");\n const isInsideAddon = useContext(InputGroupAddonContext);\n const isDisabled = disabled ?? context?.disabled;\n const isIndividual =\n context?.focusMode === \"individual\" || context?.focusMode === \"hybrid\";\n const effectiveVariant = variant ?? \"ghost\";\n\n if (\n process.env.NODE_ENV !== \"production\" &&\n context &&\n effectiveVariant === \"ghost\" &&\n !isInsideAddon\n ) {\n console.warn(\n \"InputGroup.Button: Ghost buttons should be wrapped in <InputGroup.Addon> for correct spacing.\",\n );\n }\n\n if (\n process.env.NODE_ENV !== \"production\" &&\n context &&\n size !== undefined\n ) {\n console.warn(\n \"InputGroup.Button: Set `size` on <InputGroup> instead of <InputGroup.Button>.\",\n );\n }\n\n // Derive aria-label from tooltip string when the button has no explicit label.\n // Icon-only buttons require an aria-label for a11y.\n const tooltipAriaLabel =\n typeof tooltip === \"string\" && !props[\"aria-label\"] ? tooltip : undefined;\n\n // Pre-render the icon with the context-derived size so it matches the\n // Addon icon sizing (e.g. 18px at \"base\"). Without this, Button's\n // internal renderIconNode renders `<Icon />` with no size prop,\n // falling back to CSS font-size (~14px).\n const contextIconSize = context\n ? INPUT_GROUP_SIZE[context.size ?? \"base\"].iconSize\n : undefined;\n\n const sizedIcon =\n icon &&\n contextIconSize &&\n (typeof icon === \"function\" ||\n (typeof icon === \"object\" &&\n icon !== null &&\n !React.isValidElement(icon)))\n ? React.createElement(icon as React.ComponentType<{ size?: number }>, {\n size: contextIconSize,\n })\n : icon;\n\n const btn = (\n <ButtonExternal\n ref={ref}\n type=\"button\"\n disabled={isDisabled}\n aria-label={tooltipAriaLabel}\n {...props}\n icon={sizedIcon}\n variant={variant ?? \"ghost\"}\n // Individual: use the group's size directly so buttons match the input height.\n // Container: render one size down so the button stays subordinate to the input.\n size={\n size ??\n (isIndividual\n ? (context?.size ?? \"sm\")\n : (COMPACT_BUTTON_SIZE[context?.size ?? \"base\"] ?? \"sm\"))\n }\n className={cn(\n // Ensure clicks register even when parent has pointer-events-none (e.g. disabled overlay)\n \"pointer-events-auto\",\n // Individual mode: each button owns its own border and focus indicator\n isIndividual && [\n // Own border replaces the container's shared ring; force full height\n \"relative h-full! rounded-none ring-0 border border-kumo-line\",\n // Inherit border-radius only on outer edges; inner edges are flat\n \"first:rounded-l-[inherit] last:rounded-r-[inherit]\",\n // Collapse double borders between adjacent elements\n \"not-first:border-l-0\",\n // Hovered element renders above idle siblings to show full border\n \"hover:z-[1]\",\n // Focused element renders above hovered siblings for focus indicator\n \"focus:z-[2] focus:border-kumo-line focus:outline focus:-outline-offset-1\",\n // Suppress the base Button's focus ring so only our outline shows\n \"focus-visible:ring-2 focus-visible:ring-kumo-focus\",\n // Match the group's disabled visual treatment\n \"disabled:bg-kumo-overlay disabled:text-kumo-inactive!\",\n ],\n className,\n )}\n >\n {children}\n </ButtonExternal>\n );\n\n if (tooltip) {\n return (\n <Tooltip content={tooltip} side={tooltipSide} asChild>\n {btn}\n </Tooltip>\n );\n }\n\n return btn;\n },\n);\nButton.displayName = \"InputGroup.Button\";\n","import {\n Children,\n cloneElement,\n forwardRef,\n isValidElement,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport {\n useInputGroupContext,\n INPUT_GROUP_SIZE,\n InputGroupAddonContext,\n} from \"./context\";\nimport { Button } from \"./input-group-button\";\n\nexport interface InputGroupAddonProps {\n /** Position relative to the input. @default \"start\" */\n align?: \"start\" | \"end\";\n /** Additional CSS classes. */\n className?: string;\n /** Addon content: icons, buttons, spinners, text. */\n children?: ReactNode;\n}\n\n/**\n * Container for icons, text, or compact buttons positioned at the start or end\n * of the input. Automatically sizes icon children to match the input size.\n */\nexport const Addon = forwardRef<HTMLDivElement, InputGroupAddonProps>(\n ({ align = \"start\", className, children }, ref) => {\n const context = useInputGroupContext(\"Addon\");\n\n const size = context?.size ?? \"base\";\n const tokens = INPUT_GROUP_SIZE[size];\n\n // Inject size into direct icon children that don't already have one set.\n // Skips buttons (which have their own size handling) and non-element nodes.\n // Also tracks whether a Button is present so we can reduce outer padding.\n let containsButton = false;\n const sizedChildren = Children.map(children, (child) => {\n if (!isValidElement(child)) return child;\n if (child.type === Button) {\n containsButton = true;\n return child;\n }\n const props = child.props as { size?: unknown };\n if (props.size !== undefined) return child;\n return cloneElement(child as ReactElement<{ size?: number }>, {\n size: tokens.iconSize,\n });\n });\n\n // Always use flex-based positioning. CSS order controls visual placement.\n return (\n <div\n ref={ref}\n data-slot={\n align === \"start\"\n ? \"input-group-addon-start\"\n : \"input-group-addon-end\"\n }\n className={cn(\n \"relative z-[1] pointer-events-none flex shrink-0 items-center gap-1.5\",\n \"text-kumo-subtle\",\n tokens.fontSize,\n \"*:pointer-events-auto\",\n align === \"start\"\n ? cn(\n \"-order-1\",\n containsButton\n ? tokens.addonButtonOuterStart\n : tokens.addonOuterStart,\n \"pr-0\",\n )\n : cn(\n \"order-1\",\n \"pl-0\",\n containsButton\n ? tokens.addonButtonOuterEnd\n : tokens.addonOuterEnd,\n ),\n className,\n )}\n >\n <InputGroupAddonContext.Provider value={true}>\n {sizedChildren}\n </InputGroupAddonContext.Provider>\n </div>\n );\n },\n);\nAddon.displayName = \"InputGroup.Addon\";\n","import { forwardRef, type ReactNode } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useInputGroupContext, INPUT_GROUP_SIZE } from \"./context\";\n\nexport interface InputGroupSuffixProps {\n /** Additional CSS classes. */\n className?: string;\n /** Suffix content (e.g., \".workers.dev\"). */\n children?: ReactNode;\n}\n\n/**\n * Inline suffix that flows seamlessly next to the typed input value.\n * Input width adjusts automatically via CSS `field-sizing: content`.\n */\nexport const Suffix = forwardRef<HTMLDivElement, InputGroupSuffixProps>(\n ({ className, children }, ref) => {\n const context = useInputGroupContext(\"Suffix\");\n\n const size = context?.size ?? \"base\";\n const tokens = INPUT_GROUP_SIZE[size];\n\n return (\n <div\n ref={ref}\n data-slot=\"input-group-suffix\"\n className={cn(\n \"pointer-events-none flex min-w-0 grow select-none items-center text-kumo-subtle\",\n tokens.fontSize,\n tokens.suffixPad,\n className,\n )}\n >\n <span className=\"truncate\">{children}</span>\n </div>\n );\n },\n);\nSuffix.displayName = \"InputGroup.Suffix\";\n","import {\n forwardRef,\n useId,\n useMemo,\n type ComponentPropsWithoutRef,\n type PropsWithChildren,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { inputVariants } from \"../input/input\";\nimport { Field } from \"../field/field\";\nimport {\n InputGroupContext,\n INPUT_GROUP_HAS_CLASSES,\n detectFocusMode,\n partitionChildren,\n type InputGroupRootPropsInternal,\n} from \"./context\";\nimport { Input } from \"./input-group-input\";\nimport { Button } from \"./input-group-button\";\nimport { Addon } from \"./input-group-addon\";\nimport { Suffix } from \"./input-group-suffix\";\n\nexport { type InputGroupRootProps } from \"./context\";\nexport { type InputGroupInputProps } from \"./input-group-input\";\nexport { type InputGroupButtonProps } from \"./input-group-button\";\nexport { type InputGroupAddonProps } from \"./input-group-addon\";\nexport { type InputGroupSuffixProps } from \"./input-group-suffix\";\n\nexport const KUMO_INPUT_GROUP_VARIANTS = {\n size: {\n xs: {\n classes: \"h-6 text-xs\",\n description: \"Extra small size.\",\n },\n sm: {\n classes: \"h-7 text-xs\",\n description: \"Small size.\",\n },\n base: {\n classes: \"h-9 text-base\",\n description: \"Default size.\",\n },\n lg: {\n classes: \"h-11 text-base\",\n description: \"Large size.\",\n },\n },\n} as const;\n\nexport const KUMO_INPUT_GROUP_DEFAULT_VARIANTS = {\n size: \"base\",\n} as const;\n\n/**\n * Compound input component for building inputs with icons, addons, inline\n * suffixes, and action buttons. Accepts Field props and wraps content in\n * Field when label is provided.\n *\n * Renders as `<label>` only in standalone container mode (single input, no\n * sibling buttons) so clicking empty space focuses the input. Otherwise\n * renders as `<div>` to avoid nested `<label>` (when Field provides one) or\n * the browser's `:hover` propagation from `<label>` to its first labelable\n * descendant (when multiple labelable controls are siblings).\n *\n * @note Do not wrap InputGroup inside an external Field without using the `label` prop —\n * this creates invalid nested `<label>` elements. Use InputGroup's own `label` prop instead.\n *\n * @example\n * ```tsx\n * <InputGroup label=\"Email\" error={{ message: \"Invalid\", match: true }}>\n * <InputGroup.Addon><EnvelopeIcon /></InputGroup.Addon>\n * <InputGroup.Input placeholder=\"you@example.com\" />\n * </InputGroup>\n * ```\n *\n * @example\n * ```tsx\n * <InputGroup>\n * <InputGroup.Input placeholder=\"my-worker\" />\n * <InputGroup.Suffix>.workers.dev</InputGroup.Suffix>\n * </InputGroup>\n * ```\n */\nconst Root = forwardRef<\n HTMLElement,\n PropsWithChildren<InputGroupRootPropsInternal>\n>(\n (\n {\n size = \"base\",\n children,\n className,\n disabled = false,\n label,\n description,\n error,\n required,\n labelTooltip,\n ...rest\n },\n forwardedRef,\n ) => {\n const inputId = useId();\n const focusMode = detectFocusMode(children);\n\n const contextValue = useMemo(\n () => ({\n size,\n focusMode,\n disabled,\n error,\n inputId,\n }),\n [size, focusMode, disabled, error, inputId],\n );\n\n // When label is provided, Field already renders a <label> with htmlFor\n // that handles click-to-focus. Using <div> avoids nested <label> elements\n // (invalid HTML with undefined assistive technology behavior).\n // When standalone (no label), a native <label> preserves click-to-focus.\n const containerClassName = cn(\n // Establish positioning context and make the whole area a click target\n \"relative w-full cursor-text\",\n // inputVariants provides base ring-kumo-line; must come before state overrides\n inputVariants({ size }),\n // Subtle drop shadow to separate the group from the page surface\n \"shadow-xs\",\n // Disabled state: prevent interaction and dim the entire group\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n // Container mode: clip children to rounded corners and show a shared focus ring\n // Individual mode: disable container ring/shadow so each child owns its own border\n focusMode === \"container\"\n ? [\n \"overflow-hidden\",\n // Focus state must come AFTER inputVariants to override ring-kumo-line\n \"focus-within:ring-kumo-focus\",\n ]\n : // isolate creates a new stacking context so z-index in children doesn't leak out\n \"isolate overflow-visible ring-0 shadow-none\",\n // Error state must also come after inputVariants\n \"has-[input[aria-invalid=true]]:ring-kumo-danger\",\n // Reset horizontal padding — children handle their own spacing\n \"px-0\",\n // Horizontal layout with no gap — children control their own internal spacing\n \"flex items-center gap-0\",\n // When a suffix is present, let the input shrink to its content width\n // so the suffix stays visually adjacent\n \"has-[[data-slot=input-group-suffix]]:[&_input]:[field-sizing:content]\",\n \"has-[[data-slot=input-group-suffix]]:[&_input]:max-w-full\",\n \"has-[[data-slot=input-group-suffix]]:[&_input]:grow-0\",\n \"has-[[data-slot=input-group-suffix]]:[&_input]:pr-0\",\n // Size-specific padding adjustments when addons or suffixes are present\n INPUT_GROUP_HAS_CLASSES[size],\n // Reset bottom margin to avoid inherited spacing from parent <label> styles\n \"!mb-0\",\n className,\n );\n\n // Data attributes drive CSS selectors in kumo-binding.css (focus outline)\n // and enable child components to query their parent's state.\n const dataProps = {\n \"data-slot\": \"input-group\" as const,\n \"data-focus-mode\": focusMode,\n \"data-disabled\": disabled ? (\"\" as const) : undefined,\n };\n\n // Hybrid mode: splits children into two rendering zones:\n // 1. Container zone (Addon + Input + Suffix) — shares a single border/ring\n // 2. Individual zone (standalone Buttons) — each button owns its own border\n // This lets inputs and addons look unified while buttons remain independent.\n if (focusMode === \"hybrid\") {\n // Partition children by type: addons/inputs/suffixes → container, buttons → individual\n const { containerZone, individualZone } = partitionChildren(children);\n\n // Override focusMode to \"container\" for children inside the zone\n // so InputGroup.Input uses container-mode styling (ring-0!, no own border).\n const containerZoneContext = {\n ...contextValue,\n focusMode: \"container\" as const,\n };\n\n const hybridContent = (\n <>\n {/* Container zone wrapper — shares a single border/ring */}\n <InputGroupContext.Provider value={containerZoneContext}>\n <div\n data-slot=\"input-group-container-zone\"\n className={cn(\n // Base input sizing/shape from shared variant function\n inputVariants({ size }),\n // Clip children to rounded corners within the zone\n \"overflow-hidden\",\n // Show red ring on validation error\n \"has-[input[aria-invalid=true]]:ring-kumo-danger\",\n // Reset horizontal padding — children handle their own spacing\n \"px-0\",\n // Fill available width but allow shrinking when sibling buttons are present\n \"flex min-w-0 flex-1 items-center gap-0\",\n // Use a clean 1px CSS border instead of ring+shadow from inputVariants\n // so the zone matches adjacent individual-mode buttons exactly.\n \"ring-0 shadow-none\",\n \"border border-kumo-line\",\n \"focus-within:ring-1 focus-within:ring-kumo-focus\",\n // Collapse double borders between zone and adjacent individual-mode button\n \"not-first:border-l-0\",\n // Inherit border-radius from the outer container on outer edges only;\n // inner edges are flat so they butt cleanly against sibling buttons\n \"first:rounded-l-[inherit] last:rounded-r-[inherit] rounded-none\",\n // Size-specific padding adjustments when addons or suffixes are present\n INPUT_GROUP_HAS_CLASSES[size],\n // When a suffix is present, let the input shrink to its content width\n \"has-[[data-slot=input-group-suffix]]:[&_input]:[field-sizing:content]\",\n \"has-[[data-slot=input-group-suffix]]:[&_input]:max-w-full\",\n \"has-[[data-slot=input-group-suffix]]:[&_input]:grow-0\",\n \"has-[[data-slot=input-group-suffix]]:[&_input]:pr-0\",\n )}\n >\n {/* When label exists, an invisible <label> overlay enables click-to-focus\n inside the container zone without nesting visible <label> elements */}\n {label && (\n // eslint-disable-next-line jsx-a11y/label-has-associated-control -- invisible overlay for click-to-focus; the visible Field label handles a11y\n <label\n htmlFor={inputId}\n // Positioned behind children (z-0) so it catches clicks on empty space\n className=\"absolute inset-0 z-0 cursor-text !mb-0\"\n aria-hidden=\"true\"\n />\n )}\n {containerZone}\n </div>\n </InputGroupContext.Provider>\n {/* Individual zone — buttons with their own borders */}\n {individualZone}\n </>\n );\n\n // Hybrid always uses a <div> container (never <label>) because\n // individual-zone buttons are siblings — wrapping them in a <label>\n // would be semantically incorrect.\n const hybridContainer = (\n <InputGroupContext.Provider value={contextValue}>\n <div\n ref={forwardedRef as React.Ref<HTMLDivElement>}\n {...dataProps}\n className={containerClassName}\n {...rest}\n >\n {hybridContent}\n </div>\n </InputGroupContext.Provider>\n );\n\n if (label) {\n return (\n <Field\n label={label}\n description={description}\n error={error}\n required={required}\n labelTooltip={labelTooltip}\n >\n {hybridContainer}\n </Field>\n );\n }\n\n return hybridContainer;\n }\n\n // Container / Individual mode (non-hybrid)\n // Use <label> only when there's exactly one labelable descendant; otherwise <label> would propagate :hover to its first labelable descendant.\n const useLabelContainer = !label && focusMode === \"container\";\n const container = (\n <InputGroupContext.Provider value={contextValue}>\n {/* When label is set, use <div> to avoid nested <label> (Field provides one).\n An invisible <label> overlay handles click-to-focus on empty space. */}\n {label ? (\n <div\n ref={forwardedRef as React.Ref<HTMLDivElement>}\n {...dataProps}\n className={containerClassName}\n {...rest}\n >\n {/* eslint-disable-next-line jsx-a11y/label-has-associated-control -- invisible overlay for click-to-focus; the visible Field label handles a11y */}\n <label\n htmlFor={inputId}\n // Positioned behind children (z-0) so it catches clicks on empty space\n className=\"absolute inset-0 z-0 !mb-0\"\n aria-hidden=\"true\"\n />\n {children}\n </div>\n ) : useLabelContainer ? (\n // Standalone container mode: <label> enables click-to-focus on empty space.\n <label\n ref={forwardedRef as React.Ref<HTMLLabelElement>}\n {...dataProps}\n className={cn(containerClassName, \"!mb-0\")}\n {...rest}\n >\n {children}\n </label>\n ) : (\n // Individual mode: <div> avoids :hover propagating to the first labelable sibling.\n <div\n ref={forwardedRef as React.Ref<HTMLDivElement>}\n {...dataProps}\n className={containerClassName}\n {...rest}\n >\n {children}\n </div>\n )}\n </InputGroupContext.Provider>\n );\n\n if (label) {\n return (\n <Field\n label={label}\n description={description}\n error={error}\n required={required}\n labelTooltip={labelTooltip}\n >\n {container}\n </Field>\n );\n }\n\n return container;\n },\n);\nRoot.displayName = \"InputGroup\";\n\n/** @deprecated Use `InputGroup.Addon` instead. */\nconst Label = forwardRef<\n HTMLDivElement,\n ComponentPropsWithoutRef<typeof Addon>\n>((props, ref) => <Addon ref={ref} align=\"start\" {...props} />);\nLabel.displayName = \"InputGroup.Label\";\n\n/** @deprecated Use `InputGroup.Suffix` instead. */\nconst Description = forwardRef<\n HTMLDivElement,\n ComponentPropsWithoutRef<typeof Suffix>\n>((props, ref) => <Suffix ref={ref} {...props} />);\nDescription.displayName = \"InputGroup.Description\";\n\nexport const InputGroup = Object.assign(Root, {\n Input,\n Button,\n Addon,\n Suffix,\n /** @deprecated Use `InputGroup.Addon` instead. */\n Label,\n /** @deprecated Use `InputGroup.Suffix` instead. */\n Description,\n});\n"],"names":["INPUT_GROUP_SIZE","INPUT_GROUP_HAS_CLASSES","InputGroupContext","createContext","InputGroupAddonContext","useInputGroupContext","componentName","context","useContext","partitionChildren","children","containerZone","individualZone","Children","child","isValidElement","detectFocusMode","hasNonGhostDirectButton","hasAddon","type","displayName","variant","Input","forwardRef","props","ref","size","tokens","isIndividual","hasError","inputId","jsx","InputExternal","cn","COMPACT_BUTTON_SIZE","Button","className","disabled","tooltip","tooltipSide","icon","isInsideAddon","isDisabled","effectiveVariant","tooltipAriaLabel","contextIconSize","sizedIcon","React","btn","ButtonExternal","Tooltip","Addon","align","containsButton","sizedChildren","cloneElement","Suffix","KUMO_INPUT_GROUP_VARIANTS","KUMO_INPUT_GROUP_DEFAULT_VARIANTS","Root","label","description","error","required","labelTooltip","rest","forwardedRef","useId","focusMode","contextValue","useMemo","containerClassName","inputVariants","dataProps","containerZoneContext","hybridContent","jsxs","Fragment","hybridContainer","Field","useLabelContainer","container","Label","Description","InputGroup"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"input-group-5luo0442jgsie018.js","sources":["../../src/components/input-group/context.ts","../../src/components/input-group/input-group-input.tsx","../../src/components/input-group/input-group-button.tsx","../../src/components/input-group/input-group-addon.tsx","../../src/components/input-group/input-group-suffix.tsx","../../src/components/input-group/input-group.tsx"],"sourcesContent":["import {\n Children,\n createContext,\n isValidElement,\n useContext,\n type HTMLAttributes,\n type ReactNode,\n} from \"react\";\nimport type { KumoInputSize } from \"../input/input\";\nimport type { FieldProps } from \"../field/field\";\n\n// Spacing model\n//\n// Each element type has a fixed outer padding. The container uses has-[] CSS\n// to reduce the input's padding on sides that touch an addon.\n//\n// Input outer: px-3 (12px base) — full padding when at the edge\n// Input seam: pl-2 / pr-2 (8px base) — applied by container has-[]\n// Addon outer: pl-2 / pr-2 (8px base) — on the container-edge side\n// Addon seam: nothing — input owns the gap entirely\n//\n// has-[] rules on the container override [&_input]:pl-{seam} when a start\n// addon is present, and [&_input]:pr-{seam} when an end addon is present.\n\nexport interface InputGroupSizeTokens {\n /** Full outer padding — matches standalone Input (e.g. px-3). */\n inputOuter: string;\n /**\n * Directional outer padding for Addon at the container edge.\n *\n * These MUST be static pl-/pr- strings (not derived at runtime via\n * `\"px-N\".replace(…)`) so Tailwind JIT can detect them during its\n * source-file scan. Dynamic string construction produces class names\n * that never appear as literals, so Tailwind never generates the CSS.\n */\n addonOuterStart: string;\n addonOuterEnd: string;\n /**\n * Reduced outer padding when the Addon contains a Button.\n * Buttons have their own internal padding, so the Addon can use\n * less outer padding to keep the visual gap balanced.\n */\n addonButtonOuterStart: string;\n addonButtonOuterEnd: string;\n /** pr- for suffix when no end addon. */\n suffixPad: string;\n fontSize: string;\n /** Icon size in px. */\n iconSize: number;\n}\n\nexport const INPUT_GROUP_SIZE: Record<KumoInputSize, InputGroupSizeTokens> = {\n xs: {\n inputOuter: \"px-1.5\",\n addonOuterStart: \"pl-1.5\",\n addonOuterEnd: \"pr-1.5\",\n addonButtonOuterStart: \"pl-1\",\n addonButtonOuterEnd: \"pr-1\",\n suffixPad: \"pr-1.5\",\n fontSize: \"text-xs\",\n iconSize: 10,\n },\n sm: {\n inputOuter: \"px-2\",\n addonOuterStart: \"pl-1.5\",\n addonOuterEnd: \"pr-1.5\",\n addonButtonOuterStart: \"pl-1\",\n addonButtonOuterEnd: \"pr-1\",\n suffixPad: \"pr-2\",\n fontSize: \"text-xs\",\n iconSize: 13,\n },\n base: {\n inputOuter: \"px-3\",\n addonOuterStart: \"pl-2\",\n addonOuterEnd: \"pr-2\",\n addonButtonOuterStart: \"pl-1\",\n addonButtonOuterEnd: \"pr-1\",\n suffixPad: \"pr-3\",\n fontSize: \"text-base\",\n iconSize: 18,\n },\n lg: {\n inputOuter: \"px-4\",\n addonOuterStart: \"pl-2.5\",\n addonOuterEnd: \"pr-2.5\",\n addonButtonOuterStart: \"pl-1.5\",\n addonButtonOuterEnd: \"pr-1.5\",\n suffixPad: \"pr-4\",\n fontSize: \"text-base\",\n iconSize: 20,\n },\n};\n\n// Build the has-[] container classes that reduce input padding when addons\n// are present. These are static strings so Tailwind JIT can detect them.\nexport const INPUT_GROUP_HAS_CLASSES: Record<KumoInputSize, string> = {\n xs: [\n \"has-[[data-slot=input-group-addon-start]]:[&_input]:pl-1\",\n \"has-[[data-slot=input-group-addon-end]]:[&_input]:pr-1\",\n ].join(\" \"),\n sm: [\n \"has-[[data-slot=input-group-addon-start]]:[&_input]:pl-1.5\",\n \"has-[[data-slot=input-group-addon-end]]:[&_input]:pr-1.5\",\n ].join(\" \"),\n base: [\n \"has-[[data-slot=input-group-addon-start]]:[&_input]:pl-2\",\n \"has-[[data-slot=input-group-addon-end]]:[&_input]:pr-2\",\n ].join(\" \"),\n lg: [\n \"has-[[data-slot=input-group-addon-start]]:[&_input]:pl-2.5\",\n \"has-[[data-slot=input-group-addon-end]]:[&_input]:pr-2.5\",\n ].join(\" \"),\n};\n\n// Context\n\n/**\n * Props for `InputGroup.Root`. Focus mode is auto-detected from children\n * (see `detectFocusMode`), so it is not part of the public or internal API.\n */\nexport interface InputGroupRootPropsInternal\n extends HTMLAttributes<HTMLElement>,\n Partial<\n Pick<\n FieldProps,\n \"label\" | \"description\" | \"error\" | \"required\" | \"labelTooltip\"\n >\n > {\n size?: KumoInputSize | undefined;\n disabled?: boolean;\n}\n\n/** Public InputGroup.Root props — identical to the internal type. */\nexport type InputGroupRootProps = InputGroupRootPropsInternal;\n\nexport interface InputGroupContextValue {\n size?: KumoInputSize;\n focusMode: \"container\" | \"individual\" | \"hybrid\";\n disabled: boolean;\n error?: FieldProps[\"error\"];\n /** Auto-generated id for the input element; used by the invisible label overlay. */\n inputId: string;\n}\n\nexport const InputGroupContext = createContext<InputGroupContextValue | null>(\n null,\n);\n\n/**\n * Set to `true` by `InputGroup.Addon` so that `InputGroup.Button` can detect\n * whether it's wrapped in an Addon. Ghost buttons should always live inside\n * an Addon for correct spacing.\n */\nexport const InputGroupAddonContext = createContext(false);\n\n/**\n * Reads InputGroupContext and warns in development when the context is null\n * (i.e. when a sub-component is rendered outside of `<InputGroup>`).\n */\nexport function useInputGroupContext(componentName: string) {\n const context = useContext(InputGroupContext);\n if (process.env.NODE_ENV !== \"production\" && !context) {\n console.warn(\n `<InputGroup.${componentName}> must be used within <InputGroup>. Falling back to default values.`,\n );\n }\n return context;\n}\n\n/**\n * Partitions InputGroup children for hybrid focus mode.\n *\n * Container zone: Addon, Input, Suffix, text nodes — everything that should\n * share a single container-style border.\n *\n * Individual zone: Direct `InputGroup.Button` elements that manage their own\n * border and focus ring.\n *\n * Uses `displayName` comparison to identify elements, avoiding circular\n * imports between `context.ts` and the sub-component files.\n */\nexport function partitionChildren(children: ReactNode): {\n containerZone: ReactNode[];\n individualZone: ReactNode[];\n} {\n const containerZone: ReactNode[] = [];\n const individualZone: ReactNode[] = [];\n\n Children.forEach(children, (child) => {\n if (\n isValidElement(child) &&\n (child.type as { displayName?: string })?.displayName ===\n \"InputGroup.Button\"\n ) {\n individualZone.push(child);\n } else {\n containerZone.push(child);\n }\n });\n\n return { containerZone, individualZone };\n}\n\n/**\n * Analyzes the direct children of `InputGroup` to determine the focus mode.\n *\n * Returns `\"hybrid\"` when BOTH an `InputGroup.Addon` AND a non-ghost direct\n * `InputGroup.Button` are present. In hybrid mode, Addon+Input share a\n * container-style border while Buttons get individual borders.\n *\n * Returns `\"individual\"` when a non-ghost direct `InputGroup.Button` is\n * present WITHOUT any `InputGroup.Addon`. This signals a toolbar/pagination\n * layout where each element manages its own focus ring.\n *\n * Returns `\"container\"` (default) in all other cases — the container owns a\n * single shared focus ring.\n *\n * Uses `displayName` comparison to identify elements, avoiding circular\n * imports between `context.ts` and the sub-component files.\n */\nexport function detectFocusMode(\n children: ReactNode,\n): \"container\" | \"individual\" | \"hybrid\" {\n let hasNonGhostDirectButton = false;\n let hasAddon = false;\n\n Children.forEach(children, (child) => {\n if (!isValidElement(child)) return;\n\n // Identify components by displayName to avoid circular imports.\n const type = child.type;\n const displayName =\n typeof type === \"function\" || typeof type === \"object\"\n ? (type as { displayName?: string }).displayName\n : undefined;\n\n if (displayName === \"InputGroup.Addon\") {\n hasAddon = true;\n return;\n }\n\n if (displayName !== \"InputGroup.Button\") return;\n\n // A direct-child Button is by definition NOT inside an Addon (Addon's\n // children are children of the Addon element, not of InputGroup).\n // Check whether the variant is explicitly non-ghost.\n const variant = (child.props as { variant?: string }).variant;\n if (variant !== undefined && variant !== \"ghost\") {\n hasNonGhostDirectButton = true;\n }\n });\n\n if (hasNonGhostDirectButton && hasAddon) return \"hybrid\";\n if (hasNonGhostDirectButton) return \"individual\";\n return \"container\";\n}\n","import { forwardRef } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Input as InputExternal, type InputProps } from \"../input/input\";\nimport { useInputGroupContext, INPUT_GROUP_SIZE } from \"./context\";\n\n/** Props for InputGroup.Input — omits Field props since InputGroup handles them. */\nexport type InputGroupInputProps = Omit<\n InputProps,\n \"label\" | \"labelTooltip\" | \"description\" | \"error\" | \"size\" | \"disabled\"\n>;\n\n/**\n * Text input that inherits size, disabled, and error state from InputGroup context.\n * Automatically sets `aria-invalid` when parent has an error.\n */\nexport const Input = forwardRef<HTMLInputElement, InputGroupInputProps>(\n (props, ref) => {\n const context = useInputGroupContext(\"Input\");\n\n // Warn when props that belong on <InputGroup> are passed directly\n if (process.env.NODE_ENV !== \"production\" && context) {\n if ((props as any).size !== undefined) {\n console.warn(\n \"InputGroup.Input: Set `size` on <InputGroup> instead of <InputGroup.Input>.\",\n );\n }\n if ((props as any).disabled !== undefined) {\n console.warn(\n \"InputGroup.Input: Set `disabled` on <InputGroup> instead of <InputGroup.Input>.\",\n );\n }\n if ((props as any).label !== undefined) {\n console.warn(\n \"InputGroup.Input: Use the `label` prop on <InputGroup> instead of <InputGroup.Input>.\",\n );\n }\n if ((props as any).description !== undefined) {\n console.warn(\n \"InputGroup.Input: Use <InputGroup.Suffix> instead of passing `description` to <InputGroup.Input>.\",\n );\n }\n }\n\n const size = context?.size ?? \"base\";\n const tokens = INPUT_GROUP_SIZE[size];\n const isIndividual = context?.focusMode === \"individual\";\n\n // Auto-set aria-invalid when error is present in context\n const hasError = Boolean(context?.error);\n\n // Use explicit id if provided, otherwise fall back to context id\n // (links the input to the invisible label overlay for click-to-focus).\n const inputId = props.id ?? context?.inputId;\n\n return (\n <InputExternal\n ref={ref}\n size={context?.size}\n disabled={context?.disabled || (props as any).disabled}\n aria-invalid={hasError || props[\"aria-invalid\"]}\n {...props}\n id={inputId}\n className={cn(\n // Base input layout: fill height, allow shrinking, strip native border/radius\n \"flex h-full min-w-0 grow items-center rounded-none border-0 bg-transparent font-sans\",\n // Always use full outer padding — the container's has-[] rules reduce\n // pl/pr to inputSeam on sides that touch an addon.\n tokens.inputOuter,\n // Truncate overflowing text with \"…\" instead of expanding the input\n \"text-ellipsis\",\n // Individual mode: each element owns its own border instead of sharing a container ring\n isIndividual\n ? [\n // Own border replaces the container's shared ring\n \"relative ring-0 border border-kumo-line\",\n // Inherit border-radius only on outer edges; inner edges are flat\n \"first:rounded-l-[inherit] last:rounded-r-[inherit]\",\n // Collapse double borders between adjacent elements\n \"not-first:border-l-0\",\n // Hovered element renders above idle siblings to show full border\n \"hover:z-[1] hover:border-kumo-line\",\n // Focused element renders above hovered siblings for focus indicator\n \"focus:z-[2] focus:border-kumo-line focus:outline focus:-outline-offset-1\",\n ].join(\" \")\n : // Container mode: kill all focus indicators — the container handles them\n // z-[1] lifts the input above the invisible label overlay so cursor/selection work\n \"relative z-[1] ring-0! shadow-none outline-none focus:ring-0! focus:outline-none\",\n props.className,\n )}\n />\n );\n },\n);\nInput.displayName = \"InputGroup.Input\";\n","import React, {\n forwardRef,\n useContext,\n type PropsWithChildren,\n type ReactNode,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { type ButtonProps, Button as ButtonExternal } from \"../button/button\";\nimport { Tooltip, type KumoTooltipSide } from \"../tooltip/tooltip\";\nimport type { KumoInputSize } from \"../input/input\";\nimport {\n INPUT_GROUP_SIZE,\n InputGroupAddonContext,\n useInputGroupContext,\n} from \"./context\";\n\n/**\n * In container mode, buttons render \"one size down\" so they stay visually\n * subordinate to the input. In individual mode the size passes through\n * unchanged (pagination / toolbar buttons should match the input height).\n */\nconst COMPACT_BUTTON_SIZE: Record<KumoInputSize, KumoInputSize> = {\n xs: \"xs\",\n sm: \"xs\",\n base: \"sm\",\n lg: \"base\",\n};\n\nexport type InputGroupButtonProps = ButtonProps & {\n /**\n * When provided, wraps the button in a `Tooltip` showing this content on hover.\n * Automatically sets `aria-label` from a string value when no `aria-label` is set.\n *\n * @example\n * ```tsx\n * <InputGroup.Addon align=\"end\">\n * <InputGroup.Button tooltip=\"Query language help\" aria-label=\"Query language help\">\n * <QuestionIcon size={16} />\n * </InputGroup.Button>\n * </InputGroup.Addon>\n * ```\n */\n tooltip?: ReactNode;\n /**\n * Preferred side for the tooltip popup.\n * @default \"bottom\"\n */\n tooltipSide?: KumoTooltipSide;\n};\n\n/**\n * Button for secondary actions rendered inside `InputGroup.Addon`\n * (toggle, copy, help).\n *\n * In `focusMode=\"container\"` (default), renders as a compact ghost button\n * subordinate to the input. In `focusMode=\"individual\"`, renders as a full\n * standalone button with its own focus ring, matching toolbar/pagination usage.\n *\n * Pass a `tooltip` prop to show a tooltip on hover.\n */\nexport const Button = forwardRef<\n HTMLButtonElement,\n PropsWithChildren<InputGroupButtonProps>\n>(\n (\n {\n children,\n className,\n variant,\n size,\n disabled,\n tooltip,\n tooltipSide = \"bottom\",\n icon,\n ...props\n }: PropsWithChildren<InputGroupButtonProps>,\n ref: React.ForwardedRef<HTMLButtonElement>,\n ) => {\n const context = useInputGroupContext(\"Button\");\n const isInsideAddon = useContext(InputGroupAddonContext);\n const isDisabled = disabled ?? context?.disabled;\n const isIndividual =\n context?.focusMode === \"individual\" || context?.focusMode === \"hybrid\";\n const effectiveVariant = variant ?? \"ghost\";\n\n if (\n process.env.NODE_ENV !== \"production\" &&\n context &&\n effectiveVariant === \"ghost\" &&\n !isInsideAddon\n ) {\n console.warn(\n \"InputGroup.Button: Ghost buttons should be wrapped in <InputGroup.Addon> for correct spacing.\",\n );\n }\n\n if (\n process.env.NODE_ENV !== \"production\" &&\n context &&\n size !== undefined\n ) {\n console.warn(\n \"InputGroup.Button: Set `size` on <InputGroup> instead of <InputGroup.Button>.\",\n );\n }\n\n // Derive aria-label from tooltip string when the button has no explicit label.\n // Icon-only buttons require an aria-label for a11y.\n const tooltipAriaLabel =\n typeof tooltip === \"string\" && !props[\"aria-label\"] ? tooltip : undefined;\n\n // Pre-render the icon with the context-derived size so it matches the\n // Addon icon sizing (e.g. 18px at \"base\"). Without this, Button's\n // internal renderIconNode renders `<Icon />` with no size prop,\n // falling back to CSS font-size (~14px).\n const contextIconSize = context\n ? INPUT_GROUP_SIZE[context.size ?? \"base\"].iconSize\n : undefined;\n\n const sizedIcon =\n icon &&\n contextIconSize &&\n (typeof icon === \"function\" ||\n (typeof icon === \"object\" &&\n icon !== null &&\n !React.isValidElement(icon)))\n ? React.createElement(icon as React.ComponentType<{ size?: number }>, {\n size: contextIconSize,\n })\n : icon;\n\n const btn = (\n <ButtonExternal\n ref={ref}\n type=\"button\"\n disabled={isDisabled}\n aria-label={tooltipAriaLabel}\n {...props}\n icon={sizedIcon}\n variant={variant ?? \"ghost\"}\n // Individual: use the group's size directly so buttons match the input height.\n // Container: render one size down so the button stays subordinate to the input.\n size={\n size ??\n (isIndividual\n ? (context?.size ?? \"sm\")\n : (COMPACT_BUTTON_SIZE[context?.size ?? \"base\"] ?? \"sm\"))\n }\n className={cn(\n // Ensure clicks register even when parent has pointer-events-none (e.g. disabled overlay)\n \"pointer-events-auto\",\n // Individual mode: each button owns its own border and focus indicator\n isIndividual && [\n // Own border replaces the container's shared ring; force full height\n \"relative h-full! rounded-none ring-0 border border-kumo-line\",\n // Inherit border-radius only on outer edges; inner edges are flat\n \"first:rounded-l-[inherit] last:rounded-r-[inherit]\",\n // Collapse double borders between adjacent elements\n \"not-first:border-l-0\",\n // Hovered element renders above idle siblings to show full border\n \"hover:z-[1]\",\n // Focused element renders above hovered siblings for focus indicator\n \"focus:z-[2] focus:border-kumo-line focus:outline focus:-outline-offset-1\",\n // Suppress the base Button's focus ring so only our outline shows\n \"focus-visible:ring-2 focus-visible:ring-kumo-focus\",\n // Match the group's disabled visual treatment\n \"disabled:bg-kumo-overlay disabled:text-kumo-inactive!\",\n ],\n className,\n )}\n >\n {children}\n </ButtonExternal>\n );\n\n if (tooltip) {\n return (\n <Tooltip content={tooltip} side={tooltipSide} asChild>\n {btn}\n </Tooltip>\n );\n }\n\n return btn;\n },\n);\nButton.displayName = \"InputGroup.Button\";\n","import {\n Children,\n cloneElement,\n forwardRef,\n isValidElement,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport {\n useInputGroupContext,\n INPUT_GROUP_SIZE,\n InputGroupAddonContext,\n} from \"./context\";\nimport { Button } from \"./input-group-button\";\n\nexport interface InputGroupAddonProps {\n /** Position relative to the input. @default \"start\" */\n align?: \"start\" | \"end\";\n /** Additional CSS classes. */\n className?: string;\n /** Addon content: icons, buttons, spinners, text. */\n children?: ReactNode;\n}\n\n/**\n * Container for icons, text, or compact buttons positioned at the start or end\n * of the input. Automatically sizes icon children to match the input size.\n */\nexport const Addon = forwardRef<HTMLDivElement, InputGroupAddonProps>(\n ({ align = \"start\", className, children }, ref) => {\n const context = useInputGroupContext(\"Addon\");\n\n const size = context?.size ?? \"base\";\n const tokens = INPUT_GROUP_SIZE[size];\n\n // Inject size into direct icon children that don't already have one set.\n // Skips buttons (which have their own size handling) and non-element nodes.\n // Also tracks whether a Button is present so we can reduce outer padding.\n let containsButton = false;\n const sizedChildren = Children.map(children, (child) => {\n if (!isValidElement(child)) return child;\n if (child.type === Button) {\n containsButton = true;\n return child;\n }\n const props = child.props as { size?: unknown };\n if (props.size !== undefined) return child;\n return cloneElement(child as ReactElement<{ size?: number }>, {\n size: tokens.iconSize,\n });\n });\n\n // Always use flex-based positioning. CSS order controls visual placement.\n return (\n <div\n ref={ref}\n data-slot={\n align === \"start\"\n ? \"input-group-addon-start\"\n : \"input-group-addon-end\"\n }\n className={cn(\n \"relative z-[1] pointer-events-none flex shrink-0 items-center gap-1.5\",\n \"text-kumo-subtle\",\n tokens.fontSize,\n \"*:pointer-events-auto\",\n align === \"start\"\n ? cn(\n \"-order-1\",\n containsButton\n ? tokens.addonButtonOuterStart\n : tokens.addonOuterStart,\n \"pr-0\",\n )\n : cn(\n \"order-1\",\n \"pl-0\",\n containsButton\n ? tokens.addonButtonOuterEnd\n : tokens.addonOuterEnd,\n ),\n className,\n )}\n >\n <InputGroupAddonContext.Provider value={true}>\n {sizedChildren}\n </InputGroupAddonContext.Provider>\n </div>\n );\n },\n);\nAddon.displayName = \"InputGroup.Addon\";\n","import { forwardRef, type ReactNode } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useInputGroupContext, INPUT_GROUP_SIZE } from \"./context\";\n\nexport interface InputGroupSuffixProps {\n /** Additional CSS classes. */\n className?: string;\n /** Suffix content (e.g., \".workers.dev\"). */\n children?: ReactNode;\n}\n\n/**\n * Inline suffix that flows seamlessly next to the typed input value.\n * Input width adjusts automatically via CSS `field-sizing: content`.\n */\nexport const Suffix = forwardRef<HTMLDivElement, InputGroupSuffixProps>(\n ({ className, children }, ref) => {\n const context = useInputGroupContext(\"Suffix\");\n\n const size = context?.size ?? \"base\";\n const tokens = INPUT_GROUP_SIZE[size];\n\n return (\n <div\n ref={ref}\n data-slot=\"input-group-suffix\"\n className={cn(\n \"pointer-events-none flex min-w-0 grow select-none items-center text-kumo-subtle\",\n tokens.fontSize,\n tokens.suffixPad,\n className,\n )}\n >\n <span className=\"truncate\">{children}</span>\n </div>\n );\n },\n);\nSuffix.displayName = \"InputGroup.Suffix\";\n","import {\n forwardRef,\n useId,\n useMemo,\n type ComponentPropsWithoutRef,\n type PropsWithChildren,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { inputVariants } from \"../input/input\";\nimport { Field } from \"../field/field\";\nimport {\n InputGroupContext,\n INPUT_GROUP_HAS_CLASSES,\n detectFocusMode,\n partitionChildren,\n type InputGroupRootPropsInternal,\n} from \"./context\";\nimport { Input } from \"./input-group-input\";\nimport { Button } from \"./input-group-button\";\nimport { Addon } from \"./input-group-addon\";\nimport { Suffix } from \"./input-group-suffix\";\n\nexport { type InputGroupRootProps } from \"./context\";\nexport { type InputGroupInputProps } from \"./input-group-input\";\nexport { type InputGroupButtonProps } from \"./input-group-button\";\nexport { type InputGroupAddonProps } from \"./input-group-addon\";\nexport { type InputGroupSuffixProps } from \"./input-group-suffix\";\n\nexport const KUMO_INPUT_GROUP_VARIANTS = {\n size: {\n xs: {\n classes: \"h-6 text-xs\",\n description: \"Extra small size.\",\n },\n sm: {\n classes: \"h-7 text-xs\",\n description: \"Small size.\",\n },\n base: {\n classes: \"h-9 text-base\",\n description: \"Default size.\",\n },\n lg: {\n classes: \"h-11 text-base\",\n description: \"Large size.\",\n },\n },\n} as const;\n\nexport const KUMO_INPUT_GROUP_DEFAULT_VARIANTS = {\n size: \"base\",\n} as const;\n\n/**\n * Compound input component for building inputs with icons, addons, inline\n * suffixes, and action buttons. Accepts Field props and wraps content in\n * Field when label is provided.\n *\n * Renders as `<label>` only in standalone container mode (single input, no\n * sibling buttons) so clicking empty space focuses the input. Otherwise\n * renders as `<div>` to avoid nested `<label>` (when Field provides one) or\n * the browser's `:hover` propagation from `<label>` to its first labelable\n * descendant (when multiple labelable controls are siblings).\n *\n * @note Do not wrap InputGroup inside an external Field without using the `label` prop —\n * this creates invalid nested `<label>` elements. Use InputGroup's own `label` prop instead.\n *\n * @example\n * ```tsx\n * <InputGroup label=\"Email\" error={{ message: \"Invalid\", match: true }}>\n * <InputGroup.Addon><EnvelopeIcon /></InputGroup.Addon>\n * <InputGroup.Input placeholder=\"you@example.com\" />\n * </InputGroup>\n * ```\n *\n * @example\n * ```tsx\n * <InputGroup>\n * <InputGroup.Input placeholder=\"my-worker\" />\n * <InputGroup.Suffix>.workers.dev</InputGroup.Suffix>\n * </InputGroup>\n * ```\n */\nconst Root = forwardRef<\n HTMLElement,\n PropsWithChildren<InputGroupRootPropsInternal>\n>(\n (\n {\n size = \"base\",\n children,\n className,\n disabled = false,\n label,\n description,\n error,\n required,\n labelTooltip,\n ...rest\n },\n forwardedRef,\n ) => {\n const inputId = useId();\n const focusMode = detectFocusMode(children);\n\n const contextValue = useMemo(\n () => ({\n size,\n focusMode,\n disabled,\n error,\n inputId,\n }),\n [size, focusMode, disabled, error, inputId],\n );\n\n // When label is provided, Field already renders a <label> with htmlFor\n // that handles click-to-focus. Using <div> avoids nested <label> elements\n // (invalid HTML with undefined assistive technology behavior).\n // When standalone (no label), a native <label> preserves click-to-focus.\n const containerClassName = cn(\n // Establish positioning context and make the whole area a click target\n \"relative w-full cursor-text\",\n // inputVariants provides base ring-kumo-line; must come before state overrides\n inputVariants({ size }),\n // Subtle drop shadow to separate the group from the page surface\n \"shadow-xs\",\n // Disabled state: prevent interaction and dim the entire group\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n // Container mode: clip children to rounded corners and show a shared focus ring\n // Individual mode: disable container ring/shadow so each child owns its own border\n focusMode === \"container\"\n ? [\n \"overflow-hidden\",\n // Focus state must come AFTER inputVariants to override ring-kumo-line\n \"focus-within:ring-kumo-focus\",\n ]\n : // isolate creates a new stacking context so z-index in children doesn't leak out\n \"isolate overflow-visible ring-0 shadow-none\",\n // Error state must also come after inputVariants\n \"has-[input[aria-invalid=true]]:ring-kumo-danger\",\n // Reset horizontal padding — children handle their own spacing\n \"px-0\",\n // Horizontal layout with no gap — children control their own internal spacing\n \"flex items-center gap-0\",\n // When a suffix is present, let the input shrink to its content width\n // so the suffix stays visually adjacent\n \"has-[[data-slot=input-group-suffix]]:[&_input]:[field-sizing:content]\",\n \"has-[[data-slot=input-group-suffix]]:[&_input]:max-w-full\",\n \"has-[[data-slot=input-group-suffix]]:[&_input]:grow-0\",\n \"has-[[data-slot=input-group-suffix]]:[&_input]:pr-0\",\n // Size-specific padding adjustments when addons or suffixes are present\n INPUT_GROUP_HAS_CLASSES[size],\n // Reset bottom margin to avoid inherited spacing from parent <label> styles\n \"!mb-0\",\n className,\n );\n\n // Data attributes drive CSS selectors in kumo-binding.css (focus outline)\n // and enable child components to query their parent's state.\n const dataProps = {\n \"data-slot\": \"input-group\" as const,\n \"data-focus-mode\": focusMode,\n \"data-disabled\": disabled ? (\"\" as const) : undefined,\n };\n\n // Hybrid mode: splits children into two rendering zones:\n // 1. Container zone (Addon + Input + Suffix) — shares a single border/ring\n // 2. Individual zone (standalone Buttons) — each button owns its own border\n // This lets inputs and addons look unified while buttons remain independent.\n if (focusMode === \"hybrid\") {\n // Partition children by type: addons/inputs/suffixes → container, buttons → individual\n const { containerZone, individualZone } = partitionChildren(children);\n\n // Override focusMode to \"container\" for children inside the zone\n // so InputGroup.Input uses container-mode styling (ring-0!, no own border).\n const containerZoneContext = {\n ...contextValue,\n focusMode: \"container\" as const,\n };\n\n const hybridContent = (\n <>\n {/* Container zone wrapper — shares a single border/ring */}\n <InputGroupContext.Provider value={containerZoneContext}>\n <div\n data-slot=\"input-group-container-zone\"\n className={cn(\n // Base input sizing/shape from shared variant function\n inputVariants({ size }),\n // Clip children to rounded corners within the zone\n \"overflow-hidden\",\n // Show red ring on validation error\n \"has-[input[aria-invalid=true]]:ring-kumo-danger\",\n // Reset horizontal padding — children handle their own spacing\n \"px-0\",\n // Fill available width but allow shrinking when sibling buttons are present\n \"flex min-w-0 flex-1 items-center gap-0\",\n // Use a clean 1px CSS border instead of ring+shadow from inputVariants\n // so the zone matches adjacent individual-mode buttons exactly.\n \"ring-0 shadow-none\",\n \"border border-kumo-line\",\n \"focus-within:ring-1 focus-within:ring-kumo-focus\",\n // Collapse double borders between zone and adjacent individual-mode button\n \"not-first:border-l-0\",\n // Inherit border-radius from the outer container on outer edges only;\n // inner edges are flat so they butt cleanly against sibling buttons\n \"first:rounded-l-[inherit] last:rounded-r-[inherit] rounded-none\",\n // Size-specific padding adjustments when addons or suffixes are present\n INPUT_GROUP_HAS_CLASSES[size],\n // When a suffix is present, let the input shrink to its content width\n \"has-[[data-slot=input-group-suffix]]:[&_input]:[field-sizing:content]\",\n \"has-[[data-slot=input-group-suffix]]:[&_input]:max-w-full\",\n \"has-[[data-slot=input-group-suffix]]:[&_input]:grow-0\",\n \"has-[[data-slot=input-group-suffix]]:[&_input]:pr-0\",\n )}\n >\n {/* When label exists, an invisible <label> overlay enables click-to-focus\n inside the container zone without nesting visible <label> elements */}\n {label && (\n // eslint-disable-next-line jsx-a11y/label-has-associated-control -- invisible overlay for click-to-focus; the visible Field label handles a11y\n <label\n htmlFor={inputId}\n // Positioned behind children (z-0) so it catches clicks on empty space\n className=\"absolute inset-0 z-0 cursor-text !mb-0\"\n aria-hidden=\"true\"\n />\n )}\n {containerZone}\n </div>\n </InputGroupContext.Provider>\n {/* Individual zone — buttons with their own borders */}\n {individualZone}\n </>\n );\n\n // Hybrid always uses a <div> container (never <label>) because\n // individual-zone buttons are siblings — wrapping them in a <label>\n // would be semantically incorrect.\n const hybridContainer = (\n <InputGroupContext.Provider value={contextValue}>\n <div\n ref={forwardedRef as React.Ref<HTMLDivElement>}\n {...dataProps}\n className={containerClassName}\n {...rest}\n >\n {hybridContent}\n </div>\n </InputGroupContext.Provider>\n );\n\n if (label) {\n return (\n <Field\n label={label}\n description={description}\n error={error}\n required={required}\n labelTooltip={labelTooltip}\n >\n {hybridContainer}\n </Field>\n );\n }\n\n return hybridContainer;\n }\n\n // Container / Individual mode (non-hybrid)\n // Use <label> only when there's exactly one labelable descendant; otherwise <label> would propagate :hover to its first labelable descendant.\n const useLabelContainer = !label && focusMode === \"container\";\n const container = (\n <InputGroupContext.Provider value={contextValue}>\n {/* When label is set, use <div> to avoid nested <label> (Field provides one).\n An invisible <label> overlay handles click-to-focus on empty space. */}\n {label ? (\n <div\n ref={forwardedRef as React.Ref<HTMLDivElement>}\n {...dataProps}\n className={containerClassName}\n {...rest}\n >\n {/* eslint-disable-next-line jsx-a11y/label-has-associated-control -- invisible overlay for click-to-focus; the visible Field label handles a11y */}\n <label\n htmlFor={inputId}\n // Positioned behind children (z-0) so it catches clicks on empty space\n className=\"absolute inset-0 z-0 !mb-0\"\n aria-hidden=\"true\"\n />\n {children}\n </div>\n ) : useLabelContainer ? (\n // Standalone container mode: <label> enables click-to-focus on empty space.\n <label\n ref={forwardedRef as React.Ref<HTMLLabelElement>}\n {...dataProps}\n className={cn(containerClassName, \"!mb-0\")}\n {...rest}\n >\n {children}\n </label>\n ) : (\n // Individual mode: <div> avoids :hover propagating to the first labelable sibling.\n <div\n ref={forwardedRef as React.Ref<HTMLDivElement>}\n {...dataProps}\n className={containerClassName}\n {...rest}\n >\n {children}\n </div>\n )}\n </InputGroupContext.Provider>\n );\n\n if (label) {\n return (\n <Field\n label={label}\n description={description}\n error={error}\n required={required}\n labelTooltip={labelTooltip}\n >\n {container}\n </Field>\n );\n }\n\n return container;\n },\n);\nRoot.displayName = \"InputGroup\";\n\n/** @deprecated Use `InputGroup.Addon` instead. */\nconst Label = forwardRef<\n HTMLDivElement,\n ComponentPropsWithoutRef<typeof Addon>\n>((props, ref) => <Addon ref={ref} align=\"start\" {...props} />);\nLabel.displayName = \"InputGroup.Label\";\n\n/** @deprecated Use `InputGroup.Suffix` instead. */\nconst Description = forwardRef<\n HTMLDivElement,\n ComponentPropsWithoutRef<typeof Suffix>\n>((props, ref) => <Suffix ref={ref} {...props} />);\nDescription.displayName = \"InputGroup.Description\";\n\nexport const InputGroup = Object.assign(Root, {\n Input,\n Button,\n Addon,\n Suffix,\n /** @deprecated Use `InputGroup.Addon` instead. */\n Label,\n /** @deprecated Use `InputGroup.Suffix` instead. */\n Description,\n});\n"],"names":["INPUT_GROUP_SIZE","INPUT_GROUP_HAS_CLASSES","InputGroupContext","createContext","InputGroupAddonContext","useInputGroupContext","componentName","context","useContext","partitionChildren","children","containerZone","individualZone","Children","child","isValidElement","detectFocusMode","hasNonGhostDirectButton","hasAddon","type","displayName","variant","Input","forwardRef","props","ref","size","tokens","isIndividual","hasError","inputId","jsx","InputExternal","cn","COMPACT_BUTTON_SIZE","Button","className","disabled","tooltip","tooltipSide","icon","isInsideAddon","isDisabled","effectiveVariant","tooltipAriaLabel","contextIconSize","sizedIcon","React","btn","ButtonExternal","Tooltip","Addon","align","containsButton","sizedChildren","cloneElement","Suffix","KUMO_INPUT_GROUP_VARIANTS","KUMO_INPUT_GROUP_DEFAULT_VARIANTS","Root","label","description","error","required","labelTooltip","rest","forwardedRef","useId","focusMode","contextValue","useMemo","containerClassName","inputVariants","dataProps","containerZoneContext","hybridContent","jsxs","Fragment","hybridContainer","Field","useLabelContainer","container","Label","Description","InputGroup"],"mappings":"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"}
|
|
@@ -3,8 +3,8 @@ import { jsx as p } from "react/jsx-runtime";
|
|
|
3
3
|
import { c as f } from "./cn-ct4n7r74mh8y0f48.js";
|
|
4
4
|
import { r as c } from "./resolve-variant-gw6eh7fa4st8ej7m.js";
|
|
5
5
|
import { forwardRef as k } from "react";
|
|
6
|
-
import { F as N } from "./field-
|
|
7
|
-
import { I as y } from "./vendor-base-ui-
|
|
6
|
+
import { F as N } from "./field-mil8efu3x0s68eed.js";
|
|
7
|
+
import { I as y } from "./vendor-base-ui-epfrwb4nfbd4btaz.js";
|
|
8
8
|
const d = {
|
|
9
9
|
size: {
|
|
10
10
|
xs: {
|
|
@@ -111,4 +111,4 @@ export {
|
|
|
111
111
|
d as K,
|
|
112
112
|
E as i
|
|
113
113
|
};
|
|
114
|
-
//# sourceMappingURL=input-
|
|
114
|
+
//# sourceMappingURL=input-kmztt6h4mzy101ho.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-k2ychlh2zo6hsocz.js","sources":["../../src/components/input/input.tsx"],"sourcesContent":["import { cn } from \"../../utils/cn\";\nimport { resolveVariant } from \"../../utils/resolve-variant\";\nimport {\n forwardRef,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from \"react\";\nimport { Input as BaseInput } from \"@base-ui/react/input\";\nimport { Field, type FieldErrorMatch } from \"../field/field\";\n\n/** Input size and variant definitions mapping names to their Tailwind classes. */\nexport const KUMO_INPUT_VARIANTS = {\n size: {\n xs: {\n classes: \"h-5 gap-1 rounded-sm px-1.5 text-xs\",\n description: \"Extra small input for compact UIs\",\n },\n sm: {\n classes: \"h-6.5 gap-1 rounded-md px-2 text-xs\",\n description: \"Small input for secondary fields\",\n },\n base: {\n classes: \"h-9 gap-1.5 rounded-lg px-3 text-base\",\n description: \"Default input size\",\n },\n lg: {\n classes: \"h-10 gap-2 rounded-lg px-4 text-base\",\n description: \"Large input for prominent fields\",\n },\n },\n variant: {\n default: {\n classes: \"focus:ring-kumo-focus/50 focus:ring-[1.5px]\",\n description: \"Default input appearance\",\n },\n error: {\n classes: \"!ring-kumo-danger focus:ring-kumo-danger/50 focus:ring-[1.5px]\",\n description: \"Error state for validation failures\",\n },\n },\n} as const;\n\nexport const KUMO_INPUT_DEFAULT_VARIANTS = {\n size: \"base\",\n variant: \"default\",\n} as const;\n\nexport const KUMO_INPUT_STYLING = {\n dimensions: {\n xs: { height: 20, paddingX: 6, fontSize: 12, borderRadius: 2, width: 160 },\n sm: { height: 26, paddingX: 8, fontSize: 12, borderRadius: 6, width: 200 },\n base: {\n height: 36,\n paddingX: 12,\n fontSize: 16,\n borderRadius: 8,\n width: 280,\n },\n lg: { height: 40, paddingX: 16, fontSize: 16, borderRadius: 8, width: 320 },\n },\n baseTokens: {\n background: \"color-secondary\",\n text: \"text-color-surface\",\n placeholder: \"text-color-muted\",\n ring: \"color-border\",\n },\n stateTokens: {\n focus: { ring: \"color-active\" },\n error: { ring: \"color-error\" },\n disabled: { opacity: 0.5, text: \"text-color-muted\" },\n },\n} as const;\n\n// Derived types from KUMO_INPUT_VARIANTS\nexport type KumoInputSize = keyof typeof KUMO_INPUT_VARIANTS.size;\nexport type KumoInputVariant = keyof typeof KUMO_INPUT_VARIANTS.variant;\n\nexport interface KumoInputVariantsProps {\n /**\n * Input size.\n * - `\"xs\"` — Extra small for compact UIs\n * - `\"sm\"` — Small for secondary fields\n * - `\"base\"` — Default size\n * - `\"lg\"` — Large for prominent fields\n * @default \"base\"\n */\n size?: KumoInputSize;\n /**\n * Visual variant.\n * - `\"default\"` — Standard input\n * - `\"error\"` — Error state for validation failures\n * @default \"default\"\n */\n variant?: KumoInputVariant;\n parentFocusIndicator?: boolean;\n focusIndicator?: boolean;\n}\n\n// Omit native `size` attribute (number) to avoid conflict with our custom `size` variant\ntype BaseInputProps = Omit<ComponentPropsWithoutRef<typeof BaseInput>, \"size\">;\n\nexport function inputVariants({\n variant = KUMO_INPUT_DEFAULT_VARIANTS.variant,\n size = KUMO_INPUT_DEFAULT_VARIANTS.size,\n parentFocusIndicator = false,\n focusIndicator = false,\n}: KumoInputVariantsProps = {}) {\n return cn(\n // Base styles\n \"border-0 bg-kumo-control text-kumo-default ring ring-kumo-line outline-none focus:outline-none\",\n // Disabled state and placeholder styles (using vanilla CSS class for Chrome compatibility)\n \"kumo-input-placeholder disabled:text-kumo-disabled\",\n // Apply size styles from KUMO_INPUT_VARIANTS\n resolveVariant(KUMO_INPUT_VARIANTS.size, size, KUMO_INPUT_DEFAULT_VARIANTS.size).classes,\n // Apply variant styles from KUMO_INPUT_VARIANTS\n resolveVariant(KUMO_INPUT_VARIANTS.variant, variant, KUMO_INPUT_DEFAULT_VARIANTS.variant).classes,\n // Focus state handling\n parentFocusIndicator &&\n (variant === \"error\"\n ? \"focus-within:ring-kumo-danger/50 focus-within:ring-[1.5px]\"\n : \"focus-within:ring-kumo-focus/50 focus-within:ring-[1.5px]\"),\n focusIndicator &&\n (variant === \"error\"\n ? \"focus:ring-kumo-danger/50 focus:ring-[1.5px]\"\n : \"focus:ring-kumo-focus/50 focus:ring-[1.5px]\"),\n );\n}\n\nexport const Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => {\n const {\n className,\n size = \"base\",\n variant: variantProp,\n label,\n labelTooltip,\n description,\n error,\n ...inputProps\n } = props;\n\n // Deprecation warning for variant=\"error\"\n if (process.env.NODE_ENV !== \"production\" && variantProp === \"error\") {\n console.warn(\n '[Kumo Input]: variant=\"error\" is deprecated. ' +\n \"Error styling is now automatically applied when the `error` prop is truthy. \" +\n \"Simply remove the variant prop and pass an error message instead.\",\n );\n }\n\n // Auto-apply error styling when error prop is truthy\n // Explicit variant prop takes precedence for backwards compatibility\n const variant = variantProp ?? (error ? \"error\" : \"default\");\n\n // Extract required from inputProps to pass to Field for label decoration\n const { required } = inputProps;\n\n // A11y enforcement: warn in dev if no accessible name provided\n if (process.env.NODE_ENV !== \"production\") {\n const hasLabel = Boolean(label);\n const hasAriaLabel = Boolean(inputProps[\"aria-label\"]);\n const hasAriaLabelledBy = Boolean(inputProps[\"aria-labelledby\"]);\n\n if (!hasLabel && !hasAriaLabel && !hasAriaLabelledBy) {\n console.warn(\n \"[Kumo Input]: Input must have an accessible name. Provide either:\\n\" +\n \" - label prop: <Input label='Email' />\\n\" +\n \" - aria-label: <Input aria-label='Email address' />\\n\" +\n \" - aria-labelledby for custom label association\",\n );\n }\n }\n\n const input = (\n <BaseInput\n ref={ref}\n className={cn(\n inputVariants({ size, variant, focusIndicator: true }),\n className,\n )}\n {...inputProps}\n />\n );\n\n // Render with Field wrapper if label is provided\n if (label) {\n return (\n <Field\n label={label}\n required={required}\n labelTooltip={labelTooltip}\n description={description}\n error={\n error\n ? typeof error === \"string\"\n ? { message: error, match: true }\n : error\n : undefined\n }\n >\n {input}\n </Field>\n );\n }\n\n // Render bare input without Field wrapper\n return input;\n});\n\nInput.displayName = \"Input\";\n\n/**\n * Input component props with accessibility guidance.\n *\n * **Accessible Name Required:** Input should have one of:\n * 1. `label` prop (recommended) - enables Field wrapper with label/description/error\n * 2. `placeholder` + `aria-label` - for bare inputs with visual placeholder\n * 3. `aria-labelledby` - for custom label association\n *\n * Missing accessible names will trigger console warnings in development.\n *\n * @example\n * // Recommended: Built-in Field wrapper\n * <Input label=\"Email\" placeholder=\"you@example.com\" />\n *\n * @example\n * // Bare input with placeholder and aria-label\n * <Input placeholder=\"Search...\" aria-label=\"Search products\" />\n *\n * @example\n * // Custom label association\n * <label id=\"email-label\">Email</label>\n * <Input aria-labelledby=\"email-label\" />\n *\n * @example\n * // With description and error\n * <Input\n * label=\"Password\"\n * description=\"Must be at least 8 characters\"\n * error=\"Password is too short\"\n * />\n */\nexport type InputProps = Pick<KumoInputVariantsProps, \"size\" | \"variant\"> &\n BaseInputProps & {\n /** Label content for the input (enables Field wrapper) - can be a string or any React node */\n label?: ReactNode;\n /** Tooltip content to display next to the label via an info icon */\n labelTooltip?: ReactNode;\n /** Helper text displayed below the input */\n description?: ReactNode;\n /** Error message or validation error object */\n error?: string | { message: ReactNode; match: FieldErrorMatch };\n };\n"],"names":["KUMO_INPUT_VARIANTS","KUMO_INPUT_DEFAULT_VARIANTS","inputVariants","variant","size","parentFocusIndicator","focusIndicator","cn","resolveVariant","Input","forwardRef","props","ref","className","variantProp","label","labelTooltip","description","error","inputProps","required","hasLabel","hasAriaLabel","hasAriaLabelledBy","input","jsx","BaseInput","Field"],"mappings":";;;;;;;AAWO,MAAMA,IAAsB;AAAA,EACjC,MAAM;AAAA,IACJ,IAAI;AAAA,MACF,SAAS;AAAA,MACT,aAAa;AAAA,IAAA;AAAA,IAEf,IAAI;AAAA,MACF,SAAS;AAAA,MACT,aAAa;AAAA,IAAA;AAAA,IAEf,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,aAAa;AAAA,IAAA;AAAA,IAEf,IAAI;AAAA,MACF,SAAS;AAAA,MACT,aAAa;AAAA,IAAA;AAAA,EACf;AAAA,EAEF,SAAS;AAAA,IACP,SAAS;AAAA,MACP,SAAS;AAAA,MACT,aAAa;AAAA,IAAA;AAAA,IAEf,OAAO;AAAA,MACL,SAAS;AAAA,MACT,aAAa;AAAA,IAAA;AAAA,EACf;AAEJ,GAEaC,IAA8B;AAAA,EACzC,MAAM;AAAA,EACN,SAAS;AACX;AAwDO,SAASC,EAAc;AAAA,EAC5B,SAAAC,IAAUF,EAA4B;AAAA,EACtC,MAAAG,IAAOH,EAA4B;AAAA,EACnC,sBAAAI,IAAuB;AAAA,EACvB,gBAAAC,IAAiB;AACnB,IAA4B,IAAI;AAC9B,SAAOC;AAAA;AAAA,IAEL;AAAA;AAAA,IAEA;AAAA;AAAA,IAEAC,EAAeR,EAAoB,MAAMI,GAAMH,EAA4B,IAAI,EAAE;AAAA;AAAA,IAEjFO,EAAeR,EAAoB,SAASG,GAASF,EAA4B,OAAO,EAAE;AAAA;AAAA,IAE1FI,MACGF,MAAY,UACT,+DACA;AAAA,IACNG,MACGH,MAAY,UACT,iDACA;AAAA,EAAA;AAEV;AAEO,MAAMM,IAAQC,EAAyC,CAACC,GAAOC,MAAQ;AAC5E,QAAM;AAAA,IACJ,WAAAC;AAAA,IACA,MAAAT,IAAO;AAAA,IACP,SAASU;AAAA,IACT,OAAAC;AAAA,IACA,cAAAC;AAAA,IACA,aAAAC;AAAA,IACA,OAAAC;AAAA,IACA,GAAGC;AAAA,EAAA,IACDR;AAGJ,EAAI,QAAQ,IAAI,aAAa,gBAAgBG,MAAgB,WAC3D,QAAQ;AAAA,IACN;AAAA,EAAA;AAQJ,QAAMX,IAAUW,MAAgBI,IAAQ,UAAU,YAG5C,EAAE,UAAAE,MAAaD;AAGrB,MAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,UAAME,IAAW,EAAQN,GACnBO,IAAe,EAAQH,EAAW,YAAY,GAC9CI,IAAoB,EAAQJ,EAAW,iBAAiB;AAE9D,IAAI,CAACE,KAAY,CAACC,KAAgB,CAACC,KACjC,QAAQ;AAAA,MACN;AAAA;AAAA;AAAA;AAAA,IAAA;AAAA,EAMN;AAEA,QAAMC,IACJ,gBAAAC;AAAA,IAACC;AAAAA,IAAA;AAAA,MACC,KAAAd;AAAA,MACA,WAAWL;AAAA,QACTL,EAAc,EAAE,MAAAE,GAAM,SAAAD,GAAS,gBAAgB,IAAM;AAAA,QACrDU;AAAA,MAAA;AAAA,MAED,GAAGM;AAAA,IAAA;AAAA,EAAA;AAKR,SAAIJ,IAEA,gBAAAU;AAAA,IAACE;AAAA,IAAA;AAAA,MACC,OAAAZ;AAAA,MACA,UAAAK;AAAA,MACA,cAAAJ;AAAA,MACA,aAAAC;AAAA,MACA,OACEC,IACI,OAAOA,KAAU,WACf,EAAE,SAASA,GAAO,OAAO,GAAA,IACzBA,IACF;AAAA,MAGL,UAAAM;AAAA,IAAA;AAAA,EAAA,IAMAA;AACT,CAAC;AAEDf,EAAM,cAAc;"}
|
|
1
|
+
{"version":3,"file":"input-kmztt6h4mzy101ho.js","sources":["../../src/components/input/input.tsx"],"sourcesContent":["import { cn } from \"../../utils/cn\";\nimport { resolveVariant } from \"../../utils/resolve-variant\";\nimport {\n forwardRef,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from \"react\";\nimport { Input as BaseInput } from \"@base-ui/react/input\";\nimport { Field, type FieldErrorMatch } from \"../field/field\";\n\n/** Input size and variant definitions mapping names to their Tailwind classes. */\nexport const KUMO_INPUT_VARIANTS = {\n size: {\n xs: {\n classes: \"h-5 gap-1 rounded-sm px-1.5 text-xs\",\n description: \"Extra small input for compact UIs\",\n },\n sm: {\n classes: \"h-6.5 gap-1 rounded-md px-2 text-xs\",\n description: \"Small input for secondary fields\",\n },\n base: {\n classes: \"h-9 gap-1.5 rounded-lg px-3 text-base\",\n description: \"Default input size\",\n },\n lg: {\n classes: \"h-10 gap-2 rounded-lg px-4 text-base\",\n description: \"Large input for prominent fields\",\n },\n },\n variant: {\n default: {\n classes: \"focus:ring-kumo-focus/50 focus:ring-[1.5px]\",\n description: \"Default input appearance\",\n },\n error: {\n classes: \"!ring-kumo-danger focus:ring-kumo-danger/50 focus:ring-[1.5px]\",\n description: \"Error state for validation failures\",\n },\n },\n} as const;\n\nexport const KUMO_INPUT_DEFAULT_VARIANTS = {\n size: \"base\",\n variant: \"default\",\n} as const;\n\nexport const KUMO_INPUT_STYLING = {\n dimensions: {\n xs: { height: 20, paddingX: 6, fontSize: 12, borderRadius: 2, width: 160 },\n sm: { height: 26, paddingX: 8, fontSize: 12, borderRadius: 6, width: 200 },\n base: {\n height: 36,\n paddingX: 12,\n fontSize: 16,\n borderRadius: 8,\n width: 280,\n },\n lg: { height: 40, paddingX: 16, fontSize: 16, borderRadius: 8, width: 320 },\n },\n baseTokens: {\n background: \"color-secondary\",\n text: \"text-color-surface\",\n placeholder: \"text-color-muted\",\n ring: \"color-border\",\n },\n stateTokens: {\n focus: { ring: \"color-active\" },\n error: { ring: \"color-error\" },\n disabled: { opacity: 0.5, text: \"text-color-muted\" },\n },\n} as const;\n\n// Derived types from KUMO_INPUT_VARIANTS\nexport type KumoInputSize = keyof typeof KUMO_INPUT_VARIANTS.size;\nexport type KumoInputVariant = keyof typeof KUMO_INPUT_VARIANTS.variant;\n\nexport interface KumoInputVariantsProps {\n /**\n * Input size.\n * - `\"xs\"` — Extra small for compact UIs\n * - `\"sm\"` — Small for secondary fields\n * - `\"base\"` — Default size\n * - `\"lg\"` — Large for prominent fields\n * @default \"base\"\n */\n size?: KumoInputSize;\n /**\n * Visual variant.\n * - `\"default\"` — Standard input\n * - `\"error\"` — Error state for validation failures\n * @default \"default\"\n */\n variant?: KumoInputVariant;\n parentFocusIndicator?: boolean;\n focusIndicator?: boolean;\n}\n\n// Omit native `size` attribute (number) to avoid conflict with our custom `size` variant\ntype BaseInputProps = Omit<ComponentPropsWithoutRef<typeof BaseInput>, \"size\">;\n\nexport function inputVariants({\n variant = KUMO_INPUT_DEFAULT_VARIANTS.variant,\n size = KUMO_INPUT_DEFAULT_VARIANTS.size,\n parentFocusIndicator = false,\n focusIndicator = false,\n}: KumoInputVariantsProps = {}) {\n return cn(\n // Base styles\n \"border-0 bg-kumo-control text-kumo-default ring ring-kumo-line outline-none focus:outline-none\",\n // Disabled state and placeholder styles (using vanilla CSS class for Chrome compatibility)\n \"kumo-input-placeholder disabled:text-kumo-disabled\",\n // Apply size styles from KUMO_INPUT_VARIANTS\n resolveVariant(KUMO_INPUT_VARIANTS.size, size, KUMO_INPUT_DEFAULT_VARIANTS.size).classes,\n // Apply variant styles from KUMO_INPUT_VARIANTS\n resolveVariant(KUMO_INPUT_VARIANTS.variant, variant, KUMO_INPUT_DEFAULT_VARIANTS.variant).classes,\n // Focus state handling\n parentFocusIndicator &&\n (variant === \"error\"\n ? \"focus-within:ring-kumo-danger/50 focus-within:ring-[1.5px]\"\n : \"focus-within:ring-kumo-focus/50 focus-within:ring-[1.5px]\"),\n focusIndicator &&\n (variant === \"error\"\n ? \"focus:ring-kumo-danger/50 focus:ring-[1.5px]\"\n : \"focus:ring-kumo-focus/50 focus:ring-[1.5px]\"),\n );\n}\n\nexport const Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => {\n const {\n className,\n size = \"base\",\n variant: variantProp,\n label,\n labelTooltip,\n description,\n error,\n ...inputProps\n } = props;\n\n // Deprecation warning for variant=\"error\"\n if (process.env.NODE_ENV !== \"production\" && variantProp === \"error\") {\n console.warn(\n '[Kumo Input]: variant=\"error\" is deprecated. ' +\n \"Error styling is now automatically applied when the `error` prop is truthy. \" +\n \"Simply remove the variant prop and pass an error message instead.\",\n );\n }\n\n // Auto-apply error styling when error prop is truthy\n // Explicit variant prop takes precedence for backwards compatibility\n const variant = variantProp ?? (error ? \"error\" : \"default\");\n\n // Extract required from inputProps to pass to Field for label decoration\n const { required } = inputProps;\n\n // A11y enforcement: warn in dev if no accessible name provided\n if (process.env.NODE_ENV !== \"production\") {\n const hasLabel = Boolean(label);\n const hasAriaLabel = Boolean(inputProps[\"aria-label\"]);\n const hasAriaLabelledBy = Boolean(inputProps[\"aria-labelledby\"]);\n\n if (!hasLabel && !hasAriaLabel && !hasAriaLabelledBy) {\n console.warn(\n \"[Kumo Input]: Input must have an accessible name. Provide either:\\n\" +\n \" - label prop: <Input label='Email' />\\n\" +\n \" - aria-label: <Input aria-label='Email address' />\\n\" +\n \" - aria-labelledby for custom label association\",\n );\n }\n }\n\n const input = (\n <BaseInput\n ref={ref}\n className={cn(\n inputVariants({ size, variant, focusIndicator: true }),\n className,\n )}\n {...inputProps}\n />\n );\n\n // Render with Field wrapper if label is provided\n if (label) {\n return (\n <Field\n label={label}\n required={required}\n labelTooltip={labelTooltip}\n description={description}\n error={\n error\n ? typeof error === \"string\"\n ? { message: error, match: true }\n : error\n : undefined\n }\n >\n {input}\n </Field>\n );\n }\n\n // Render bare input without Field wrapper\n return input;\n});\n\nInput.displayName = \"Input\";\n\n/**\n * Input component props with accessibility guidance.\n *\n * **Accessible Name Required:** Input should have one of:\n * 1. `label` prop (recommended) - enables Field wrapper with label/description/error\n * 2. `placeholder` + `aria-label` - for bare inputs with visual placeholder\n * 3. `aria-labelledby` - for custom label association\n *\n * Missing accessible names will trigger console warnings in development.\n *\n * @example\n * // Recommended: Built-in Field wrapper\n * <Input label=\"Email\" placeholder=\"you@example.com\" />\n *\n * @example\n * // Bare input with placeholder and aria-label\n * <Input placeholder=\"Search...\" aria-label=\"Search products\" />\n *\n * @example\n * // Custom label association\n * <label id=\"email-label\">Email</label>\n * <Input aria-labelledby=\"email-label\" />\n *\n * @example\n * // With description and error\n * <Input\n * label=\"Password\"\n * description=\"Must be at least 8 characters\"\n * error=\"Password is too short\"\n * />\n */\nexport type InputProps = Pick<KumoInputVariantsProps, \"size\" | \"variant\"> &\n BaseInputProps & {\n /** Label content for the input (enables Field wrapper) - can be a string or any React node */\n label?: ReactNode;\n /** Tooltip content to display next to the label via an info icon */\n labelTooltip?: ReactNode;\n /** Helper text displayed below the input */\n description?: ReactNode;\n /** Error message or validation error object */\n error?: string | { message: ReactNode; match: FieldErrorMatch };\n };\n"],"names":["KUMO_INPUT_VARIANTS","KUMO_INPUT_DEFAULT_VARIANTS","inputVariants","variant","size","parentFocusIndicator","focusIndicator","cn","resolveVariant","Input","forwardRef","props","ref","className","variantProp","label","labelTooltip","description","error","inputProps","required","hasLabel","hasAriaLabel","hasAriaLabelledBy","input","jsx","BaseInput","Field"],"mappings":";;;;;;;AAWO,MAAMA,IAAsB;AAAA,EACjC,MAAM;AAAA,IACJ,IAAI;AAAA,MACF,SAAS;AAAA,MACT,aAAa;AAAA,IAAA;AAAA,IAEf,IAAI;AAAA,MACF,SAAS;AAAA,MACT,aAAa;AAAA,IAAA;AAAA,IAEf,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,aAAa;AAAA,IAAA;AAAA,IAEf,IAAI;AAAA,MACF,SAAS;AAAA,MACT,aAAa;AAAA,IAAA;AAAA,EACf;AAAA,EAEF,SAAS;AAAA,IACP,SAAS;AAAA,MACP,SAAS;AAAA,MACT,aAAa;AAAA,IAAA;AAAA,IAEf,OAAO;AAAA,MACL,SAAS;AAAA,MACT,aAAa;AAAA,IAAA;AAAA,EACf;AAEJ,GAEaC,IAA8B;AAAA,EACzC,MAAM;AAAA,EACN,SAAS;AACX;AAwDO,SAASC,EAAc;AAAA,EAC5B,SAAAC,IAAUF,EAA4B;AAAA,EACtC,MAAAG,IAAOH,EAA4B;AAAA,EACnC,sBAAAI,IAAuB;AAAA,EACvB,gBAAAC,IAAiB;AACnB,IAA4B,IAAI;AAC9B,SAAOC;AAAA;AAAA,IAEL;AAAA;AAAA,IAEA;AAAA;AAAA,IAEAC,EAAeR,EAAoB,MAAMI,GAAMH,EAA4B,IAAI,EAAE;AAAA;AAAA,IAEjFO,EAAeR,EAAoB,SAASG,GAASF,EAA4B,OAAO,EAAE;AAAA;AAAA,IAE1FI,MACGF,MAAY,UACT,+DACA;AAAA,IACNG,MACGH,MAAY,UACT,iDACA;AAAA,EAAA;AAEV;AAEO,MAAMM,IAAQC,EAAyC,CAACC,GAAOC,MAAQ;AAC5E,QAAM;AAAA,IACJ,WAAAC;AAAA,IACA,MAAAT,IAAO;AAAA,IACP,SAASU;AAAA,IACT,OAAAC;AAAA,IACA,cAAAC;AAAA,IACA,aAAAC;AAAA,IACA,OAAAC;AAAA,IACA,GAAGC;AAAA,EAAA,IACDR;AAGJ,EAAI,QAAQ,IAAI,aAAa,gBAAgBG,MAAgB,WAC3D,QAAQ;AAAA,IACN;AAAA,EAAA;AAQJ,QAAMX,IAAUW,MAAgBI,IAAQ,UAAU,YAG5C,EAAE,UAAAE,MAAaD;AAGrB,MAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,UAAME,IAAW,EAAQN,GACnBO,IAAe,EAAQH,EAAW,YAAY,GAC9CI,IAAoB,EAAQJ,EAAW,iBAAiB;AAE9D,IAAI,CAACE,KAAY,CAACC,KAAgB,CAACC,KACjC,QAAQ;AAAA,MACN;AAAA;AAAA;AAAA;AAAA,IAAA;AAAA,EAMN;AAEA,QAAMC,IACJ,gBAAAC;AAAA,IAACC;AAAAA,IAAA;AAAA,MACC,KAAAd;AAAA,MACA,WAAWL;AAAA,QACTL,EAAc,EAAE,MAAAE,GAAM,SAAAD,GAAS,gBAAgB,IAAM;AAAA,QACrDU;AAAA,MAAA;AAAA,MAED,GAAGM;AAAA,IAAA;AAAA,EAAA;AAKR,SAAIJ,IAEA,gBAAAU;AAAA,IAACE;AAAA,IAAA;AAAA,MACC,OAAAZ;AAAA,MACA,UAAAK;AAAA,MACA,cAAAJ;AAAA,MACA,aAAAC;AAAA,MACA,OACEC,IACI,OAAOA,KAAU,WACf,EAAE,SAASA,GAAO,OAAO,GAAA,IACzBA,IACF;AAAA,MAGL,UAAAM;AAAA,IAAA;AAAA,EAAA,IAMAA;AACT,CAAC;AAEDf,EAAM,cAAc;"}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { jsx as e, jsxs as c, Fragment as f } from "react/jsx-runtime";
|
|
3
3
|
import { Info as u } from "@phosphor-icons/react";
|
|
4
4
|
import { c as a } from "./cn-ct4n7r74mh8y0f48.js";
|
|
5
|
-
import { B as p } from "./button-
|
|
6
|
-
import { T as b } from "./tooltip-
|
|
5
|
+
import { B as p } from "./button-n859eyw550yi2b9z.js";
|
|
6
|
+
import { T as b } from "./tooltip-fjxy4s4l75hjxp1x.js";
|
|
7
7
|
const T = {
|
|
8
8
|
// Label currently has no variant options but structure is ready for future additions
|
|
9
9
|
}, B = {};
|
|
@@ -65,4 +65,4 @@ export {
|
|
|
65
65
|
B as b,
|
|
66
66
|
d as l
|
|
67
67
|
};
|
|
68
|
-
//# sourceMappingURL=label-
|
|
68
|
+
//# sourceMappingURL=label-d14ibjmcbk1qmyrt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"label-
|
|
1
|
+
{"version":3,"file":"label-d14ibjmcbk1qmyrt.js","sources":["../../src/components/label/label.tsx"],"sourcesContent":["import { Info } from \"@phosphor-icons/react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Button } from \"../button\";\nimport { Tooltip } from \"../tooltip\";\n\n/** Label variant definitions (currently empty, reserved for future additions). */\nexport const KUMO_LABEL_VARIANTS = {\n // Label currently has no variant options but structure is ready for future additions\n} as const;\n\nexport const KUMO_LABEL_DEFAULT_VARIANTS = {} as const;\n\n// Derived types from KUMO_LABEL_VARIANTS\nexport interface KumoLabelVariantsProps {}\n\nexport function labelVariants(_props: KumoLabelVariantsProps = {}) {\n return cn(\n // Base styles - when used standalone, apply text styling\n // When used inside Field, the parent FieldBase.Label provides these styles\n \"m-0 text-base font-medium text-kumo-default\",\n );\n}\n\nexport function labelContentVariants() {\n return cn(\n // Content wrapper styles - always applied\n \"inline-flex items-center gap-1\",\n );\n}\n\n/**\n * Label component props.\n *\n * @example\n * ```tsx\n * <Label>Email</Label>\n * <Label showOptional>Middle Name</Label>\n * <Label tooltip=\"We'll use this to send you updates\">Email</Label>\n * ```\n */\nexport interface LabelProps extends KumoLabelVariantsProps {\n /** The label content — can be a string or any React node. */\n children: ReactNode;\n /** When `true`, shows gray \"(optional)\" text after the label. */\n showOptional?: boolean;\n /** Tooltip content displayed next to the label via an info icon. */\n tooltip?: ReactNode;\n /** Additional CSS classes merged via `cn()`. */\n className?: string;\n /** The id of the form element this label is associated with */\n htmlFor?: string;\n /**\n * When true, only renders the inline content (indicators, tooltip) without\n * the outer label element with font styling. Useful when composed inside another\n * label element that already provides the text styling.\n * @default false\n */\n asContent?: boolean;\n}\n\n/**\n * Label component for form fields.\n *\n * Provides a standardized way to display labels with optional indicators:\n * - Optional indicator: gray \"(optional)\" text when `showOptional={true}`\n * - Tooltip: info icon with hover tooltip for additional context\n *\n * @example\n * // Basic label\n * <Label>Email</Label>\n *\n * @example\n * // Optional field with indicator\n * <Label showOptional>Middle Name</Label>\n *\n * @example\n * // With tooltip\n * <Label tooltip=\"We'll use this to send you updates\">Email</Label>\n *\n * @example\n * // With ReactNode children\n * <Label>\n * <span>Custom label with <strong>bold</strong> text</span>\n * </Label>\n */\nexport function Label({\n children,\n showOptional = false,\n tooltip,\n className,\n htmlFor,\n asContent = false,\n}: LabelProps) {\n const content = (\n <>\n {children}\n {showOptional && (\n <span className=\"font-normal text-kumo-subtle\">(optional)</span>\n )}\n {tooltip && (\n <Tooltip\n content={tooltip}\n render={\n <Button\n variant=\"ghost\"\n size=\"xs\"\n shape=\"square\"\n aria-label=\"More information\"\n >\n <Info className=\"size-4\" />\n </Button>\n }\n />\n )}\n </>\n );\n\n // When used as content inside another styled element, just render inline\n if (asContent) {\n return (\n <span className={cn(labelContentVariants(), className)}>{content}</span>\n );\n }\n\n // When used standalone, render as <label> for accessibility\n return (\n <label\n htmlFor={htmlFor}\n className={cn(labelVariants(), labelContentVariants(), className)}\n >\n {content}\n </label>\n );\n}\n\nLabel.displayName = \"Label\";\n"],"names":["KUMO_LABEL_VARIANTS","KUMO_LABEL_DEFAULT_VARIANTS","labelVariants","_props","cn","labelContentVariants","Label","children","showOptional","tooltip","className","htmlFor","asContent","content","jsxs","Fragment","jsx","Tooltip","Button","Info"],"mappings":";;;;;;AAOO,MAAMA,IAAsB;AAAA;AAEnC,GAEaC,IAA8B,CAAA;AAKpC,SAASC,EAAcC,IAAiC,IAAI;AACjE,SAAOC;AAAA;AAAA;AAAA,IAGL;AAAA,EAAA;AAEJ;AAEO,SAASC,IAAuB;AACrC,SAAOD;AAAA;AAAA,IAEL;AAAA,EAAA;AAEJ;AAyDO,SAASE,EAAM;AAAA,EACpB,UAAAC;AAAA,EACA,cAAAC,IAAe;AAAA,EACf,SAAAC;AAAA,EACA,WAAAC;AAAA,EACA,SAAAC;AAAA,EACA,WAAAC,IAAY;AACd,GAAe;AACb,QAAMC,IACJ,gBAAAC,EAAAC,GAAA,EACG,UAAA;AAAA,IAAAR;AAAA,IACAC,KACC,gBAAAQ,EAAC,QAAA,EAAK,WAAU,gCAA+B,UAAA,cAAU;AAAA,IAE1DP,KACC,gBAAAO;AAAA,MAACC;AAAA,MAAA;AAAA,QACC,SAASR;AAAA,QACT,QACE,gBAAAO;AAAA,UAACE;AAAA,UAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,OAAM;AAAA,YACN,cAAW;AAAA,YAEX,UAAA,gBAAAF,EAACG,GAAA,EAAK,WAAU,SAAA,CAAS;AAAA,UAAA;AAAA,QAAA;AAAA,MAC3B;AAAA,IAAA;AAAA,EAEJ,GAEJ;AAIF,SAAIP,IAEA,gBAAAI,EAAC,UAAK,WAAWZ,EAAGC,KAAwBK,CAAS,GAAI,UAAAG,GAAQ,IAMnE,gBAAAG;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,SAAAL;AAAA,MACA,WAAWP,EAAGF,EAAA,GAAiBG,EAAA,GAAwBK,CAAS;AAAA,MAE/D,UAAAG;AAAA,IAAA;AAAA,EAAA;AAGP;AAEAP,EAAM,cAAc;"}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as s } from "react/jsx-runtime";
|
|
3
3
|
import { forwardRef as y, Children as p, isValidElement as C, Fragment as g } from "react";
|
|
4
|
-
import { c as
|
|
5
|
-
import { aU as L, aV as S } from "./vendor-base-ui-
|
|
4
|
+
import { c as n } from "./cn-ct4n7r74mh8y0f48.js";
|
|
5
|
+
import { aU as L, aV as S } from "./vendor-base-ui-epfrwb4nfbd4btaz.js";
|
|
6
6
|
const A = "overflow-hidden rounded-lg bg-kumo-base shadow-xs ring ring-kumo-line", R = "flex w-full flex-col overflow-hidden rounded-lg bg-kumo-elevated text-base ring ring-kumo-hairline", _ = "-my-2 flex items-center gap-2 bg-kumo-elevated p-4 text-base font-medium text-kumo-subtle", E = "relative flex flex-col gap-2 overflow-hidden rounded-lg bg-kumo-base p-4 pr-3 text-inherit no-underline ring ring-kumo-fill";
|
|
7
7
|
function x(r = {}) {
|
|
8
|
-
return
|
|
8
|
+
return n(A);
|
|
9
9
|
}
|
|
10
10
|
function i(r) {
|
|
11
|
-
return p.toArray(r).some((e) => C(e) ? e.type ===
|
|
11
|
+
return p.toArray(r).some((e) => C(e) ? e.type === o || e.type === t ? !0 : e.type === g ? i(e.props.children) : !1 : !1);
|
|
12
12
|
}
|
|
13
|
-
const d = y(function({ children: e, className:
|
|
13
|
+
const d = y(function({ children: e, className: a, render: l, ...m }, u) {
|
|
14
14
|
const f = i(e), c = {
|
|
15
|
-
className:
|
|
15
|
+
className: n(
|
|
16
16
|
f ? R : x(),
|
|
17
|
-
|
|
17
|
+
a
|
|
18
18
|
)
|
|
19
19
|
};
|
|
20
20
|
return L({
|
|
@@ -24,23 +24,24 @@ const d = y(function({ children: e, className: o, render: l, ...m }, u) {
|
|
|
24
24
|
props: S(c, m, { children: e })
|
|
25
25
|
});
|
|
26
26
|
});
|
|
27
|
-
function
|
|
27
|
+
function t({
|
|
28
28
|
children: r,
|
|
29
|
-
className: e
|
|
29
|
+
className: e,
|
|
30
|
+
...a
|
|
30
31
|
}) {
|
|
31
|
-
return /* @__PURE__ */ s("div", { className:
|
|
32
|
+
return /* @__PURE__ */ s("div", { className: n(_, e), ...a, children: r });
|
|
32
33
|
}
|
|
33
|
-
function
|
|
34
|
-
return /* @__PURE__ */ s("div", { className:
|
|
34
|
+
function o({ children: r, className: e, ...a }) {
|
|
35
|
+
return /* @__PURE__ */ s("div", { className: n(E, e), ...a, children: r });
|
|
35
36
|
}
|
|
36
37
|
d.displayName = "LayerCard";
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
t.displayName = "LayerCard.Secondary";
|
|
39
|
+
o.displayName = "LayerCard.Primary";
|
|
39
40
|
const h = Object.assign(d, {
|
|
40
|
-
Primary:
|
|
41
|
-
Secondary:
|
|
41
|
+
Primary: o,
|
|
42
|
+
Secondary: t
|
|
42
43
|
});
|
|
43
44
|
export {
|
|
44
45
|
h as L
|
|
45
46
|
};
|
|
46
|
-
//# sourceMappingURL=layer-card-
|
|
47
|
+
//# sourceMappingURL=layer-card-eomdoafn3sfpih1d.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layer-card-eomdoafn3sfpih1d.js","sources":["../../src/components/layer-card/layer-card.tsx"],"sourcesContent":["import {\n Children,\n Fragment,\n forwardRef,\n isValidElement,\n type ComponentPropsWithoutRef,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { mergeProps } from \"@base-ui/react/merge-props\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { cn } from \"../../utils/cn\";\n\nconst LAYER_CARD_SURFACE_CLASSES =\n \"overflow-hidden rounded-lg bg-kumo-base shadow-xs ring ring-kumo-line\";\nconst LAYER_CARD_LAYERED_ROOT_CLASSES =\n \"flex w-full flex-col overflow-hidden rounded-lg bg-kumo-elevated text-base ring ring-kumo-hairline\";\nconst LAYER_CARD_SECONDARY_CLASSES =\n \"-my-2 flex items-center gap-2 bg-kumo-elevated p-4 text-base font-medium text-kumo-subtle\";\nconst LAYER_CARD_PRIMARY_CLASSES =\n \"relative flex flex-col gap-2 overflow-hidden rounded-lg bg-kumo-base p-4 pr-3 text-inherit no-underline ring ring-kumo-fill\";\n\n/** LayerCard variant definitions (currently empty, reserved for future additions). */\nexport const KUMO_LAYER_CARD_VARIANTS = {\n // LayerCard currently has no variant options but structure is ready for future additions\n} as const;\n\nexport const KUMO_LAYER_CARD_DEFAULT_VARIANTS = {} as const;\n\n// Derived types from KUMO_LAYER_CARD_VARIANTS\nexport interface KumoLayerCardVariantsProps {}\n\nexport function layerCardVariants(_props: KumoLayerCardVariantsProps = {}) {\n return cn(LAYER_CARD_SURFACE_CLASSES);\n}\n\nfunction hasLayerCardSections(children: ReactNode): boolean {\n return Children.toArray(children).some((child): boolean => {\n if (!isValidElement(child)) {\n return false;\n }\n\n if (child.type === LayerCardPrimary || child.type === LayerCardSecondary) {\n return true;\n }\n\n if (child.type === Fragment) {\n const fragmentChild = child as ReactElement<{ children?: ReactNode }>;\n return hasLayerCardSections(fragmentChild.props.children);\n }\n\n return false;\n });\n}\n\n/**\n * LayerCard component props.\n *\n * @example\n * ```tsx\n * <LayerCard className=\"p-4\">\n * Get started with Kumo\n * </LayerCard>\n *\n * <LayerCard>\n * <LayerCard.Secondary>Next Steps</LayerCard.Secondary>\n * <LayerCard.Primary>Get started with Kumo</LayerCard.Primary>\n * </LayerCard>\n * ```\n */\nexport type LayerCardProps = useRender.ComponentProps<\"div\"> &\n KumoLayerCardVariantsProps;\n\nexport type LayerCardSectionProps = ComponentPropsWithoutRef<\"div\">;\n\n/**\n * Card container for both simple surfaces and layered layouts.\n *\n * Render children directly for a single-surface card, or use\n * `LayerCard.Secondary` and `LayerCard.Primary` for the layered card treatment.\n *\n * @example\n * ```tsx\n * <LayerCard className=\"rounded-lg p-4\">Card content</LayerCard>\n * ```\n *\n * @example\n * ```tsx\n * <LayerCard>\n * <LayerCard.Secondary>Getting Started</LayerCard.Secondary>\n * <LayerCard.Primary>Quick start guide</LayerCard.Primary>\n * </LayerCard>\n * ```\n */\nconst LayerCardRoot = forwardRef<HTMLDivElement, LayerCardProps>(function LayerCard(\n { children, className, render, ...props },\n ref,\n) {\n const hasStructuredLayers = hasLayerCardSections(children);\n\n const defaultProps: useRender.ElementProps<\"div\"> = {\n className: cn(\n hasStructuredLayers ? LAYER_CARD_LAYERED_ROOT_CLASSES : layerCardVariants(),\n className,\n ),\n };\n\n return useRender({\n defaultTagName: \"div\",\n render,\n ref,\n props: mergeProps<\"div\">(defaultProps, props, { children }),\n });\n});\n\nfunction LayerCardSecondary({\n children,\n className,\n ...props\n}: LayerCardSectionProps) {\n return <div className={cn(LAYER_CARD_SECONDARY_CLASSES, className)} {...props}>{children}</div>;\n}\n\nfunction LayerCardPrimary({ children, className, ...props }: LayerCardSectionProps) {\n return <div className={cn(LAYER_CARD_PRIMARY_CLASSES, className)} {...props}>{children}</div>;\n}\n\nLayerCardRoot.displayName = \"LayerCard\";\nLayerCardSecondary.displayName = \"LayerCard.Secondary\";\nLayerCardPrimary.displayName = \"LayerCard.Primary\";\n\ntype LayerCardComponent = typeof LayerCardRoot & {\n Primary: typeof LayerCardPrimary;\n Secondary: typeof LayerCardSecondary;\n};\n\nconst LayerCard = Object.assign(LayerCardRoot, {\n Primary: LayerCardPrimary,\n Secondary: LayerCardSecondary,\n}) as LayerCardComponent;\n\nexport { LayerCard };\n"],"names":["LAYER_CARD_SURFACE_CLASSES","LAYER_CARD_LAYERED_ROOT_CLASSES","LAYER_CARD_SECONDARY_CLASSES","LAYER_CARD_PRIMARY_CLASSES","layerCardVariants","_props","cn","hasLayerCardSections","children","Children","child","isValidElement","LayerCardPrimary","LayerCardSecondary","Fragment","LayerCardRoot","forwardRef","className","render","props","ref","hasStructuredLayers","defaultProps","useRender","mergeProps","jsx","LayerCard"],"mappings":";;;;;AAaA,MAAMA,IACJ,yEACIC,IACJ,sGACIC,IACJ,6FACIC,IACJ;AAYK,SAASC,EAAkBC,IAAqC,IAAI;AACzE,SAAOC,EAAGN,CAA0B;AACtC;AAEA,SAASO,EAAqBC,GAA8B;AAC1D,SAAOC,EAAS,QAAQD,CAAQ,EAAE,KAAK,CAACE,MACjCC,EAAeD,CAAK,IAIrBA,EAAM,SAASE,KAAoBF,EAAM,SAASG,IAC7C,KAGLH,EAAM,SAASI,IAEVP,EADeG,EACoB,MAAM,QAAQ,IAGnD,KAZE,EAaV;AACH;AAyCA,MAAMK,IAAgBC,EAA2C,SAC/D,EAAE,UAAAR,GAAU,WAAAS,GAAW,QAAAC,GAAQ,GAAGC,EAAA,GAClCC,GACA;AACA,QAAMC,IAAsBd,EAAqBC,CAAQ,GAEnDc,IAA8C;AAAA,IAClD,WAAWhB;AAAA,MACTe,IAAsBpB,IAAkCG,EAAA;AAAA,MACxDa;AAAA,IAAA;AAAA,EACF;AAGF,SAAOM,EAAU;AAAA,IACf,gBAAgB;AAAA,IAChB,QAAAL;AAAA,IACA,KAAAE;AAAA,IACA,OAAOI,EAAkBF,GAAcH,GAAO,EAAE,UAAAX,GAAU;AAAA,EAAA,CAC3D;AACH,CAAC;AAED,SAASK,EAAmB;AAAA,EAC1B,UAAAL;AAAA,EACA,WAAAS;AAAA,EACA,GAAGE;AACL,GAA0B;AACxB,SAAO,gBAAAM,EAAC,SAAI,WAAWnB,EAAGJ,GAA8Be,CAAS,GAAI,GAAGE,GAAQ,UAAAX,GAAS;AAC3F;AAEA,SAASI,EAAiB,EAAE,UAAAJ,GAAU,WAAAS,GAAW,GAAGE,KAAgC;AAClF,SAAO,gBAAAM,EAAC,SAAI,WAAWnB,EAAGH,GAA4Bc,CAAS,GAAI,GAAGE,GAAQ,UAAAX,GAAS;AACzF;AAEAO,EAAc,cAAc;AAC5BF,EAAmB,cAAc;AACjCD,EAAiB,cAAc;AAO/B,MAAMc,IAAY,OAAO,OAAOX,GAAe;AAAA,EAC7C,SAASH;AAAA,EACT,WAAWC;AACb,CAAC;"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsxs as
|
|
3
|
-
import { forwardRef as k } from "react";
|
|
4
|
-
import { c as
|
|
5
|
-
import { r as
|
|
6
|
-
import { u as
|
|
7
|
-
import { aU as x, aV as
|
|
8
|
-
const
|
|
2
|
+
import { jsxs as d, jsx as i } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef as k, useEffect as f } from "react";
|
|
4
|
+
import { c as r } from "./cn-ct4n7r74mh8y0f48.js";
|
|
5
|
+
import { r as L } from "./resolve-variant-gw6eh7fa4st8ej7m.js";
|
|
6
|
+
import { u as h } from "./link-provider-mn2voeohon7cj9o4.js";
|
|
7
|
+
import { aU as x, aV as v } from "./vendor-base-ui-epfrwb4nfbd4btaz.js";
|
|
8
|
+
const o = (n) => /* @__PURE__ */ d(
|
|
9
9
|
"svg",
|
|
10
10
|
{
|
|
11
11
|
width: "1em",
|
|
@@ -19,12 +19,12 @@ const r = (n) => /* @__PURE__ */ p(
|
|
|
19
19
|
className: "link-external-icon",
|
|
20
20
|
...n,
|
|
21
21
|
children: [
|
|
22
|
-
/* @__PURE__ */
|
|
23
|
-
/* @__PURE__ */
|
|
22
|
+
/* @__PURE__ */ i("path", { d: "M9 4H8.8C7.11984 4 6.27976 4 5.63803 4.32698C5.07354 4.6146 4.6146 5.07354 4.32698 5.63803C4 6.27976 4 7.11984 4 8.8V15.2C4 16.8802 4 17.7202 4.32698 18.362C4.6146 18.9265 5.07354 19.3854 5.63803 19.673C6.27976 20 7.11984 20 8.8 20H15.2C16.8802 20 17.7202 20 18.362 19.673C18.9265 19.3854 19.3854 18.9265 19.673 18.362C20 17.7202 20 16.8802 20 15.2V15" }),
|
|
23
|
+
/* @__PURE__ */ i("path", { d: "M14 4H20M20 4V10M20 4L11 13" })
|
|
24
24
|
]
|
|
25
25
|
}
|
|
26
26
|
);
|
|
27
|
-
|
|
27
|
+
o.displayName = "Link.ExternalIcon";
|
|
28
28
|
const C = {
|
|
29
29
|
variant: {
|
|
30
30
|
inline: {
|
|
@@ -49,32 +49,46 @@ const C = {
|
|
|
49
49
|
}, t = {
|
|
50
50
|
variant: "inline"
|
|
51
51
|
};
|
|
52
|
-
function
|
|
52
|
+
function g({
|
|
53
53
|
variant: n = t.variant
|
|
54
54
|
} = {}) {
|
|
55
|
-
return
|
|
55
|
+
return r(L(C.variant, n, t.variant).classes);
|
|
56
56
|
}
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
const s = k(function({ className: a, variant: l = "inline", render: c, ...e }, u) {
|
|
58
|
+
const m = h();
|
|
59
|
+
process.env.NODE_ENV !== "production" && f(() => {
|
|
60
|
+
"to" in e && e.to !== void 0 && console.warn(
|
|
61
|
+
`[kumo] Link: The \`to\` prop is deprecated. Use \`href\` instead.
|
|
62
|
+
|
|
63
|
+
If your app uses a client-side router, configure a LinkProvider that
|
|
64
|
+
maps \`href\` to your router's navigation prop. See:
|
|
65
|
+
https://kumo.cfops.it/utilities/link-provider
|
|
66
|
+
|
|
67
|
+
Migration example:
|
|
68
|
+
Before: <Link to="/page">…</Link>
|
|
69
|
+
After: <Link href="/page">…</Link>`
|
|
70
|
+
);
|
|
71
|
+
}, []);
|
|
72
|
+
const p = {
|
|
73
|
+
className: r(
|
|
74
|
+
g({ variant: l }),
|
|
61
75
|
"group/link inline-flex items-center gap-[0.1875em]"
|
|
62
76
|
)
|
|
63
77
|
};
|
|
64
78
|
return x({
|
|
65
|
-
render:
|
|
66
|
-
ref:
|
|
67
|
-
props:
|
|
79
|
+
render: c ?? /* @__PURE__ */ i(m, {}),
|
|
80
|
+
ref: u,
|
|
81
|
+
props: v(p, e, { className: a })
|
|
68
82
|
});
|
|
69
83
|
});
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
ExternalIcon:
|
|
84
|
+
s.displayName = "Link";
|
|
85
|
+
const _ = Object.assign(s, {
|
|
86
|
+
ExternalIcon: o
|
|
73
87
|
});
|
|
74
88
|
export {
|
|
75
89
|
C as K,
|
|
76
|
-
|
|
90
|
+
_ as L,
|
|
77
91
|
t as a,
|
|
78
|
-
|
|
92
|
+
g as l
|
|
79
93
|
};
|
|
80
|
-
//# sourceMappingURL=link-
|
|
94
|
+
//# sourceMappingURL=link-ihastr6a2dmo1so5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-ihastr6a2dmo1so5.js","sources":["../../src/components/link/link.tsx"],"sourcesContent":["import { forwardRef, useEffect, type SVGProps } from \"react\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { mergeProps } from \"@base-ui/react/merge-props\";\nimport { cn } from \"../../utils/cn\";\nimport { resolveVariant } from \"../../utils/resolve-variant\";\nimport {\n useLinkComponent,\n type LinkComponentProps,\n} from \"../../utils/link-provider\";\n\n/**\n * ExternalIcon - Visual indicator for links that open in a new tab/window.\n *\n * Use this as a child of Link to indicate external navigation:\n * ```tsx\n * <Link href=\"https://example.com\" target=\"_blank\" rel=\"noopener noreferrer\">\n * Visit Example <Link.ExternalIcon />\n * </Link>\n * ```\n */\nconst ExternalIcon = (props: SVGProps<SVGSVGElement>) => (\n <svg\n width=\"1em\"\n height=\"1em\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n className=\"link-external-icon\"\n {...props}\n >\n <path d=\"M9 4H8.8C7.11984 4 6.27976 4 5.63803 4.32698C5.07354 4.6146 4.6146 5.07354 4.32698 5.63803C4 6.27976 4 7.11984 4 8.8V15.2C4 16.8802 4 17.7202 4.32698 18.362C4.6146 18.9265 5.07354 19.3854 5.63803 19.673C6.27976 20 7.11984 20 8.8 20H15.2C16.8802 20 17.7202 20 18.362 19.673C18.9265 19.3854 19.3854 18.9265 19.673 18.362C20 17.7202 20 16.8802 20 15.2V15\" />\n <path d=\"M14 4H20M20 4V10M20 4L11 13\" />\n </svg>\n);\n\nExternalIcon.displayName = \"Link.ExternalIcon\";\n\n/** Link variant definitions mapping variant names to their Tailwind classes. */\nexport const KUMO_LINK_VARIANTS = {\n variant: {\n inline: {\n classes:\n // text-kumo-link provides defensive color that won't be overridden by global `a` styles\n \"text-kumo-link underline underline-offset-[0.15em] decoration-[0.0625em] link-current transition-colors\",\n description: \"Inline text link that flows with content\",\n },\n current: {\n classes:\n \"text-current underline underline-offset-[0.15em] decoration-[0.0625em] link-current transition-colors\",\n description: \"Link that inherits color from parent text\",\n },\n plain: {\n classes:\n // text-kumo-link provides defensive color that won't be overridden by global `a` styles\n \"text-kumo-link hover:text-kumo-link/70 transition-colors\",\n description: \"Link without underline decoration\",\n },\n },\n} as const;\n\nexport const KUMO_LINK_DEFAULT_VARIANTS = {\n variant: \"inline\",\n} as const;\n\nexport type KumoLinkVariant = keyof typeof KUMO_LINK_VARIANTS.variant;\n\nexport interface KumoLinkVariantsProps {\n /**\n * Visual style of the link.\n * - `\"inline\"` — Inline text link that flows with content\n * - `\"current\"` — Link that inherits color from parent text\n * - `\"plain\"` — Link without underline decoration\n * @default \"inline\"\n */\n variant?: KumoLinkVariant;\n}\n\nexport function linkVariants({\n variant = KUMO_LINK_DEFAULT_VARIANTS.variant,\n}: KumoLinkVariantsProps = {}) {\n return cn(resolveVariant(KUMO_LINK_VARIANTS.variant, variant, KUMO_LINK_DEFAULT_VARIANTS.variant).classes);\n}\n\n/**\n * Link component props.\n *\n * Use `href` for the link destination. For framework-specific routing, use the\n * `render` prop or configure a `LinkProvider` at the app root.\n *\n * @example Internal link\n * ```tsx\n * <Link href=\"/docs\">Learn more</Link>\n * ```\n *\n * @example External link\n * ```tsx\n * <Link href=\"https://cloudflare.com\" target=\"_blank\" rel=\"noopener noreferrer\">\n * Visit Cloudflare <Link.ExternalIcon />\n * </Link>\n * ```\n *\n * @example Composition with render prop\n * ```tsx\n * <Link render={<RouterLink to=\"/dashboard\" />}>Dashboard</Link>\n * ```\n */\nexport type LinkProps = useRender.ComponentProps<\"a\"> &\n LinkComponentProps &\n KumoLinkVariantsProps;\n\n/**\n * Link component for consistent inline text links.\n *\n * Link is a **presentational component** — it handles visual styling and\n * accessibility. Routing behavior belongs in the application layer, via\n * either the `render` prop or a `LinkProvider`.\n *\n * - Without `render`: renders via LinkProvider (default `<a>` or configured component)\n * - With `render`: merges props onto the provided element with proper ref/event handling\n *\n * @example Basic usage\n * ```tsx\n * <Link href=\"/docs\">Learn more</Link>\n * ```\n *\n * @example External link with icon\n * ```tsx\n * <Link href=\"https://cloudflare.com\" target=\"_blank\" rel=\"noopener noreferrer\">\n * Visit Cloudflare <Link.ExternalIcon />\n * </Link>\n * ```\n *\n * @example Composition with React Router via render prop\n * ```tsx\n * <Link render={<RouterLink to=\"/dashboard\" />} variant=\"inline\">\n * Dashboard\n * </Link>\n * ```\n *\n * @example Composition via LinkProvider (recommended for app-wide routing)\n * ```tsx\n * // App root:\n * <LinkProvider component={AppLink}>\n * <App />\n * </LinkProvider>\n *\n * // Then use href everywhere:\n * <Link href=\"/dashboard\">Dashboard</Link>\n * <Link href=\"https://example.com\" target=\"_blank\">External</Link>\n * ```\n */\nconst LinkBase = forwardRef<HTMLAnchorElement, LinkProps>(function Link(\n { className, variant = \"inline\", render, ...props },\n ref,\n) {\n const LinkComponent = useLinkComponent();\n\n if (process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line react-hooks/rules-of-hooks -- dev-only, conditional is stable\n useEffect(() => {\n if (\"to\" in props && props.to !== undefined) {\n console.warn(\n '[kumo] Link: The `to` prop is deprecated. Use `href` instead.\\n\\n' +\n 'If your app uses a client-side router, configure a LinkProvider that\\n' +\n 'maps `href` to your router\\'s navigation prop. See:\\n' +\n 'https://kumo.cfops.it/utilities/link-provider\\n\\n' +\n 'Migration example:\\n' +\n ' Before: <Link to=\"/page\">…</Link>\\n' +\n ' After: <Link href=\"/page\">…</Link>',\n );\n }\n }, []); // eslint-disable-line react-hooks/exhaustive-deps -- one-time warning\n }\n\n const defaultProps: useRender.ElementProps<\"a\"> = {\n className: cn(\n linkVariants({ variant }),\n \"group/link inline-flex items-center gap-[0.1875em]\",\n ),\n };\n\n const element = useRender({\n render: render ?? <LinkComponent />,\n ref,\n props: mergeProps<\"a\">(defaultProps, props, { className }),\n });\n\n return element;\n});\n\nLinkBase.displayName = \"Link\";\n\n// Compound component with ExternalIcon subcomponent\nexport const Link = Object.assign(LinkBase, {\n ExternalIcon,\n});\n"],"names":["ExternalIcon","props","jsxs","jsx","KUMO_LINK_VARIANTS","KUMO_LINK_DEFAULT_VARIANTS","linkVariants","variant","cn","resolveVariant","LinkBase","forwardRef","className","render","ref","LinkComponent","useLinkComponent","useEffect","defaultProps","useRender","mergeProps","Link"],"mappings":";;;;;;;AAoBA,MAAMA,IAAe,CAACC,MACpB,gBAAAC;AAAA,EAAC;AAAA,EAAA;AAAA,IACC,OAAM;AAAA,IACN,QAAO;AAAA,IACP,SAAQ;AAAA,IACR,MAAK;AAAA,IACL,QAAO;AAAA,IACP,eAAc;AAAA,IACd,gBAAe;AAAA,IACf,eAAY;AAAA,IACZ,WAAU;AAAA,IACT,GAAGD;AAAA,IAEJ,UAAA;AAAA,MAAA,gBAAAE,EAAC,QAAA,EAAK,GAAE,kWAAA,CAAkW;AAAA,MAC1W,gBAAAA,EAAC,QAAA,EAAK,GAAE,8BAAA,CAA8B;AAAA,IAAA;AAAA,EAAA;AACxC;AAGFH,EAAa,cAAc;AAGpB,MAAMI,IAAqB;AAAA,EAChC,SAAS;AAAA,IACP,QAAQ;AAAA,MACN;AAAA;AAAA,QAEE;AAAA;AAAA,MACF,aAAa;AAAA,IAAA;AAAA,IAEf,SAAS;AAAA,MACP,SACE;AAAA,MACF,aAAa;AAAA,IAAA;AAAA,IAEf,OAAO;AAAA,MACL;AAAA;AAAA,QAEE;AAAA;AAAA,MACF,aAAa;AAAA,IAAA;AAAA,EACf;AAEJ,GAEaC,IAA6B;AAAA,EACxC,SAAS;AACX;AAeO,SAASC,EAAa;AAAA,EAC3B,SAAAC,IAAUF,EAA2B;AACvC,IAA2B,IAAI;AAC7B,SAAOG,EAAGC,EAAeL,EAAmB,SAASG,GAASF,EAA2B,OAAO,EAAE,OAAO;AAC3G;AAsEA,MAAMK,IAAWC,EAAyC,SACxD,EAAE,WAAAC,GAAW,SAAAL,IAAU,UAAU,QAAAM,GAAQ,GAAGZ,EAAA,GAC5Ca,GACA;AACA,QAAMC,IAAgBC,EAAA;AAEtB,EAAI,QAAQ,IAAI,aAAa,gBAE3BC,EAAU,MAAM;AACd,IAAI,QAAQhB,KAASA,EAAM,OAAO,UAChC,QAAQ;AAAA,MACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA;AAAA,EASN,GAAG,CAAA,CAAE;AAGP,QAAMiB,IAA4C;AAAA,IAChD,WAAWV;AAAA,MACTF,EAAa,EAAE,SAAAC,GAAS;AAAA,MACxB;AAAA,IAAA;AAAA,EACF;AASF,SANgBY,EAAU;AAAA,IACxB,QAAQN,KAAU,gBAAAV,EAACY,GAAA,CAAA,CAAc;AAAA,IACjC,KAAAD;AAAA,IACA,OAAOM,EAAgBF,GAAcjB,GAAO,EAAE,WAAAW,GAAW;AAAA,EAAA,CAC1D;AAGH,CAAC;AAEDF,EAAS,cAAc;AAGhB,MAAMW,IAAO,OAAO,OAAOX,GAAU;AAAA,EAC1C,cAAAV;AACF,CAAC;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link-provider-mn2voeohon7cj9o4.js","sources":["../../src/utils/link-provider.tsx"],"sourcesContent":["import {\n createContext,\n forwardRef,\n type AnchorHTMLAttributes,\n type ForwardRefExoticComponent,\n type ReactNode,\n type RefAttributes,\n useContext,\n} from \"react\";\n\ntype LinkComponentProps = AnchorHTMLAttributes<HTMLAnchorElement> & {\n to?: string;\n};\n\nconst DefaultLinkComponent = forwardRef<HTMLAnchorElement, LinkComponentProps>(\n function DefaultAnchor({ to, href, ...rest }, ref) {\n // Children and other content props are passed via ...rest spread\n // oxlint-disable-next-line anchor-has-content\n return <a ref={ref} href={href ?? to ?? undefined} {...rest} />;\n },\n);\n\ntype ForwardLinkComponent = ForwardRefExoticComponent<\n LinkComponentProps & RefAttributes<HTMLAnchorElement>\n>;\n\nconst LinkComponentContext =\n createContext<ForwardLinkComponent>(DefaultLinkComponent);\n\nexport function useLinkComponent() {\n return useContext(LinkComponentContext);\n}\n\nexport function LinkProvider({\n component,\n children,\n}: {\n component?: ForwardLinkComponent;\n children: ReactNode;\n}) {\n return (\n <LinkComponentContext.Provider value={component ?? DefaultLinkComponent}>\n {children}\n </LinkComponentContext.Provider>\n );\n}\n\nexport type { LinkComponentProps };\n"],"names":["DefaultLinkComponent","forwardRef","to","href","rest","ref","jsx","LinkComponentContext","createContext","useLinkComponent","useContext","LinkProvider","component","children"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"link-provider-mn2voeohon7cj9o4.js","sources":["../../src/utils/link-provider.tsx"],"sourcesContent":["import {\n createContext,\n forwardRef,\n type AnchorHTMLAttributes,\n type ForwardRefExoticComponent,\n type ReactNode,\n type RefAttributes,\n useContext,\n} from \"react\";\n\ntype LinkComponentProps = AnchorHTMLAttributes<HTMLAnchorElement> & {\n /**\n * @deprecated Use `href` instead. The `to` prop is a routing-framework concept\n * (e.g. React Router) that does not belong on a presentational component.\n *\n * If your application uses a client-side router, configure the `LinkProvider`\n * with a wrapper component that maps `href` to your router's navigation prop:\n *\n * ```tsx\n * const AppLink = forwardRef(({ href, ...rest }, ref) => (\n * <ReactRouterLink ref={ref} to={href} {...rest} />\n * ));\n *\n * <LinkProvider component={AppLink}>\n * <App />\n * </LinkProvider>\n * ```\n */\n to?: string;\n};\n\nconst DefaultLinkComponent = forwardRef<HTMLAnchorElement, LinkComponentProps>(\n function DefaultAnchor({ to, href, ...rest }, ref) {\n // Children and other content props are passed via ...rest spread\n // oxlint-disable-next-line anchor-has-content\n return <a ref={ref} href={href ?? to ?? undefined} {...rest} />;\n },\n);\n\ntype ForwardLinkComponent = ForwardRefExoticComponent<\n LinkComponentProps & RefAttributes<HTMLAnchorElement>\n>;\n\nconst LinkComponentContext =\n createContext<ForwardLinkComponent>(DefaultLinkComponent);\n\nexport function useLinkComponent() {\n return useContext(LinkComponentContext);\n}\n\n/**\n * Provides a custom link component for all Kumo Link instances in the tree.\n *\n * Use this to integrate framework-specific routing (React Router, Next.js, etc.)\n * while keeping Kumo's Link component framework-agnostic.\n *\n * Your custom component receives standard anchor props (including `href`) and\n * is responsible for bridging to your router's API:\n *\n * @example React Router integration\n * ```tsx\n * import { Link as ReactRouterLink } from \"react-router-dom\";\n *\n * const AppLink = forwardRef<HTMLAnchorElement, LinkComponentProps>(\n * ({ href, ...rest }, ref) => (\n * <ReactRouterLink ref={ref} to={href ?? \"\"} {...rest} />\n * ),\n * );\n *\n * <LinkProvider component={AppLink}>\n * <App />\n * </LinkProvider>\n * ```\n *\n * @example Next.js integration\n * ```tsx\n * import NextLink from \"next/link\";\n *\n * const AppLink = forwardRef<HTMLAnchorElement, LinkComponentProps>(\n * (props, ref) => <NextLink ref={ref} {...props} />,\n * );\n *\n * <LinkProvider component={AppLink}>\n * <App />\n * </LinkProvider>\n * ```\n */\nexport function LinkProvider({\n component,\n children,\n}: {\n component?: ForwardLinkComponent;\n children: ReactNode;\n}) {\n return (\n <LinkComponentContext.Provider value={component ?? DefaultLinkComponent}>\n {children}\n </LinkComponentContext.Provider>\n );\n}\n\nexport type { LinkComponentProps };\n"],"names":["DefaultLinkComponent","forwardRef","to","href","rest","ref","jsx","LinkComponentContext","createContext","useLinkComponent","useContext","LinkProvider","component","children"],"mappings":";;;AA+BA,MAAMA,IAAuBC;AAAA,EAC3B,SAAuB,EAAE,IAAAC,GAAI,MAAAC,GAAM,GAAGC,EAAA,GAAQC,GAAK;AAGjD,WAAO,gBAAAC,EAAC,OAAE,KAAAD,GAAU,MAAMF,KAAQD,KAAM,QAAY,GAAGE,GAAM;AAAA,EAC/D;AACF,GAMMG,IACJC,EAAoCR,CAAoB;AAEnD,SAASS,IAAmB;AACjC,SAAOC,EAAWH,CAAoB;AACxC;AAuCO,SAASI,EAAa;AAAA,EAC3B,WAAAC;AAAA,EACA,UAAAC;AACF,GAGG;AACD,2BACGN,EAAqB,UAArB,EAA8B,OAAOK,KAAaZ,GAChD,UAAAa,GACH;AAEJ;"}
|