@cloudflare/kumo 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/ai/component-registry.json +220 -30
  3. package/ai/component-registry.md +305 -19
  4. package/dist/.build-complete +1 -1
  5. package/dist/blocks-source/resource-list/resource-list.tsx +1 -1
  6. package/dist/chunks/{autocomplete-cs3fwy6lwzlyirpq.js → autocomplete-48aq0d244bs2e8zv.js} +3 -3
  7. package/dist/chunks/{autocomplete-cs3fwy6lwzlyirpq.js.map → autocomplete-48aq0d244bs2e8zv.js.map} +1 -1
  8. package/dist/chunks/{checkbox-eren6w2csum1xghg.js → checkbox-hvxfvhtx1qjo2mww.js} +2 -2
  9. package/dist/chunks/{checkbox-eren6w2csum1xghg.js.map → checkbox-hvxfvhtx1qjo2mww.js.map} +1 -1
  10. package/dist/chunks/{clipboard-text-f9q753udny1uyxr5.js → clipboard-text-hswydzx3iql369sd.js} +2 -2
  11. package/dist/chunks/{clipboard-text-f9q753udny1uyxr5.js.map → clipboard-text-hswydzx3iql369sd.js.map} +1 -1
  12. package/dist/chunks/{code-cz0w1y5z4h29a9eg.js → code-f9v1ikwhekqw274q.js} +4 -4
  13. package/dist/chunks/{code-cz0w1y5z4h29a9eg.js.map → code-f9v1ikwhekqw274q.js.map} +1 -1
  14. package/dist/chunks/{collapsible-k8urhi16pg90jvxa.js → collapsible-nlp2jvcyuzxmq28o.js} +12 -11
  15. package/dist/chunks/{collapsible-k8urhi16pg90jvxa.js.map → collapsible-nlp2jvcyuzxmq28o.js.map} +1 -1
  16. package/dist/chunks/{combobox-n9qht9h9ag6kh5sn.js → combobox-fq36ye0hstote16x.js} +10 -10
  17. package/dist/chunks/{combobox-n9qht9h9ag6kh5sn.js.map → combobox-fq36ye0hstote16x.js.map} +1 -1
  18. package/dist/chunks/{command-palette-gk9m34ymp2b3hfc5.js → command-palette-md65owxt5hv4rt9r.js} +142 -142
  19. package/dist/chunks/{command-palette-gk9m34ymp2b3hfc5.js.map → command-palette-md65owxt5hv4rt9r.js.map} +1 -1
  20. package/dist/chunks/{date-range-picker-c9wnx9tbwohai7jy.js → date-range-picker-o8uyril1kogvhoei.js} +19 -19
  21. package/dist/chunks/{date-range-picker-c9wnx9tbwohai7jy.js.map → date-range-picker-o8uyril1kogvhoei.js.map} +1 -1
  22. package/dist/chunks/{dialog-94v7wiz7j3in6528.js → dialog-k3f1fbam6nt96k8x.js} +2 -2
  23. package/dist/chunks/{dialog-94v7wiz7j3in6528.js.map → dialog-k3f1fbam6nt96k8x.js.map} +1 -1
  24. package/dist/chunks/{empty-kpymw59thjf2ip8g.js → empty-b82oer7npkhtkx7k.js} +6 -6
  25. package/dist/chunks/{empty-kpymw59thjf2ip8g.js.map → empty-b82oer7npkhtkx7k.js.map} +1 -1
  26. package/dist/chunks/{field-lnj619xpe8zjd26r.js → field-c0wf94plit2gci59.js} +2 -2
  27. package/dist/chunks/{field-lnj619xpe8zjd26r.js.map → field-c0wf94plit2gci59.js.map} +1 -1
  28. package/dist/chunks/{input-area-h8xbqturegdfm1mi.js → input-area-bkyzu6f7gsck479h.js} +3 -3
  29. package/dist/chunks/{input-area-h8xbqturegdfm1mi.js.map → input-area-bkyzu6f7gsck479h.js.map} +1 -1
  30. package/dist/chunks/{input-group-dh4pg8p20rh4mdi0.js → input-group-bidweffa0zyg8gt0.js} +3 -3
  31. package/dist/chunks/{input-group-dh4pg8p20rh4mdi0.js.map → input-group-bidweffa0zyg8gt0.js.map} +1 -1
  32. package/dist/chunks/{input-lpa5fc75tgrraafv.js → input-ncfowphv81yq7fyy.js} +18 -18
  33. package/dist/chunks/input-ncfowphv81yq7fyy.js.map +1 -0
  34. package/dist/chunks/{label-be8m7qzlakzig2sl.js → label-c3h9i3y4wiccelt7.js} +22 -22
  35. package/dist/chunks/{label-be8m7qzlakzig2sl.js.map → label-c3h9i3y4wiccelt7.js.map} +1 -1
  36. package/dist/chunks/{layer-card-hvivdirwwnyq88wa.js → layer-card-ikm31xemd70w3lru.js} +2 -2
  37. package/dist/chunks/{layer-card-hvivdirwwnyq88wa.js.map → layer-card-ikm31xemd70w3lru.js.map} +1 -1
  38. package/dist/chunks/{meter-bqetlujwg8gm2u7m.js → meter-n34a7yb8c3rim26i.js} +2 -2
  39. package/dist/chunks/{meter-bqetlujwg8gm2u7m.js.map → meter-n34a7yb8c3rim26i.js.map} +1 -1
  40. package/dist/chunks/{pagination-ho8zesqfyp6ckmrl.js → pagination-jb3mncivbwsoi1se.js} +40 -40
  41. package/dist/chunks/{pagination-ho8zesqfyp6ckmrl.js.map → pagination-jb3mncivbwsoi1se.js.map} +1 -1
  42. package/dist/chunks/{select-kpfbib9l8xrrmzpz.js → select-g261chvosodu22i8.js} +3 -3
  43. package/dist/chunks/{select-kpfbib9l8xrrmzpz.js.map → select-g261chvosodu22i8.js.map} +1 -1
  44. package/dist/chunks/{sensitive-input-i1upqytzaw2pus8v.js → sensitive-input-cijagk551mesdtk4.js} +3 -3
  45. package/dist/chunks/{sensitive-input-i1upqytzaw2pus8v.js.map → sensitive-input-cijagk551mesdtk4.js.map} +1 -1
  46. package/dist/chunks/{sidebar-kh37grvfxto14ek6.js → sidebar-kb9kykqfgy5yzqwr.js} +4 -4
  47. package/dist/chunks/{sidebar-kh37grvfxto14ek6.js.map → sidebar-kb9kykqfgy5yzqwr.js.map} +1 -1
  48. package/dist/chunks/{surface-o63tktyrifcjejyb.js → surface-k0e8mq1x00b7i8r6.js} +2 -2
  49. package/dist/chunks/{surface-o63tktyrifcjejyb.js.map → surface-k0e8mq1x00b7i8r6.js.map} +1 -1
  50. package/dist/chunks/{switch-lclhiplr9zqf73tj.js → switch-jdfsr3j3oa1qxegw.js} +2 -2
  51. package/dist/chunks/{switch-lclhiplr9zqf73tj.js.map → switch-jdfsr3j3oa1qxegw.js.map} +1 -1
  52. package/dist/chunks/{table-fyy8gl875yyevqs3.js → table-iudje0lva0z68jto.js} +2 -2
  53. package/dist/chunks/{table-fyy8gl875yyevqs3.js.map → table-iudje0lva0z68jto.js.map} +1 -1
  54. package/dist/chunks/{tabs-jywwt8ebjqjkux75.js → tabs-mkhf1uemgr3ij0ps.js} +3 -3
  55. package/dist/chunks/{tabs-jywwt8ebjqjkux75.js.map → tabs-mkhf1uemgr3ij0ps.js.map} +1 -1
  56. package/dist/chunks/toast-h573o0tc7tefivk2.js.map +1 -1
  57. package/dist/code.js +30 -30
  58. package/dist/code.js.map +1 -1
  59. package/dist/components/autocomplete.js +1 -1
  60. package/dist/components/checkbox.js +1 -1
  61. package/dist/components/clipboard-text.js +1 -1
  62. package/dist/components/code.js +1 -1
  63. package/dist/components/collapsible.js +1 -1
  64. package/dist/components/combobox.js +1 -1
  65. package/dist/components/command-palette.js +1 -1
  66. package/dist/components/date-range-picker.js +1 -1
  67. package/dist/components/dialog.js +1 -1
  68. package/dist/components/empty.js +1 -1
  69. package/dist/components/field.js +1 -1
  70. package/dist/components/input-group.js +1 -1
  71. package/dist/components/input.js +3 -3
  72. package/dist/components/label.js +1 -1
  73. package/dist/components/layer-card.js +1 -1
  74. package/dist/components/meter.js +1 -1
  75. package/dist/components/pagination.js +1 -1
  76. package/dist/components/select.js +1 -1
  77. package/dist/components/sensitive-input.js +1 -1
  78. package/dist/components/sidebar.js +1 -1
  79. package/dist/components/surface.js +1 -1
  80. package/dist/components/switch.js +1 -1
  81. package/dist/components/table.js +1 -1
  82. package/dist/components/tabs.js +1 -1
  83. package/dist/index.js +27 -27
  84. package/dist/scripts/theme-generator/config.js +11 -4
  85. package/dist/scripts/theme-generator/config.js.map +1 -1
  86. package/dist/src/components/code/code.d.ts +2 -2
  87. package/dist/src/components/collapsible/collapsible.d.ts +1 -1
  88. package/dist/src/components/collapsible/collapsible.d.ts.map +1 -1
  89. package/dist/src/components/toast/toast.d.ts +1 -1
  90. package/dist/src/components/toast/toast.d.ts.map +1 -1
  91. package/dist/styles/kumo-standalone.css +1 -1
  92. package/dist/styles/theme-kumo.css +8 -8
  93. package/package.json +1 -1
  94. package/scripts/component-registry/index.test.ts +42 -0
  95. package/scripts/component-registry/index.ts +18 -4
  96. package/scripts/component-registry/metadata.ts +222 -2
  97. package/scripts/theme-generator/config.ts +9 -9
  98. package/dist/chunks/input-lpa5fc75tgrraafv.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudflare/kumo",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Kumo - Cloudflare's component library for building modern web applications",
