@cloudflare/kumo 1.4.1 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +15 -7
  3. package/ai/component-registry.json +55 -131
  4. package/ai/component-registry.md +182 -135
  5. package/ai/schemas.ts +6 -4
  6. package/bin/kumo.js +23 -19
  7. package/dist/.build-complete +1 -1
  8. package/dist/ai/schemas.d.ts +2147 -0
  9. package/dist/ai/schemas.d.ts.map +1 -0
  10. package/dist/button-Bh96oxRL.js.map +1 -1
  11. package/dist/catalog.js +1 -1
  12. package/dist/{checkbox-C1LPq8eL.js → checkbox-CWANiedi.js} +3 -3
  13. package/dist/{checkbox-C1LPq8eL.js.map → checkbox-CWANiedi.js.map} +1 -1
  14. package/dist/{clipboard-text-CJSI9X2m.js → clipboard-text-B32_yb2r.js} +10 -10
  15. package/dist/clipboard-text-B32_yb2r.js.map +1 -0
  16. package/dist/{combobox-CWxn5aHA.js → combobox-C9koouxM.js} +4 -4
  17. package/dist/{combobox-CWxn5aHA.js.map → combobox-C9koouxM.js.map} +1 -1
  18. package/dist/command-line/cli.js +16 -17
  19. package/dist/command-line/commands/ai.js +2 -3
  20. package/dist/{command-palette-J50WKjS7.js → command-palette-TGXgr6Vq.js} +2 -2
  21. package/dist/{command-palette-J50WKjS7.js.map → command-palette-TGXgr6Vq.js.map} +1 -1
  22. package/dist/components/checkbox.js +1 -1
  23. package/dist/components/clipboard-text.js +1 -1
  24. package/dist/components/combobox.js +1 -1
  25. package/dist/components/command-palette.js +1 -1
  26. package/dist/components/dialog.js +1 -1
  27. package/dist/components/dropdown.js +1 -1
  28. package/dist/components/field.js +1 -1
  29. package/dist/components/input.js +8 -7
  30. package/dist/components/label.js +1 -1
  31. package/dist/components/link.js +1 -1
  32. package/dist/components/menubar.js +1 -1
  33. package/dist/components/meter.js +1 -1
  34. package/dist/components/pagination.js +1 -1
  35. package/dist/components/popover.js +1 -1
  36. package/dist/components/radio.js +1 -1
  37. package/dist/components/select.js +1 -1
  38. package/dist/components/sensitive-input.js +1 -1
  39. package/dist/components/switch.js +1 -1
  40. package/dist/components/table.js +1 -1
  41. package/dist/components/tabs.js +1 -1
  42. package/dist/components/toast.js +5 -4
  43. package/dist/components/tooltip.js +1 -1
  44. package/dist/dialog-CpCeOqSZ.js +97 -0
  45. package/dist/dialog-CpCeOqSZ.js.map +1 -0
  46. package/dist/{dropdown-BAyk1knz.js → dropdown-DFeFcKfn.js} +3 -3
  47. package/dist/{dropdown-BAyk1knz.js.map → dropdown-DFeFcKfn.js.map} +1 -1
  48. package/dist/{field-B7ORz5ej.js → field-Dt-XuSaQ.js} +3 -3
  49. package/dist/{field-B7ORz5ej.js.map → field-Dt-XuSaQ.js.map} +1 -1
  50. package/dist/index.js +137 -124
  51. package/dist/index.js.map +1 -1
  52. package/dist/{input-D6YgDfDG.js → input-GZAWBXYX.js} +3 -3
  53. package/dist/{input-D6YgDfDG.js.map → input-GZAWBXYX.js.map} +1 -1
  54. package/dist/{input-area-DN_Ncliw.js → input-area-CS1-ceY4.js} +21 -19
  55. package/dist/input-area-CS1-ceY4.js.map +1 -0
  56. package/dist/{input-group-BXzBwH4p.js → input-group-COo-wz5O.js} +2 -2
  57. package/dist/{input-group-BXzBwH4p.js.map → input-group-COo-wz5O.js.map} +1 -1
  58. package/dist/label-ChZ2Pp5p.js +58 -0
  59. package/dist/label-ChZ2Pp5p.js.map +1 -0
  60. package/dist/{link-CcuZKqob.js → link-Mj2WM1AS.js} +2 -2
  61. package/dist/{link-CcuZKqob.js.map → link-Mj2WM1AS.js.map} +1 -1
  62. package/dist/{menubar-CzimiryS.js → menubar-CbXWXQYR.js} +2 -2
  63. package/dist/{menubar-CzimiryS.js.map → menubar-CbXWXQYR.js.map} +1 -1
  64. package/dist/{meter-BrJnHJ3Q.js → meter-Bu5f3mAc.js} +2 -2
  65. package/dist/{meter-BrJnHJ3Q.js.map → meter-Bu5f3mAc.js.map} +1 -1
  66. package/dist/{pagination-D0x9KQSk.js → pagination-Cf-yRO-n.js} +21 -20
  67. package/dist/pagination-Cf-yRO-n.js.map +1 -0
  68. package/dist/{popover-CtKDH8Yc.js → popover-D7yeRosi.js} +2 -2
  69. package/dist/{popover-CtKDH8Yc.js.map → popover-D7yeRosi.js.map} +1 -1
  70. package/dist/primitives/accordion.js +1 -1
  71. package/dist/primitives/alert-dialog.js +1 -1
  72. package/dist/primitives/autocomplete.js +1 -1
  73. package/dist/primitives/avatar.js +1 -1
  74. package/dist/primitives/button.js +1 -1
  75. package/dist/primitives/checkbox-group.js +1 -1
  76. package/dist/primitives/checkbox.js +1 -1
  77. package/dist/primitives/collapsible.js +1 -1
  78. package/dist/primitives/combobox.js +1 -1
  79. package/dist/primitives/context-menu.js +1 -1
  80. package/dist/primitives/dialog.js +1 -1
  81. package/dist/primitives/direction-provider.js +1 -1
  82. package/dist/primitives/field.js +1 -1
  83. package/dist/primitives/fieldset.js +1 -1
  84. package/dist/primitives/form.js +1 -1
  85. package/dist/primitives/input.js +1 -1
  86. package/dist/primitives/menu.js +1 -1
  87. package/dist/primitives/menubar.js +1 -1
  88. package/dist/primitives/meter.js +1 -1
  89. package/dist/primitives/navigation-menu.js +1 -1
  90. package/dist/primitives/number-field.js +1 -1
  91. package/dist/primitives/popover.js +1 -1
  92. package/dist/primitives/preview-card.js +1 -1
  93. package/dist/primitives/progress.js +1 -1
  94. package/dist/primitives/radio-group.js +1 -1
  95. package/dist/primitives/radio.js +1 -1
  96. package/dist/primitives/scroll-area.js +1 -1
  97. package/dist/primitives/select.js +1 -1
  98. package/dist/primitives/separator.js +1 -1
  99. package/dist/primitives/slider.js +1 -1
  100. package/dist/primitives/switch.js +1 -1
  101. package/dist/primitives/tabs.js +1 -1
  102. package/dist/primitives/toast.js +1 -1
  103. package/dist/primitives/toggle-group.js +1 -1
  104. package/dist/primitives/toggle.js +1 -1
  105. package/dist/primitives/toolbar.js +1 -1
  106. package/dist/primitives/tooltip.js +1 -1
  107. package/dist/primitives.js +1 -1
  108. package/dist/{radio-CYejLANA.js → radio-CKn09bGo.js} +2 -2
  109. package/dist/{radio-CYejLANA.js.map → radio-CKn09bGo.js.map} +1 -1
  110. package/dist/{schemas-DCw6TIy0.js → schemas-H10xB2M_.js} +10 -9
  111. package/dist/{schemas-DCw6TIy0.js.map → schemas-H10xB2M_.js.map} +1 -1
  112. package/dist/{select-D4rKQAax.js → select-DvpgiOau.js} +3 -3
  113. package/dist/{select-D4rKQAax.js.map → select-DvpgiOau.js.map} +1 -1
  114. package/dist/{sensitive-input-DYvAmxkN.js → sensitive-input-BuYT6U6C.js} +4 -4
  115. package/dist/{sensitive-input-DYvAmxkN.js.map → sensitive-input-BuYT6U6C.js.map} +1 -1
  116. package/dist/src/blocks/delete-resource/delete-resource.d.ts.map +1 -1
  117. package/dist/src/blocks/delete-resource/delete-resource.tsx +213 -0
  118. package/dist/src/blocks/page-header/page-header.tsx +99 -0
  119. package/dist/src/blocks/resource-list/resource-list.test.tsx +28 -0
  120. package/dist/src/blocks/resource-list/resource-list.tsx +69 -0
  121. package/dist/src/command-line/commands/ai.d.ts.map +1 -1
  122. package/dist/src/components/button/button.d.ts +20 -12
  123. package/dist/src/components/button/button.d.ts.map +1 -1
  124. package/dist/src/components/dialog/dialog.d.ts +54 -13
  125. package/dist/src/components/dialog/dialog.d.ts.map +1 -1
  126. package/dist/src/components/dialog/index.d.ts +1 -1
  127. package/dist/src/components/dialog/index.d.ts.map +1 -1
  128. package/dist/src/components/input/index.d.ts +1 -1
  129. package/dist/src/components/input/index.d.ts.map +1 -1
  130. package/dist/src/components/input/input-area.d.ts +19 -0
  131. package/dist/src/components/input/input-area.d.ts.map +1 -1
  132. package/dist/src/components/label/label.d.ts +5 -3
  133. package/dist/src/components/label/label.d.ts.map +1 -1
  134. package/dist/src/components/pagination/pagination.d.ts +8 -1
  135. package/dist/src/components/pagination/pagination.d.ts.map +1 -1
  136. package/dist/src/components/table/table.d.ts +2 -0
  137. package/dist/src/components/table/table.d.ts.map +1 -1
  138. package/dist/src/components/toast/index.d.ts +1 -1
  139. package/dist/src/components/toast/index.d.ts.map +1 -1
  140. package/dist/src/components/toast/toast.d.ts +2 -0
  141. package/dist/src/components/toast/toast.d.ts.map +1 -1
  142. package/dist/src/index.d.ts +3 -3
  143. package/dist/src/index.d.ts.map +1 -1
  144. package/dist/styles/kumo-standalone.css +1 -1
  145. package/dist/{switch-z7FE1nQE.js → switch-Tu34uFoa.js} +3 -3
  146. package/dist/{switch-z7FE1nQE.js.map → switch-Tu34uFoa.js.map} +1 -1
  147. package/dist/table-DtUrZ2Rj.js +149 -0
  148. package/dist/table-DtUrZ2Rj.js.map +1 -0
  149. package/dist/{tabs-DAEeuQLd.js → tabs-B7THfqHW.js} +2 -2
  150. package/dist/{tabs-DAEeuQLd.js.map → tabs-B7THfqHW.js.map} +1 -1
  151. package/dist/{toast-B8ebpHaU.js → toast-Du4y8qng.js} +16 -14
  152. package/dist/{toast-B8ebpHaU.js.map → toast-Du4y8qng.js.map} +1 -1
  153. package/dist/{tooltip-C4DRhJi1.js → tooltip-BxV1H6AV.js} +2 -2
  154. package/dist/{tooltip-C4DRhJi1.js.map → tooltip-BxV1H6AV.js.map} +1 -1
  155. package/dist/{vendor-base-ui-kX0wjdav.js → vendor-base-ui-CQ6wEonS.js} +5 -5
  156. package/dist/{vendor-base-ui-kX0wjdav.js.map → vendor-base-ui-CQ6wEonS.js.map} +1 -1
  157. package/package.json +1 -1
  158. package/scripts/component-registry/index.ts +68 -12
  159. package/scripts/css-build.ts +47 -1
  160. package/dist/clipboard-text-CJSI9X2m.js.map +0 -1
  161. package/dist/dialog-x9n9wI13.js +0 -77
  162. package/dist/dialog-x9n9wI13.js.map +0 -1
  163. package/dist/input-area-DN_Ncliw.js.map +0 -1
  164. package/dist/label-B4FY8MX_.js +0 -50
  165. package/dist/label-B4FY8MX_.js.map +0 -1
  166. package/dist/pagination-D0x9KQSk.js.map +0 -1
  167. package/dist/table-Sd2Etb1N.js +0 -153
  168. package/dist/table-Sd2Etb1N.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @cloudflare/kumo
2
2
 
3
+ ## 1.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 2c8a5ad: Changed ClipboardIcon to CopyIcon in ClipboardText component
8
+ - 31cc2e1: Fix AI command USAGE.md path resolution to work correctly from bundled dist output
9
+ - 1ae7dfd: fix(cli): include block source files in build for `kumo add` command
10
+
11
+ The `kumo add` command was failing because block source files (`.tsx`) were not being copied to `dist/` during the build process. This adds copying of block source files from `src/blocks/` to `dist/src/blocks/` so the CLI can install them into user projects.
12
+
13
+ - fa3eba3: fix(Table): Add indeterminate prop and fix checkbox click handling
14
+ - Added `indeterminate` prop to `Table.CheckHead` and `Table.CheckCell` components to support indeterminate checkbox state (shows minus icon when some but not all rows are selected)
15
+ - Fixed checkbox click handling - clicking directly on the checkbox now works correctly (previously only clicking the cell area next to the checkbox worked)
16
+ - Updated Table demos (`TableSelectedRowDemo` and `TableFullDemo`) with proper React state management for interactive row selection
17
+
18
+ - 3bc976e: fix: delete-resource shouldn't nest buttons within each other
19
+ - 752fdf1: support overwriting text in pagination component
20
+
21
+ ## 1.5.0
22
+
23
+ ### Minor Changes
24
+
25
+ - d7a6da3: fix(cli): resolve broken doc/docs/ls commands by fixing registry path from catalog/ to ai/
26
+ fix(dialog): wrap sub-components to isolate @base-ui/react type references from downstream consumers
27
+ fix(label): render as `<label>` element with htmlFor support instead of `<span>`
28
+ feat(input): add Textarea alias for InputArea
29
+ feat(toast): add ToastProvider alias for Toasty
30
+ feat(button): require aria-label on icon-only buttons (shape="square" | "circle") via discriminated union
31
+ fix(docs): add Tailwind 4 @source directive to usage example, add confirmation dialog recipe, update Select basic example, document icon-only button aria-label pattern
32
+
3
33
  ## 1.4.1