@@ -943,3 +943,45 @@ interface GroupProps extends BaseProps {
943
943
  expect(props).toEqual({});
944
944
  });
945
945
  });
946
+
947
+ describe("SUB_COMPONENT_OVERRIDES", () => {
948
+ it("declares a Tooltip.Provider entry that passes through to TooltipBase.Provider", async () => {
949
+ const { SUB_COMPONENT_OVERRIDES, PASSTHROUGH_COMPONENT_DOCS } =
950
+ await import("./metadata.js");
951
+
952
+ expect(SUB_COMPONENT_OVERRIDES.Tooltip).toBeDefined();
953
+ const tooltipOverrides = SUB_COMPONENT_OVERRIDES.Tooltip;
954
+ expect(tooltipOverrides).toHaveLength(1);
955
+
956
+ const provider = tooltipOverrides[0];
957
+ expect(provider.name).toBe("Provider");
958
+ expect(provider.valueName).toBe("TooltipProvider");
959
+ expect(provider.isPassThrough).toBe(true);
960
+ expect(provider.baseComponent).toBe("TooltipBase.Provider");
961
+ expect(provider.propsType).toBeNull();
962
+
963
+ // The baseComponent must resolve to a documented passthrough entry so the
964
+ // merge + lookup path in index.ts produces real docs, not an empty stub.
965
+ expect(
966
+ PASSTHROUGH_COMPONENT_DOCS[provider.baseComponent as string],
967
+ ).toBeDefined();
968
+ });
969
+
970
+ it("entries have the same shape as detectSubComponents() results", async () => {
971
+ const { SUB_COMPONENT_OVERRIDES } = await import("./metadata.js");
972
+
973
+ for (const overrides of Object.values(SUB_COMPONENT_OVERRIDES)) {
974
+ for (const entry of overrides) {
975
+ // Required fields of SubComponentConfig.
976
+ expect(typeof entry.name).toBe("string");
977
+ expect(typeof entry.valueName).toBe("string");
978
+ expect(typeof entry.description).toBe("string");
979
+ expect(typeof entry.isPassThrough).toBe("boolean");
980
+ // propsType may be a string or null.
981
+ expect(
982
+ entry.propsType === null || typeof entry.propsType === "string",
983
+ ).toBe(true);
984
+ }
985
+ }
986
+ });
987
+ });
@@ -44,6 +44,7 @@ import {
44
44
  createCacheEntry,
45
45
  } from "./cache.js";