4
34
 
5
35
  ### Patch Changes
package/README.md CHANGED
@@ -26,7 +26,7 @@ npx @cloudflare/kumo doc Button # Get component documentation
26
26
  npx @cloudflare/kumo docs # Get all component docs
27
27
  ```
28
28
 
29
- The CLI reads from `catalog/component-registry.json` (generated from TypeScript types + Storybook examples).
29
+ The CLI reads from `ai/component-registry.json` (generated from TypeScript types + demo examples).
30
30
 
31
31
  ## Usage
32
32
 
@@ -44,15 +44,23 @@ import { Button } from "@cloudflare/kumo/components/button";
44
44
 
45
45
  #### For Tailwind CSS Users
46
46
 
47
- ```js
48
- // Explicit import (recommended)
49
- import "@cloudflare/kumo/styles/tailwind";
47
+ **Important:** Tailwind CSS v4 does not scan `node_modules/` by default. You must add a `@source` directive so Tailwind can discover the utility classes used by Kumo components. Without this, components may render with missing styles (e.g. Dialogs not centered).
48
+
49
+ In your main CSS file (e.g. `app.css`):
50
50
 
51
- // Or use the default export (same as above)
52
- import "@cloudflare/kumo/styles";
51
+ ```css
52
+ @source "../node_modules/@cloudflare/kumo/dist/**/*.{js,jsx,ts,tsx}";
53
+ @import "@cloudflare/kumo/styles/tailwind";
54
+ @import "tailwindcss";
53
55
  ```
54
56
 
55
- This imports the raw CSS with Tailwind directives (`@theme`, `@layer`, etc.) that your Tailwind setup will process.
57
+ > **Import order matters** `@cloudflare/kumo/styles` must come **before** `@import "tailwindcss"` so Kumo's `@theme` tokens are registered first.
58
+
59
+ > **Note:** The `@source` path is relative to your CSS file. Adjust it based on your project structure — e.g. if your CSS is in `src/styles/`, you may need `../../node_modules/@cloudflare/kumo/dist/**/*.{js,jsx,ts,tsx}`.
60
+
61
+ Alternatively, you can use the default style export (`@cloudflare/kumo/styles`) which is equivalent to `styles/tailwind`.
62
+
63
+ If you are **not** using Tailwind CSS, use the standalone build instead (see below) — no `@source` directive is needed.
56
64
 
57
65
  #### For Non-Tailwind Users (Standalone)
58
66
 
@@ -239,28 +239,9 @@
239
239
  "importPath": "@cloudflare/kumo",
240
240
  "category": "Action",