46
46
  import {
47
+ toPascalCase,
47
48
  toScreamingSnakeCase,
48
49
  extractSemanticColors,
49
50
  extractBlockDependencies,
@@ -62,6 +63,7 @@ import {
62
63
  ADDITIONAL_COMPONENT_PROPS,
63
64
  PROP_TYPE_OVERRIDES,
64
65
  COMPONENT_STYLING_METADATA,
66
+ SUB_COMPONENT_OVERRIDES,
65
67
  } from "./metadata.js";
66
68
 
67
69
  // External imports - demo examples from kumo-docs-astro
@@ -585,11 +587,16 @@ async function processComponent(
585
587
  const colors = extractSemanticColors(sourcePath);
586
588
 
587
589
  // Determine examples
590
+ // Demo metadata keys are derived from file names (e.g. DropdownDemo.tsx → "Dropdown")
591
+ // which may differ from the component's export name (e.g. "DropdownMenu").
592
+ // Try the component name first, then fall back to the PascalCase directory name.
588
593
  let examples: readonly string[];
589
594
  if (config.examples !== undefined) {
590
595
  examples = config.examples;
591
596
  } else {
592
- const extracted = input.storyExamples.get(config.name);
597
+ const extracted =
598
+ input.storyExamples.get(config.name) ??
599
+ input.storyExamples.get(toPascalCase(config.dirName));
593
600
  examples = extracted?.aiExamples ?? [];
594
601
  if (examples.length > 0 && CLI_FLAGS.verbose) {
595
602
  console.log(
@@ -598,14 +605,21 @@ async function processComponent(
598
605
  }
599
606
  }
600
607
 
601
- // Detect and process sub-components
608
+ // Merge SUB_COMPONENT_OVERRIDES after source detection.
609
+ // Detected entries win on name conflict so source-level patterns aren't masked.
602
610
  const detectedSubComponents = detectSubComponents(sourcePath);
611
+ const subComponentOverrides = SUB_COMPONENT_OVERRIDES[config.name] ?? [];
612
+ const detectedNames = new Set(detectedSubComponents.map((sc) => sc.name));
613
+ const mergedSubComponents = [
614
+ ...detectedSubComponents,
615
+ ...subComponentOverrides.filter((o) => !detectedNames.has(o.name)),
616
+ ];
603
617
  let subComponentSchemas: Record<string, SubComponentSchema> | undefined;
604
618
 
605
- if (detectedSubComponents.length > 0) {
619
+ if (mergedSubComponents.length > 0) {
606
620
  subComponentSchemas = {};
607
621
 
608
- for (const subComp of detectedSubComponents) {
622
+ for (const subComp of mergedSubComponents) {
609
623
  let subProps = extractSubComponentProps(sourcePath, subComp, CLI_FLAGS);
610
624
  let description = subComp.description;
611
625
  let usageExamples: string[] | undefined;
@@ -8,7 +8,12 @@
8
8
  * - Styling metadata for Figma plugin
9
9
  */
10
10
 
11
- import type { PropSchema, PassthroughDoc, ComponentStyling } from "./types.js";
11
+ import type {
12
+ PropSchema,
13
+ PassthroughDoc,
14
+ ComponentStyling,
15
+ SubComponentConfig,
16
+ } from "./types.js";
12
17
 
13
18
  // =============================================================================
14
19
  // Pass-through Component Documentation
@@ -158,6 +163,66 @@ export const PASSTHROUGH_COMPONENT_DOCS: Record<string, PassthroughDoc> = {
158
163
  </Combobox.Collection>`,
159
164
  ],
160
165
  },
166
+
167
+ // Tooltip sub-components
168
+ "TooltipBase.Provider": {
169
+ description:
170
+ "Groups multiple tooltips so that after the first tooltip is shown, switching to another skips the open delay. Place once at your app root or layout.",
171
+ props: {
172
+ delay: {
173
+ type: "number",
174
+ description:
175
+ "How long to wait (ms) before opening a tooltip once the pointer enters the trigger.",
176
+ default: "600",
177
+ },
178
+ closeDelay: {
179
+ type: "number",
180
+ description: "How long to wait (ms) before closing a tooltip.",
181
+ default: "0",
182
+ },
183
+ timeout: {
184
+ type: "number",
185
+ description:
186
+ "Grace period (ms) during which a just-closed tooltip's delay is skipped when another tooltip opens.",
187
+ default: "400",
188
+ },
189
+ },
190
+ usageExamples: ["<TooltipProvider>\n <App />\n</TooltipProvider>"],
191
+ },
192
+ };
193
+
194
+ // =============================================================================
195
+ // Sub-Component Overrides
196
+ // =============================================================================
197
+
198
+ /**
199
+ * Manual sub-component entries that are merged into the registry alongside
200
+ * entries detected by `detectSubComponents()` in `sub-components.ts`.
201
+ *
202
+ * Use this when a component exposes a related API (e.g., a sibling named
203
+ * export like `TooltipProvider`) that we want documented as a sub-component
204
+ * (e.g., `Tooltip.Provider`) for the registry / docs, *without* changing the
205
+ * component's runtime shape (no `Object.assign`, no attached property).
206
+ *
207
+ * Detected sub-components take precedence over overrides with the same
208
+ * `name`, so a real source-level compound pattern will always win and
209
+ * prevent silent masking of detector regressions.
210
+ *
211
+ * Keyed by the parent component name (e.g., "Tooltip"). Values have the same
212
+ * shape as `detectSubComponents()` entries so they feed directly into the
213
+ * existing processing loop in `index.ts`.
214
+ */
215
+ export const SUB_COMPONENT_OVERRIDES: Record<string, SubComponentConfig[]> = {
216
+ Tooltip: [
217
+ {
218
+ name: "Provider",
219
+ valueName: "TooltipProvider",
220
+ propsType: null,
221
+ description: "Provider sub-component (wraps TooltipBase)",
222
+ isPassThrough: true,
223
+ baseComponent: "TooltipBase.Provider",
224
+ },
225
+ ],
161
226
  };
162
227
 
163
228
  // =============================================================================
@@ -254,6 +319,161 @@ export const ADDITIONAL_COMPONENT_PROPS: Record<
254
319
  description: "Callback when collapsed state changes",
255
320
  },
256
321
  },
322
+ "DropdownMenu.Item": {
323
+ icon: {
324
+ type: "Icon | ReactNode",
325
+ description: "Icon displayed before the label.",
326
+ },
327
+ variant: {
328
+ type: '"default" | "danger"',
329
+ description: "Visual style of the item.",
330
+ default: '"default"',
331
+ },
332
+ selected: {
333
+ type: "boolean",
334
+ description: "Shows a check mark indicator when true.",
335
+ },
336
+ inset: {
337
+ type: "boolean",
338
+ description: "Adds left padding to align with items that have icons.",
339
+ },
340
+ onClick: {
341
+ type: "(event: React.MouseEvent) => void",
342
+ description: "Callback when the item is clicked.",
343
+ },
344
+ closeOnClick: {
345
+ type: "boolean",
346
+ description: "Whether the menu closes after clicking this item.",
347
+ default: "true",
348
+ },
349
+ disabled: {
350
+ type: "boolean",
351
+ description: "When true, the item cannot be interacted with.",
352
+ },
353
+ },
354
+ "DropdownMenu.LinkItem": {
355
+ href: {
356
+ type: "string",
357
+ description: "URL to navigate to when clicked.",
358
+ },
359
+ icon: {
360
+ type: "Icon | ReactNode",
361
+ description: "Icon displayed before the label.",
362
+ },
363
+ variant: {
364
+ type: '"default" | "danger"',
365
+ description: "Visual style of the item.",
366
+ default: '"default"',
367
+ },
368
+ inset: {
369
+ type: "boolean",
370
+ description: "Adds left padding to align with items that have icons.",
371
+ },
372
+ target: {
373
+ type: "string",
374
+ description: 'Link target attribute (e.g. "_blank" for new tab).',
375
+ },
376
+ render: {
377
+ type: "ReactElement | ((props, state) => ReactElement)",
378
+ description:
379
+ "Custom element to render as the link. Use to integrate with framework routers (e.g. Next.js Link).",
380
+ },
381
+ },
382
+ "DropdownMenu.Content": {
383
+ sideOffset: {
384
+ type: "number",
385
+ description: "Distance in pixels from the trigger.",
386
+ default: "8",
387
+ },
388
+ container: {
389
+ type: "PortalContainer",
390
+ description:
391
+ "Container element for the portal. Use this to render inside a Shadow DOM or custom container.",
392
+ },
393
+ },
394
+ "DropdownMenu.SubTrigger": {
395
+ icon: {
396
+ type: "Icon",
397
+ description: "Icon displayed before the label.",
398
+ },
399
+ inset: {
400
+ type: "boolean",
401
+ description: "Adds left padding to align with items that have icons.",
402
+ },
403
+ },
404
+ "DropdownMenu.CheckboxItem": {
405
+ checked: {
406
+ type: "boolean",
407
+ description: "Whether the item is checked.",
408
+ },
409
+ defaultChecked: {
410
+ type: "boolean",
411
+ description: "Whether the item is initially checked (uncontrolled).",
412
+ default: "false",
413
+ },
414
+ onCheckedChange: {
415
+ type: "(checked: boolean, event: ChangeEventDetails) => void",
416
+ description: "Callback when the checked state changes.",
417
+ },
418
+ closeOnClick: {
419
+ type: "boolean",
420
+ description: "Whether the menu closes after clicking this item.",
421
+ default: "false",
422
+ },
423
+ disabled: {
424
+ type: "boolean",
425
+ description: "When true, the item cannot be interacted with.",
426
+ },
427
+ },
428
+ "DropdownMenu.RadioGroup": {
429
+ value: {
430
+ type: "any",
431
+ description:
432
+ "The controlled value of the currently selected radio item.",
433
+ },
434
+ defaultValue: {
435
+ type: "any",
436
+ description: "The initially selected value (uncontrolled).",
437
+ },
438
+ onValueChange: {
439
+ type: "(value: any, event: ChangeEventDetails) => void",
440
+ description: "Callback when the selected value changes.",
441
+ },
442
+ disabled: {
443
+ type: "boolean",
444
+ description: "When true, all radio items in the group are disabled.",
445
+ },
446
+ },
447
+ "DropdownMenu.RadioItem": {
448
+ value: {
449
+ type: "any",
450
+ required: true,
451
+ description: "The value of this radio item.",
452
+ },
453
+ icon: {
454
+ type: "Icon | ReactNode",
455
+ description: "Icon displayed before the label.",
456
+ },
457
+ inset: {
458
+ type: "boolean",
459
+ description: "Adds left padding to align with items that have icons.",
460
+ },
461
+ closeOnClick: {
462
+ type: "boolean",
463
+ description: "Whether the menu closes after clicking this item.",
464
+ default: "false",
465
+ },
466
+ disabled: {
467
+ type: "boolean",
468
+ description: "When true, the item cannot be interacted with.",
469
+ },
470
+ },
471
+ "DropdownMenu.Label": {
472
+ inset: {
473
+ type: "boolean",
474
+ description: "Adds left padding to align with items that have icons.",
475
+ },
476
+ },
257
477
  "InputGroup.Addon": {
258
478
  align: {
259
479
  type: '"start" | "end"',
@@ -420,7 +640,7 @@ export const COMPONENT_STYLING_METADATA: Record<string, ComponentStyling> = {
420
640
  ],
421
641
  },
422
642
  Code: {
423
- baseTokens: ["text-kumo-strong"],
643
+ baseTokens: ["text-kumo-subtle"],
424
644
  dimensions: "m-0 w-auto p-0",
425
645
  borderRadius: "rounded-none",
426
646
  states: {
@@ -43,8 +43,8 @@ export const THEME_CONFIG: ThemeConfig = {
43
43
  newName: "",
44
44
  theme: {
45
45
  kumo: {
46
- light: "var(--color-neutral-600, oklch(43.9% 0 0))",
47
- dark: "var(--color-neutral-400, oklch(70.8% 0 0))",
46
+ light: "var(--color-neutral-950, oklch(14.5% 0 0))", // darker than default
47
+ dark: "var(--color-neutral-50, oklch(98.5% 0 0))", // lighter than default
48
48
  },
49
49
  },
50
50
  },
@@ -52,8 +52,8 @@ export const THEME_CONFIG: ThemeConfig = {
52
52
  newName: "",
53
53
  theme: {
54
54
  kumo: {
55
- light: "var(--color-neutral-500, oklch(55.6% 0 0))",
56
- dark: "var(--color-neutral-400, oklch(70.8% 0 0))",
55
+ light: "var(--color-neutral-500, oklch(55.6% 0 0))", // lighter than default
56
+ dark: "var(--color-neutral-400, oklch(70.8% 0 0))", // darker than default
57
57
  },
58
58
  },
59
59
  },
@@ -61,17 +61,17 @@ export const THEME_CONFIG: ThemeConfig = {
61
61
  newName: "",
62
62
  theme: {
63
63
  kumo: {
64
- light: "var(--color-neutral-400, oklch(70.8% 0 0))",
65
- dark: "var(--color-neutral-600, oklch(70.8% 0 0))",
64
+ light: "var(--color-neutral-300, oklch(87% 0 0))", // lighter than subtle
65
+ dark: "var(--color-neutral-600, oklch(43.9% 0 0))", // darker than subtle
66
66
  },
67
67
  },
68
68
  },
69
- "kumo-placeholder": {
69
+ "kumo-placeholder": { // in between subtle and inactive
70
70
  newName: "",
71
71
  theme: {
72
72
  kumo: {
73
73
  light: "var(--color-neutral-400, oklch(70.8% 0 0))",
74
- dark: "var(--color-neutral-500, oklch(55.6% 0 0))",
74
+ dark: "var(--color-neutral-500, oklch(55.6% 0 0))",
75
75
  },
76
76
  },
77
77
  },
@@ -323,7 +323,7 @@ export const THEME_CONFIG: ThemeConfig = {
323
323
  kumo: {
324
324
  light: "var(--color-kumo-neutral-150, oklch(93.5% 0 0))",
325
325
  dark: "var(--color-neutral-800, oklch(26.9% 0 0))",
326
- },
326
+ },
327
327
  fedramp: {
328
328
  light: "#c8d4e5",
329
329
  dark: "#c8d4e5",
@@ -1 +0,0 @@
1
- {"version":3,"file":"input-lpa5fc75tgrraafv.js","sources":["../../src/components/input/input.tsx"],"sourcesContent":["import { cn } from \"../../utils/cn\";\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-subtle\",\n // Apply size styles from KUMO_INPUT_VARIANTS\n KUMO_INPUT_VARIANTS.size[size].classes,\n // Apply variant styles from KUMO_INPUT_VARIANTS\n KUMO_INPUT_VARIANTS.variant[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","Input","forwardRef","props","ref","className","variantProp","label","labelTooltip","description","error","inputProps","required","hasLabel","hasAriaLabel","hasAriaLabelledBy","input","jsx","BaseInput","Field"],"mappings":";;;;;;AAUO,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,IAEAP,EAAoB,KAAKI,CAAI,EAAE;AAAA;AAAA,IAE/BJ,EAAoB,QAAQG,CAAO,EAAE;AAAA;AAAA,IAErCE,MACGF,MAAY,UACT,+DACA;AAAA,IACNG,MACGH,MAAY,UACT,iDACA;AAAA,EAAA;AAEV;AAEO,MAAMK,IAAQC,EAAyC,CAACC,GAAOC,MAAQ;AAC5E,QAAM;AAAA,IACJ,WAAAC;AAAA,IACA,MAAAR,IAAO;AAAA,IACP,SAASS;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,QAAMV,IAAUU,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,WAAWJ;AAAA,QACTL,EAAc,EAAE,MAAAE,GAAM,SAAAD,GAAS,gBAAgB,IAAM;AAAA,QACrDS;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;"}