241
241
  "props": {
242
- "children": {
243
- "type": "ReactNode",
244
- "optional": true
245
- },
246
- "className": {
247
- "type": "string",
248
- "optional": true
249
- },
250
- "icon": {
251
- "type": "ReactNode",
252
- "optional": true,
253
- "description": "Icon from `@phosphor-icons/react` or a React element. Rendered before children."
254
- },
255
- "loading": {
256
- "type": "boolean",
257
- "optional": true,
258
- "description": "Shows a loading spinner and disables interaction."
259
- },
260
242
  "shape": {
261
243
  "type": "enum",
262
244
  "optional": true,
263
- "description": "Button shape.\n- `\"base\"` — Default rectangular button\n- `\"square\"` — Square button for icon-only actions\n- `\"circle\"` — Circular button for icon-only actions",
264
245
  "values": [
265
246
  "base",
266
247
  "square",
@@ -280,7 +261,6 @@
280
261
  "size": {
281
262
  "type": "enum",
282
263
  "optional": true,
283
- "description": "Button size.\n- `\"xs\"` — Extra small for compact UIs\n- `\"sm\"` — Small for secondary actions\n- `\"base\"` — Default size\n- `\"lg\"` — Large for primary CTAs",
284
264
  "values": [
285
265
  "xs",
286
266
  "sm",
@@ -304,7 +284,6 @@
304
284
  "variant": {
305
285
  "type": "enum",
306
286
  "optional": true,
307
- "description": "Visual style of the button.\n- `\"primary\"` — High-emphasis, brand-colored for primary actions\n- `\"secondary\"` — Default style with border for most actions\n- `\"ghost\"` — Minimal, no background for tertiary actions\n- `\"destructive\"` — Danger button for destructive actions\n- `\"secondary-destructive\"` — Secondary style with destructive text\n- `\"outline\"` — Bordered with transparent background",
308
287
  "values": [
309
288
  "primary",
310
289
  "secondary",
@@ -354,6 +333,24 @@
354
333
  },
355
334
  "default": "secondary"
356
335
  },
336
+ "children": {
337
+ "type": "ReactNode",
338
+ "optional": true
339
+ },
340
+ "className": {
341
+ "type": "string",
342
+ "optional": true
343
+ },
344
+ "icon": {
345
+ "type": "ReactNode",
346
+ "optional": true,
347
+ "description": "Icon from `@phosphor-icons/react` or a React element. Rendered before children."
348
+ },
349
+ "loading": {
350
+ "type": "boolean",
351
+ "optional": true,
352
+ "description": "Shows a loading spinner and disables interaction."
353
+ },
357
354
  "id": {
358
355
  "type": "string",
359
356
  "optional": true
@@ -389,7 +386,7 @@
389
386
  }
390
387
  },
391
388
  "examples": [
392
- "<div className=\"flex flex-wrap items-center gap-2\">\n <Button variant=\"secondary\">Button</Button>\n <Button variant=\"secondary\" shape=\"square\" icon={PlusIcon} />\n </div>",
389
+ "<div className=\"flex flex-wrap items-center gap-2\">\n <Button variant=\"secondary\">Button</Button>\n <Button\n variant=\"secondary\"\n shape=\"square\"\n icon={PlusIcon}\n aria-label=\"Add\"\n />\n </div>",
393
390
  "<Button variant=\"primary\">Primary</Button>",
394
391
  "<Button variant=\"secondary\">Secondary</Button>",
395
392
  "<Button variant=\"ghost\">Ghost</Button>",
@@ -398,7 +395,7 @@
398
395
  "<Button variant=\"secondary-destructive\">Secondary Destructive</Button>",
399
396
  "<div className=\"flex flex-wrap items-center gap-3\">\n <Button size=\"xs\" variant=\"secondary\">\n Extra Small\n </Button>\n <Button size=\"sm\" variant=\"secondary\">\n Small\n </Button>\n <Button size=\"base\" variant=\"secondary\">\n Base\n </Button>\n <Button size=\"lg\" variant=\"secondary\">\n Large\n </Button>\n </div>",
400
397
  "<Button variant=\"secondary\" icon={PlusIcon}>\n Create Worker\n </Button>",
401
- "<div className=\"flex flex-wrap items-center gap-3\">\n <Button variant=\"secondary\" shape=\"square\" icon={PlusIcon} />\n <Button variant=\"secondary\" shape=\"circle\" icon={PlusIcon} />\n </div>",
398
+ "<div className=\"flex flex-wrap items-center gap-3\">\n <Button\n variant=\"secondary\"\n shape=\"square\"\n icon={PlusIcon}\n aria-label=\"Add item\"\n />\n <Button\n variant=\"secondary\"\n shape=\"circle\"\n icon={PlusIcon}\n aria-label=\"Add item\"\n />\n </div>",
402
399
  "<Button variant=\"primary\" loading>\n Loading...\n </Button>",
403
400
  "<Button variant=\"secondary\" disabled>\n Disabled\n </Button>"
404
401
  ],
@@ -2409,8 +2406,9 @@
2409
2406
  }
2410
2407
  },
2411
2408
  "examples": [
2412
- "<Dialog.Root>\n <Dialog.Trigger render={(p) => <Button {...p}>Click me</Button>} />\n <Dialog className=\"p-8\">\n <div className=\"mb-4 flex items-start justify-between gap-4\">\n <Dialog.Title className=\"text-2xl font-semibold\">\n Modal Title\n </Dialog.Title>\n <Dialog.Close\n aria-label=\"Close\"\n render={(props) => (\n <Button\n {...props}\n variant=\"secondary\"\n shape=\"square\"\n icon={<X />}\n />\n )}\n />\n </div>\n <Dialog.Description className=\"text-kumo-subtle\">\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n eiusmod tempor incididunt ut labore et dolore magna aliqua.\n </Dialog.Description>\n </Dialog>\n </Dialog.Root>",
2413
- "<Dialog.Root>\n <Dialog.Trigger render={(p) => <Button {...p}>Delete</Button>} />\n <Dialog className=\"p-8\">\n <div className=\"mb-4 flex items-start justify-between gap-4\">\n <Dialog.Title className=\"text-2xl font-semibold\">\n Modal Title\n </Dialog.Title>\n <Dialog.Close\n aria-label=\"Close\"\n render={(props) => (\n <Button\n {...props}\n variant=\"secondary\"\n shape=\"square\"\n icon={<X />}\n />\n )}\n />\n </div>\n <Dialog.Description className=\"text-kumo-subtle\">\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n eiusmod tempor incididunt ut labore et dolore magna aliqua.\n </Dialog.Description>\n <div className=\"mt-8 flex justify-end gap-2\">\n <Dialog.Close\n render={(props) => (\n <Button variant=\"secondary\" {...props}>\n Cancel\n </Button>\n )}\n />\n <Dialog.Close\n render={(props) => (\n <Button variant=\"destructive\" {...props}>\n Delete\n </Button>\n )}\n />\n </div>\n </Dialog>\n </Dialog.Root>"
2409
+ "<Dialog.Root>\n <Dialog.Trigger render={(p) => <Button {...p}>Click me</Button>} />\n <Dialog className=\"p-8\">\n <div className=\"mb-4 flex items-start justify-between gap-4\">\n <Dialog.Title className=\"text-2xl font-semibold\">\n Modal Title\n </Dialog.Title>\n <Dialog.Close\n aria-label=\"Close\"\n render={(props) => (\n <Button\n {...props}\n variant=\"secondary\"\n shape=\"square\"\n icon={<X />}\n aria-label=\"Close\"\n />\n )}\n />\n </div>\n <Dialog.Description className=\"text-kumo-subtle\">\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n eiusmod tempor incididunt ut labore et dolore magna aliqua.\n </Dialog.Description>\n </Dialog>\n </Dialog.Root>",
2410
+ "<Dialog.Root>\n <Dialog.Trigger render={(p) => <Button {...p}>Delete</Button>} />\n <Dialog className=\"p-8\">\n <div className=\"mb-4 flex items-start justify-between gap-4\">\n <Dialog.Title className=\"text-2xl font-semibold\">\n Modal Title\n </Dialog.Title>\n <Dialog.Close\n aria-label=\"Close\"\n render={(props) => (\n <Button\n {...props}\n variant=\"secondary\"\n shape=\"square\"\n icon={<X />}\n aria-label=\"Close\"\n />\n )}\n />\n </div>\n <Dialog.Description className=\"text-kumo-subtle\">\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n eiusmod tempor incididunt ut labore et dolore magna aliqua.\n </Dialog.Description>\n <div className=\"mt-8 flex justify-end gap-2\">\n <Dialog.Close\n render={(props) => (\n <Button variant=\"secondary\" {...props}>\n Cancel\n </Button>\n )}\n />\n <Dialog.Close\n render={(props) => (\n <Button variant=\"destructive\" {...props}>\n Delete\n </Button>\n )}\n />\n </div>\n </Dialog>\n </Dialog.Root>",
2411
+ "<Dialog.Root disablePointerDismissal>\n <Dialog.Trigger\n render={(p) => (\n <Button {...p} variant=\"destructive\">\n Delete Project\n </Button>\n )}\n />\n <Dialog className=\"p-8\">\n <div className=\"mb-4 flex items-center gap-3\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-kumo-danger/20\">\n <Warning size={20} className=\"text-kumo-danger\" />\n </div>\n <Dialog.Title className=\"text-xl font-semibold\">\n Delete Project?\n </Dialog.Title>\n </div>\n <Dialog.Description className=\"text-kumo-subtle\">\n This action cannot be undone. This will permanently delete the project\n and all associated data.\n </Dialog.Description>\n <div className=\"mt-8 flex justify-end gap-2\">\n <Dialog.Close\n render={(props) => (\n <Button variant=\"secondary\" {...props}>\n Cancel\n </Button>\n )}\n />\n <Dialog.Close\n render={(props) => (\n <Button variant=\"destructive\" {...props}>\n Delete\n </Button>\n )}\n />\n </div>\n </Dialog>\n </Dialog.Root>"
2414
2412
  ],
2415
2413
  "colors": [
2416
2414
  "bg-kumo-base",
@@ -2420,113 +2418,28 @@
2420
2418
  "subComponents": {
2421
2419
  "Root": {
2422
2420
  "name": "Root",
2423
- "description": "Controls the open state of the dialog. Doesn't render its own HTML element.",
2424
- "props": {
2425
- "open": {
2426
- "type": "boolean",
2427
- "description": "Whether the dialog is currently open (controlled mode)"
2428
- },
2429
- "defaultOpen": {
2430
- "type": "boolean",
2431
- "description": "Whether the dialog is initially open (uncontrolled mode)",
2432
- "default": "false"
2433
- },
2434
- "onOpenChange": {
2435
- "type": "(open: boolean, event: Event) => void",
2436
- "description": "Callback fired when the dialog opens or closes"
2437
- },
2438
- "modal": {
2439
- "type": "boolean | 'trap-focus'",
2440
- "description": "Whether the dialog is modal. When true, focus is trapped and page scroll is locked",
2441
- "default": "true"
2442
- },
2443
- "dismissible": {
2444
- "type": "boolean",
2445
- "description": "Whether clicking outside closes the dialog",
2446
- "default": "true"
2447
- }
2448
- },
2449
- "isPassThrough": true,
2450
- "baseComponent": "DialogBase.Root",
2451
- "usageExamples": [
2452
- "<Dialog.Root open={isOpen} onOpenChange={setIsOpen}>",
2453
- "<Dialog.Root defaultOpen={false}>"
2454
- ]
2421
+ "description": "Root sub-component",
2422
+ "props": {}
2455
2423
  },
2456
2424
  "Trigger": {
2457
2425
  "name": "Trigger",
2458
- "description": "A button that opens the dialog when clicked.",
2459
- "props": {
2460
- "render": {
2461
- "type": "ReactElement | ((props, state) => ReactElement)",
2462
- "description": "Custom element to render instead of the default button"
2463
- },
2464
- "disabled": {
2465
- "type": "boolean",
2466
- "description": "Whether the trigger is disabled"
2467
- }
2468
- },
2469
- "isPassThrough": true,
2470
- "baseComponent": "DialogBase.Trigger",
2471
- "usageExamples": [
2472
- "<Dialog.Trigger render={<Button>Open</Button>} />",
2473
- "<Dialog.Trigger>Open Dialog</Dialog.Trigger>"
2474
- ],
2475
- "renderElement": "<button>"
2426
+ "description": "Trigger sub-component",
2427
+ "props": {}
2476
2428
  },
2477
2429
  "Title": {
2478
2430
  "name": "Title",
2479
- "description": "A heading that labels the dialog for accessibility.",
2480
- "props": {
2481
- "render": {
2482
- "type": "ReactElement | ((props, state) => ReactElement)",
2483
- "description": "Custom element to render instead of the default h2"
2484
- }
2485
- },
2486
- "isPassThrough": true,
2487
- "baseComponent": "DialogBase.Title",
2488
- "usageExamples": [
2489
- "<Dialog.Title>Confirm Action</Dialog.Title>",
2490
- "<Dialog.Title render={<h3 />}>Custom Heading</Dialog.Title>"
2491
- ],
2492
- "renderElement": "<h2>"
2431
+ "description": "Title sub-component",
2432
+ "props": {}
2493
2433
  },
2494
2434
  "Description": {
2495
2435
  "name": "Description",
2496
- "description": "A paragraph providing additional context about the dialog.",
2497
- "props": {
2498
- "render": {
2499
- "type": "ReactElement | ((props, state) => ReactElement)",
2500
- "description": "Custom element to render instead of the default p"
2501
- }
2502
- },
2503
- "isPassThrough": true,
2504
- "baseComponent": "DialogBase.Description",
2505
- "usageExamples": [
2506
- "<Dialog.Description>Are you sure you want to proceed?</Dialog.Description>"
2507
- ],
2508
- "renderElement": "<p>"
2436
+ "description": "Description sub-component",
2437
+ "props": {}
2509
2438
  },
2510
2439
  "Close": {
2511
2440
  "name": "Close",
2512
- "description": "A button that closes the dialog when clicked.",
2513
- "props": {
2514
- "render": {
2515
- "type": "ReactElement | ((props, state) => ReactElement)",
2516
- "description": "Custom element to render instead of the default button"
2517
- },
2518
- "disabled": {
2519
- "type": "boolean",
2520
- "description": "Whether the close button is disabled"
2521
- }
2522
- },
2523
- "isPassThrough": true,
2524
- "baseComponent": "DialogBase.Close",
2525
- "usageExamples": [
2526
- "<Dialog.Close render={<Button>Cancel</Button>} />",
2527
- "<Dialog.Close>×</Dialog.Close>"
2528
- ],
2529
- "renderElement": "<button>"
2441
+ "description": "Close sub-component",
2442
+ "props": {}
2530
2443
  }
2531
2444
  },
2532
2445
  "styling": {
@@ -3137,10 +3050,15 @@
3137
3050
  "optional": true,
3138
3051
  "description": "Additional CSS classes merged via `cn()`."
3139
3052
  },
3053
+ "htmlFor": {
3054
+ "type": "string",
3055
+ "optional": true,
3056
+ "description": "The id of the form element this label is associated with"
3057
+ },
3140
3058
  "asContent": {
3141
3059
  "type": "boolean",
3142
3060
  "optional": true,
3143
- "description": "When `true`, only renders the inline content (indicators, tooltip) without the outer span with font styling. Useful when composed inside another label element that already provides the text styling."
3061
+ "description": "When true, only renders the inline content (indicators, tooltip) without the outer label element with font styling. Useful when composed inside another label element that already provides the text styling."
3144
3062
  }
3145
3063
  },
3146
3064
  "examples": [
@@ -3174,7 +3092,7 @@
3174
3092
  }
3175
3093
  },
3176
3094
  "examples": [
3177
- "<LayerCard>\n <LayerCard.Secondary className=\"flex items-center justify-between\">\n <div>Next Steps</div>\n <Button variant=\"ghost\" size=\"sm\" shape=\"square\">\n <ArrowRightIcon size={16} />\n </Button>\n </LayerCard.Secondary>\n\n <LayerCard.Primary>Get started with Kumo</LayerCard.Primary>\n </LayerCard>",
3095
+ "<LayerCard>\n <LayerCard.Secondary className=\"flex items-center justify-between\">\n <div>Next Steps</div>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n shape=\"square\"\n aria-label=\"Go to next steps\"\n >\n <ArrowRightIcon size={16} />\n </Button>\n </LayerCard.Secondary>\n\n <LayerCard.Primary>Get started with Kumo</LayerCard.Primary>\n </LayerCard>",
3178
3096
  "<LayerCard className=\"w-[250px]\">\n <LayerCard.Secondary>Getting Started</LayerCard.Secondary>\n <LayerCard.Primary>\n <p className=\"text-sm text-kumo-subtle\">\n Quick start guide for new users\n </p>\n </LayerCard.Primary>\n </LayerCard>",
3179
3097
  "<div className=\"flex gap-4\">\n <LayerCard className=\"w-[200px]\">\n <LayerCard.Secondary>Components</LayerCard.Secondary>\n <LayerCard.Primary>\n <p className=\"text-sm\">Browse all components</p>\n </LayerCard.Primary>\n </LayerCard>\n <LayerCard className=\"w-[200px]\">\n <LayerCard.Secondary>Examples</LayerCard.Secondary>\n <LayerCard.Primary>\n <p className=\"text-sm\">View code examples</p>\n </LayerCard.Primary>\n </LayerCard>\n </div>"
3180
3098
  ],
@@ -3528,6 +3446,11 @@
3528
3446
  "type": "number",
3529
3447
  "optional": true,
3530
3448
  "description": "Total number of items across all pages."
3449
+ },
3450
+ "text": {
3451
+ "type": "object",
3452
+ "optional": true,
3453
+ "description": "Method to provide custom pagination text"
3531
3454
  }
3532
3455
  },
3533
3456
  "examples": [
@@ -3535,7 +3458,8 @@
3535
3458
  "<Pagination\n page={page}\n setPage={setPage}\n perPage={10}\n totalCount={100}\n controls=\"simple\"\n />",
3536
3459
  "<Pagination\n page={page}\n setPage={setPage}\n perPage={10}\n totalCount={100}\n controls=\"full\"\n />",
3537
3460
  "<Pagination page={page} setPage={setPage} perPage={10} totalCount={100} />",
3538
- "<Pagination page={page} setPage={setPage} perPage={25} totalCount={1250} />"
3461
+ "<Pagination page={page} setPage={setPage} perPage={25} totalCount={1250} />",
3462
+ "<Pagination\n text={({ perPage }) => `Page ${page} - showing ${perPage} per page`}\n page={page}\n setPage={setPage}\n perPage={25}\n totalCount={100}\n />"
3539
3463
  ],
3540
3464
  "colors": [
3541
3465
  "text-kumo-strong"
@@ -3578,7 +3502,7 @@
3578
3502
  }
3579
3503
  },
3580
3504
  "examples": [
3581
- "<Popover>\n <Popover.Trigger asChild>\n <Button shape=\"square\" icon={BellIcon} />\n </Popover.Trigger>\n <Popover.Content>\n <Popover.Title>Notifications</Popover.Title>\n <Popover.Description>\n You are all caught up. Good job!\n </Popover.Description>\n </Popover.Content>\n </Popover>",
3505
+ "<Popover>\n <Popover.Trigger asChild>\n <Button shape=\"square\" icon={BellIcon} aria-label=\"Notifications\" />\n </Popover.Trigger>\n <Popover.Content>\n <Popover.Title>Notifications</Popover.Title>\n <Popover.Description>\n You are all caught up. Good job!\n </Popover.Description>\n </Popover.Content>\n </Popover>",
3582
3506
  "<Popover>\n <Popover.Trigger asChild>\n <Button>Open Popover</Button>\n </Popover.Trigger>\n <Popover.Content>\n <Popover.Title>Popover Title</Popover.Title>\n <Popover.Description>\n This is a basic popover with a title and description.\n </Popover.Description>\n </Popover.Content>\n </Popover>",
3583
3507
  "<Popover>\n <Popover.Trigger asChild>\n <Button>Open Settings</Button>\n </Popover.Trigger>\n <Popover.Content>\n <Popover.Title>Settings</Popover.Title>\n <Popover.Description>\n Configure your preferences below.\n </Popover.Description>\n <div className=\"mt-3\">\n <Popover.Close asChild>\n <Button variant=\"secondary\" size=\"sm\">\n Close\n </Button>\n </Popover.Close>\n </div>\n </Popover.Content>\n </Popover>",
3584
3508
  "<div className=\"flex flex-wrap gap-4\">\n <Popover>\n <Popover.Trigger asChild>\n <Button variant=\"secondary\">Bottom</Button>\n </Popover.Trigger>\n <Popover.Content side=\"bottom\">\n <Popover.Title>Bottom</Popover.Title>\n <Popover.Description>\n Popover on bottom (default).\n </Popover.Description>\n </Popover.Content>\n </Popover>\n\n <Popover>\n <Popover.Trigger asChild>\n <Button variant=\"secondary\">Top</Button>\n </Popover.Trigger>\n <Popover.Content side=\"top\">\n <Popover.Title>Top</Popover.Title>\n <Popover.Description>Popover on top.</Popover.Description>\n </Popover.Content>\n </Popover>\n\n <Popover>\n <Popover.Trigger asChild>\n <Button variant=\"secondary\">Left</Button>\n </Popover.Trigger>\n <Popover.Content side=\"left\">\n <Popover.Title>Left</Popover.Title>\n <Popover.Description>Popover on left.</Popover.Description>\n </Popover.Content>\n </Popover>\n\n <Popover>\n <Popover.Trigger asChild>\n <Button variant=\"secondary\">Right</Button>\n </Popover.Trigger>\n <Popover.Content side=\"right\">\n <Popover.Title>Right</Popover.Title>\n <Popover.Description>Popover on right.</Popover.Description>\n </Popover.Content>\n </Popover>\n </div>",
@@ -3786,7 +3710,7 @@
3786
3710
  }
3787
3711
  },
3788
3712
  "examples": [
3789
- "<Select\n className=\"w-[200px]\"\n value={value}\n onValueChange={(v) => setValue(v ?? \"Apple\")}\n placeholder=\"Please select\"\n >\n <Select.Option value=\"Apple\">Apple</Select.Option>\n <Select.Option value=\"Banana\">Banana</Select.Option>\n <Select.Option value=\"Cherry\">Cherry</Select.Option>\n </Select>",
3713
+ "<Select\n className=\"w-[200px]\"\n value={value}\n onValueChange={(v) => setValue(v ?? \"apple\")}\n items={{ apple: \"Apple\", banana: \"Banana\", cherry: \"Cherry\" }}\n >\n <Select.Option value=\"apple\">Apple</Select.Option>\n <Select.Option value=\"banana\">Banana</Select.Option>\n <Select.Option value=\"cherry\">Cherry</Select.Option>\n </Select>",
3790
3714
  "<Select\n className=\"w-[200px]\"\n value={value}\n onValueChange={(v) => setValue(v as string)}\n items={{\n bug: \"Bug\",\n documentation: \"Documentation\",\n feature: \"Feature\",\n }}\n >\n <Select.Option value=\"bug\">Bug</Select.Option>\n <Select.Option value=\"documentation\">Documentation</Select.Option>\n <Select.Option value=\"feature\">Feature</Select.Option>\n </Select>",
3791
3715
  "<Select\n className=\"w-[200px]\"\n value={value}\n onValueChange={(v) => setValue(v as string | null)}\n items={[\n { value: null, label: \"Please select\" },\n { value: \"bug\", label: \"Bug\" },\n { value: \"documentation\", label: \"Documentation\" },\n { value: \"feature\", label: \"Feature\" },\n ]}\n >\n <Select.Option value=\"bug\">Bug</Select.Option>\n <Select.Option value=\"documentation\">Documentation</Select.Option>\n <Select.Option value=\"feature\">Feature</Select.Option>\n </Select>",
3792
3716
  "<Select\n className=\"w-[200px]\"\n renderValue={(v) => (\n <span>\n {v.emoji} {v.label}\n </span>\n )}\n value={value}\n onValueChange={(v) => setValue(v as (typeof languages)[0])}\n >\n {languages.map((language) => (\n <Select.Option key={language.value} value={language}>\n {language.emoji} {language.label}\n </Select.Option>\n ))}\n </Select>",
@@ -4236,10 +4160,10 @@
4236
4160
  },
4237
4161
  "examples": [
4238
4162
  "<LayerCard>\n <LayerCard.Primary className=\"p-0\">\n <Table>\n <Table.Header>\n <Table.Row>\n <Table.Head>Subject</Table.Head>\n <Table.Head>From</Table.Head>\n <Table.Head>Date</Table.Head>\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {emailData.slice(0, 3).map((row) => (\n <Table.Row key={row.id}>\n <Table.Cell>{row.subject}</Table.Cell>\n <Table.Cell>{row.from}</Table.Cell>\n <Table.Cell>{row.date}</Table.Cell>\n </Table.Row>\n ))}\n </Table.Body>\n </Table>\n </LayerCard.Primary>\n </LayerCard>",
4239
- "<LayerCard>\n <LayerCard.Primary className=\"p-0\">\n <Table>\n <Table.Header>\n <Table.Row>\n <Table.CheckHead aria-label=\"Select all rows\" />\n <Table.Head>Subject</Table.Head>\n <Table.Head>From</Table.Head>\n <Table.Head>Date</Table.Head>\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {emailData.slice(0, 3).map((row) => (\n <Table.Row key={row.id}>\n <Table.CheckCell aria-label={`Select ${row.subject}`} />\n <Table.Cell>{row.subject}</Table.Cell>\n <Table.Cell>{row.from}</Table.Cell>\n <Table.Cell>{row.date}</Table.Cell>\n </Table.Row>\n ))}\n </Table.Body>\n </Table>\n </LayerCard.Primary>\n </LayerCard>",
4240
- "<LayerCard>\n <LayerCard.Primary className=\"p-0\">\n <Table>\n <Table.Header>\n <Table.Row>\n <Table.CheckHead aria-label=\"Select all rows\" />\n <Table.Head>Subject</Table.Head>\n <Table.Head>From</Table.Head>\n <Table.Head>Date</Table.Head>\n </Table.Row>\n </Table.Header>\n <Table.Body>\n <Table.Row>\n <Table.CheckCell aria-label=\"Select row 1\" />\n <Table.Cell>Kumo v1.0.0 released</Table.Cell>\n <Table.Cell>Visal In</Table.Cell>\n <Table.Cell>5 seconds ago</Table.Cell>\n </Table.Row>\n <Table.Row variant=\"selected\">\n <Table.CheckCell checked aria-label=\"Select row 2\" />\n <Table.Cell>New Job Offer</Table.Cell>\n <Table.Cell>Cloudflare</Table.Cell>\n <Table.Cell>10 minutes ago</Table.Cell>\n </Table.Row>\n <Table.Row>\n <Table.CheckCell aria-label=\"Select row 3\" />\n <Table.Cell>Daily Email Digest</Table.Cell>\n <Table.Cell>Cloudflare</Table.Cell>\n <Table.Cell>1 hour ago</Table.Cell>\n </Table.Row>\n </Table.Body>\n </Table>\n </LayerCard.Primary>\n </LayerCard>",
4163
+ "<LayerCard>\n <LayerCard.Primary className=\"p-0\">\n <Table>\n <Table.Header>\n <Table.Row>\n <Table.CheckHead\n checked={selectedIds.size === rows.length}\n indeterminate={\n selectedIds.size > 0 && selectedIds.size < rows.length\n }\n onValueChange={toggleAll}\n aria-label=\"Select all rows\"\n />\n <Table.Head>Subject</Table.Head>\n <Table.Head>From</Table.Head>\n <Table.Head>Date</Table.Head>\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {rows.map((row) => (\n <Table.Row key={row.id}>\n <Table.CheckCell\n checked={selectedIds.has(row.id)}\n onValueChange={() => toggleRow(row.id)}\n aria-label={`Select ${row.subject}`}\n />\n <Table.Cell>{row.subject}</Table.Cell>\n <Table.Cell>{row.from}</Table.Cell>\n <Table.Cell>{row.date}</Table.Cell>\n </Table.Row>\n ))}\n </Table.Body>\n </Table>\n </LayerCard.Primary>\n </LayerCard>",
4164
+ "<LayerCard>\n <LayerCard.Primary className=\"p-0\">\n <Table>\n <Table.Header>\n <Table.Row>\n <Table.CheckHead\n checked={selectedIds.size === rows.length}\n indeterminate={\n selectedIds.size > 0 && selectedIds.size < rows.length\n }\n onValueChange={toggleAll}\n aria-label=\"Select all rows\"\n />\n <Table.Head>Subject</Table.Head>\n <Table.Head>From</Table.Head>\n <Table.Head>Date</Table.Head>\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {rows.map((row) => (\n <Table.Row\n key={row.id}\n variant={selectedIds.has(row.id) ? \"selected\" : \"default\"}\n >\n <Table.CheckCell\n checked={selectedIds.has(row.id)}\n onValueChange={() => toggleRow(row.id)}\n aria-label={`Select ${row.subject}`}\n />\n <Table.Cell>{row.subject}</Table.Cell>\n <Table.Cell>{row.from}</Table.Cell>\n <Table.Cell>{row.date}</Table.Cell>\n </Table.Row>\n ))}\n </Table.Body>\n </Table>\n </LayerCard.Primary>\n </LayerCard>",
4241
4165
  "<LayerCard>\n <LayerCard.Primary className=\"p-0\">\n <Table layout=\"fixed\">\n <colgroup>\n <col />\n <col className=\"w-[150px]\" />\n <col className=\"w-[150px]\" />\n </colgroup>\n <Table.Header>\n <Table.Row>\n <Table.Head>Subject</Table.Head>\n <Table.Head>From</Table.Head>\n <Table.Head>Date</Table.Head>\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {emailData.map((row) => (\n <Table.Row key={row.id}>\n <Table.Cell>{row.subject}</Table.Cell>\n <Table.Cell>{row.from}</Table.Cell>\n <Table.Cell>{row.date}</Table.Cell>\n </Table.Row>\n ))}\n </Table.Body>\n </Table>\n </LayerCard.Primary>\n </LayerCard>",
4242
- "<LayerCard>\n <LayerCard.Primary className=\"w-full overflow-x-auto p-0\">\n <Table layout=\"fixed\">\n <colgroup>\n <col style={{ width: \"40px\" }} />\n <col />\n <col style={{ width: \"150px\" }} />\n <col style={{ width: \"120px\" }} />\n <col style={{ width: \"50px\" }} />\n </colgroup>\n <Table.Header>\n <Table.Row>\n <Table.CheckHead aria-label=\"Select all rows\" />\n <Table.Head>Subject</Table.Head>\n <Table.Head>From</Table.Head>\n <Table.Head>Date</Table.Head>\n <Table.Head></Table.Head>\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {emailData.map((row, index) => (\n <Table.Row\n key={row.id}\n variant={index === 1 ? \"selected\" : \"default\"}\n >\n <Table.CheckCell\n checked={index === 1}\n aria-label={`Select ${row.subject}`}\n />\n <Table.Cell>\n <div className=\"flex items-center gap-2\">\n <EnvelopeSimple size={16} />\n <span className=\"truncate\">{row.subject}</span>\n {row.tags && (\n <div className=\"ml-2 inline-flex gap-1\">\n {row.tags.map((tag) => (\n <Badge key={tag}>{tag}</Badge>\n ))}\n </div>\n )}\n </div>\n </Table.Cell>\n <Table.Cell>\n <span className=\"truncate\">{row.from}</span>\n </Table.Cell>\n <Table.Cell>\n <span className=\"truncate\">{row.date}</span>\n </Table.Cell>\n <Table.Cell className=\"text-right\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n shape=\"square\"\n aria-label=\"More options\"\n >\n <DotsThree weight=\"bold\" size={16} />\n </Button>\n </Table.Cell>\n </Table.Row>\n ))}\n </Table.Body>\n </Table>\n </LayerCard.Primary>\n </LayerCard>"
4166
+ "<LayerCard>\n <LayerCard.Primary className=\"w-full overflow-x-auto p-0\">\n <Table layout=\"fixed\">\n <colgroup>\n <col />{\" \"}\n {/* Checkbox column - width handled by Table.CheckHead/CheckCell */}\n <col />\n <col style={{ width: \"150px\" }} />\n <col style={{ width: \"120px\" }} />\n <col style={{ width: \"50px\" }} />\n </colgroup>\n <Table.Header>\n <Table.Row>\n <Table.CheckHead\n checked={selectedIds.size === emailData.length}\n indeterminate={\n selectedIds.size > 0 && selectedIds.size < emailData.length\n }\n onValueChange={toggleAll}\n aria-label=\"Select all rows\"\n />\n <Table.Head>Subject</Table.Head>\n <Table.Head>From</Table.Head>\n <Table.Head>Date</Table.Head>\n <Table.Head></Table.Head>\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {emailData.map((row) => (\n <Table.Row\n key={row.id}\n variant={selectedIds.has(row.id) ? \"selected\" : \"default\"}\n >\n <Table.CheckCell\n checked={selectedIds.has(row.id)}\n onValueChange={() => toggleRow(row.id)}\n aria-label={`Select ${row.subject}`}\n />\n <Table.Cell>\n <div className=\"flex items-center gap-2\">\n <EnvelopeSimple size={16} />\n <span className=\"truncate\">{row.subject}</span>\n {row.tags && (\n <div className=\"ml-2 inline-flex gap-1\">\n {row.tags.map((tag) => (\n <Badge key={tag}>{tag}</Badge>\n ))}\n </div>\n )}\n </div>\n </Table.Cell>\n <Table.Cell>\n <span className=\"truncate\">{row.from}</span>\n </Table.Cell>\n <Table.Cell>\n <span className=\"truncate\">{row.date}</span>\n </Table.Cell>\n <Table.Cell className=\"text-right\">\n <DropdownMenu>\n <DropdownMenu.Trigger\n render={\n <Button\n variant=\"ghost\"\n size=\"sm\"\n shape=\"square\"\n aria-label=\"More options\"\n >\n <DotsThree weight=\"bold\" size={16} />\n </Button>\n }\n />\n <DropdownMenu.Content>\n <DropdownMenu.Item icon={Eye}>View</DropdownMenu.Item>\n <DropdownMenu.Item icon={PencilSimple}>\n Edit\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n <DropdownMenu.Item icon={Trash} variant=\"danger\">\n Delete\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu>\n </Table.Cell>\n </Table.Row>\n ))}\n </Table.Body>\n </Table>\n </LayerCard.Primary>\n </LayerCard>"
4243
4167
  ],
4244
4168
  "colors": [
4245
4169
  "bg-kumo-base",
@@ -4645,9 +4569,9 @@
4645
4569
  }
4646
4570
  },
4647
4571
  "examples": [
4648
- "<TooltipProvider>\n <Tooltip content=\"Add new item\" asChild>\n <Button shape=\"square\" icon={PlusIcon} />\n </Tooltip>\n </TooltipProvider>",
4649
- "<TooltipProvider>\n <Tooltip content=\"Add\" asChild>\n <Button shape=\"square\" icon={PlusIcon} />\n </Tooltip>\n </TooltipProvider>",
4650
- "<TooltipProvider>\n <div className=\"flex gap-2\">\n <Tooltip content=\"Add\" asChild>\n <Button shape=\"square\" icon={PlusIcon} />\n </Tooltip>\n <Tooltip content=\"Change language\" asChild>\n <Button shape=\"square\" icon={TranslateIcon} />\n </Tooltip>\n </div>\n </TooltipProvider>"
4572
+ "<TooltipProvider>\n <Tooltip content=\"Add new item\" asChild>\n <Button shape=\"square\" icon={PlusIcon} aria-label=\"Add new item\" />\n </Tooltip>\n </TooltipProvider>",
4573
+ "<TooltipProvider>\n <Tooltip content=\"Add\" asChild>\n <Button shape=\"square\" icon={PlusIcon} aria-label=\"Add\" />\n </Tooltip>\n </TooltipProvider>",
4574
+ "<TooltipProvider>\n <div className=\"flex gap-2\">\n <Tooltip content=\"Add\" asChild>\n <Button shape=\"square\" icon={PlusIcon} aria-label=\"Add\" />\n </Tooltip>\n <Tooltip content=\"Change language\" asChild>\n <Button\n shape=\"square\"\n icon={TranslateIcon}\n aria-label=\"Change language\"\n />\n </Tooltip>\n </div>\n </TooltipProvider>"
4651
4575
  ],
4652
4576
  "colors": [
4653
4577
  "bg-kumo-base",