@kerfjs/ui 5.0.0-beta.62 → 5.0.0-beta.63

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 (154) hide show
  1. package/README.md +4 -0
  2. package/ai/component-catalog-extension.schema.json +13 -0
  3. package/ai/component-catalog.json +8 -2
  4. package/ai/component-composition.json +9 -2
  5. package/ai/components/list-item.md +1 -1
  6. package/ai/components/workbench.md +3 -2
  7. package/ai/public-api-signatures-v1.md +136 -38
  8. package/ai/skill.md +9 -5
  9. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  10. package/analyzer/index.mjs +3 -2
  11. package/catalog-projection-cli.mjs +96 -0
  12. package/catalog-projection.d.mts +55 -0
  13. package/catalog-projection.mjs +62 -0
  14. package/dist/browser/catalog.js +1 -1
  15. package/dist/browser/collapsible-panel.js +2 -0
  16. package/dist/browser/nav-stack.js +1 -0
  17. package/dist/browser/split-view.js +1 -0
  18. package/dist/browser/toolbar-control-group.js +1 -0
  19. package/dist/browser/workbench.js +1 -0
  20. package/dist/catalog-resources.d.ts +1 -1
  21. package/dist/catalog.d.ts +1 -1
  22. package/dist/catalog.js +11 -10
  23. package/dist/catalog.js.map +1 -1
  24. package/dist/chip.d.ts +9 -3
  25. package/dist/chip.js +1 -1
  26. package/dist/{chunk-OD2VXAPL.js → chunk-3BYFWTP3.js} +4 -3
  27. package/dist/chunk-3BYFWTP3.js.map +1 -0
  28. package/dist/{chunk-5Q3N6EV7.js → chunk-5IJ6UGNZ.js} +3 -3
  29. package/dist/{chunk-5Q3N6EV7.js.map → chunk-5IJ6UGNZ.js.map} +1 -1
  30. package/dist/chunk-7AKGPBCC.js +76 -0
  31. package/dist/chunk-7AKGPBCC.js.map +1 -0
  32. package/dist/{chunk-KROD7KZK.js → chunk-AUVG54KC.js} +2 -2
  33. package/dist/{chunk-KROD7KZK.js.map → chunk-AUVG54KC.js.map} +1 -1
  34. package/dist/{chunk-AUKT3KMG.js → chunk-CQHN45XR.js} +17 -2
  35. package/dist/chunk-CQHN45XR.js.map +1 -0
  36. package/dist/{chunk-SWVW56CV.js → chunk-EN4LDR5Y.js} +2 -2
  37. package/dist/{chunk-SWVW56CV.js.map → chunk-EN4LDR5Y.js.map} +1 -1
  38. package/dist/{chunk-4MG3KXJM.js → chunk-F7OCOBTG.js} +2 -2
  39. package/dist/{chunk-4MG3KXJM.js.map → chunk-F7OCOBTG.js.map} +1 -1
  40. package/dist/{chunk-KYDDCJXU.js → chunk-HXCMWANP.js} +4 -4
  41. package/dist/{chunk-KYDDCJXU.js.map → chunk-HXCMWANP.js.map} +1 -1
  42. package/dist/{chunk-ENGVYQPG.js → chunk-IA4D5XNT.js} +60 -10
  43. package/dist/chunk-IA4D5XNT.js.map +1 -0
  44. package/dist/{chunk-F4QMLOXJ.js → chunk-IAOAZUOO.js} +2 -2
  45. package/dist/{chunk-F4QMLOXJ.js.map → chunk-IAOAZUOO.js.map} +1 -1
  46. package/dist/{chunk-X6ADHJNI.js → chunk-KFYANKJI.js} +25 -6
  47. package/dist/chunk-KFYANKJI.js.map +1 -0
  48. package/dist/chunk-MOSIE4Z2.js +51 -0
  49. package/dist/chunk-MOSIE4Z2.js.map +1 -0
  50. package/dist/{chunk-7JUBXOIV.js → chunk-NXWE5S57.js} +25 -6
  51. package/dist/chunk-NXWE5S57.js.map +1 -0
  52. package/dist/{chunk-NNMLEDMD.js → chunk-OBAFAH5B.js} +36 -8
  53. package/dist/chunk-OBAFAH5B.js.map +1 -0
  54. package/dist/{chunk-A3CKOW2R.js → chunk-R75GGNWY.js} +123 -20
  55. package/dist/chunk-R75GGNWY.js.map +1 -0
  56. package/dist/chunk-RGS4WX2M.js +44 -0
  57. package/dist/chunk-RGS4WX2M.js.map +1 -0
  58. package/dist/{chunk-RRB26JRJ.js → chunk-RTJNJTG3.js} +2 -2
  59. package/dist/{chunk-RRB26JRJ.js.map → chunk-RTJNJTG3.js.map} +1 -1
  60. package/dist/{chunk-EAC4CDY7.js → chunk-SMZGAPCU.js} +15 -2
  61. package/dist/chunk-SMZGAPCU.js.map +1 -0
  62. package/dist/{chunk-6ZXOQEAN.js → chunk-WF75U3V4.js} +7 -1
  63. package/dist/chunk-WF75U3V4.js.map +1 -0
  64. package/dist/{chunk-VCBTX62E.js → chunk-ZRWXFDDS.js} +2 -2
  65. package/dist/chunk-ZRWXFDDS.js.map +1 -0
  66. package/dist/collapsible-panel.d.ts +18 -7
  67. package/dist/collapsible-panel.js +19 -3
  68. package/dist/collapsible-panel.js.map +1 -1
  69. package/dist/content-item.d.ts +36 -5
  70. package/dist/content-item.js +1 -1
  71. package/dist/disclosure-arrow.js +2 -1
  72. package/dist/index.d.ts +2 -2
  73. package/dist/index.js +19 -19
  74. package/dist/list-action-row.js +1 -1
  75. package/dist/list-header.js +1 -1
  76. package/dist/list-item.js +1 -1
  77. package/dist/lucide-icon.d.ts +5 -2
  78. package/dist/lucide-icon.js +2 -1
  79. package/dist/nav-stack.js +2 -1
  80. package/dist/pane.d.ts +2 -1
  81. package/dist/pane.js +1 -1
  82. package/dist/{panel-toolbar-DqwtBxQL.d.ts → panel-toolbar-DDKh4uKd.d.ts} +11 -2
  83. package/dist/popup-menu-register.js +38 -1
  84. package/dist/popup-menu-register.js.map +1 -1
  85. package/dist/popup-menu.d.ts +2 -2
  86. package/dist/popup-menu.js +1 -1
  87. package/dist/select.js +1 -1
  88. package/dist/split-view.js +2 -1
  89. package/dist/split-view.js.map +1 -1
  90. package/dist/styles/chip.css +14 -0
  91. package/dist/styles/content-item.css +36 -0
  92. package/dist/styles/list-action-row.css +4 -3
  93. package/dist/styles/list-header.css +4 -3
  94. package/dist/styles/list-item.css +21 -11
  95. package/dist/styles/lucide-icon.css +5 -0
  96. package/dist/styles/pane.css +3 -2
  97. package/dist/styles/popup-menu.css +15 -10
  98. package/dist/styles/select.css +11 -0
  99. package/dist/styles/sunken-panel.css +7 -0
  100. package/dist/styles/text.css +29 -0
  101. package/dist/styles/token-search-field.css +29 -6
  102. package/dist/styles/toolbar-control-group.css +35 -0
  103. package/dist/styles/workbench.css +148 -2
  104. package/dist/sunken-panel.d.ts +6 -1
  105. package/dist/sunken-panel.js +1 -1
  106. package/dist/text.d.ts +14 -3
  107. package/dist/text.js +1 -1
  108. package/dist/token-search-field.js +2 -1
  109. package/dist/toolbar-control-group.d.ts +5 -1
  110. package/dist/toolbar-control-group.js +2 -1
  111. package/dist/toolbar.d.ts +5 -2
  112. package/dist/toolbar.js +1 -1
  113. package/dist/wire-catalog.js +1 -1
  114. package/dist/wire-content-items.d.ts +9 -0
  115. package/dist/wire-content-items.js +62 -0
  116. package/dist/wire-content-items.js.map +1 -0
  117. package/dist/wire-token-search-fields.js +2 -1
  118. package/dist/wire-workbench.d.ts +7 -0
  119. package/dist/wire-workbench.js +1 -1
  120. package/dist/workbench.d.ts +24 -8
  121. package/dist/workbench.js +2 -1
  122. package/docs/accessibility.md +21 -5
  123. package/docs/catalog.md +36 -0
  124. package/docs/collapsible-panel.md +8 -1
  125. package/docs/component-contract.md +10 -4
  126. package/docs/component-selection.md +39 -8
  127. package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -1
  128. package/docs/design/templates/toolbar/title-and-actions.svg +1 -1
  129. package/docs/design/templates/toolbar-dark.svg +1 -1
  130. package/docs/design/templates/toolbar.svg +1 -1
  131. package/docs/examples/component-catalog-extension.json +6 -0
  132. package/docs/layout.md +30 -3
  133. package/docs/sunken-panel.md +22 -0
  134. package/docs/ui-analyzer.md +4 -0
  135. package/docs/workbench.md +38 -4
  136. package/llms.txt +9 -5
  137. package/package.json +16 -2
  138. package/scripts/component-catalog-extension-validation.mjs +28 -0
  139. package/dist/chunk-4R777DUZ.js +0 -34
  140. package/dist/chunk-4R777DUZ.js.map +0 -1
  141. package/dist/chunk-6ZXOQEAN.js.map +0 -1
  142. package/dist/chunk-7JUBXOIV.js.map +0 -1
  143. package/dist/chunk-A3CKOW2R.js.map +0 -1
  144. package/dist/chunk-AUKT3KMG.js.map +0 -1
  145. package/dist/chunk-EAC4CDY7.js.map +0 -1
  146. package/dist/chunk-ENGVYQPG.js.map +0 -1
  147. package/dist/chunk-MA73TA6D.js +0 -42
  148. package/dist/chunk-MA73TA6D.js.map +0 -1
  149. package/dist/chunk-N2DRU35S.js +0 -45
  150. package/dist/chunk-N2DRU35S.js.map +0 -1
  151. package/dist/chunk-NNMLEDMD.js.map +0 -1
  152. package/dist/chunk-OD2VXAPL.js.map +0 -1
  153. package/dist/chunk-VCBTX62E.js.map +0 -1
  154. package/dist/chunk-X6ADHJNI.js.map +0 -1
package/README.md CHANGED
@@ -342,6 +342,10 @@ guidance, public hooks, and explicit geometry ownership; then concatenate its
342
342
  identity alongside each input when ids could collide. This makes a combined
343
343
  tool reason about both sides of a composition using one vocabulary without
344
344
  pretending app-local components are `@kerfjs/ui` exports.
345
+ For a consumer UX demo, `@kerfjs/ui/catalog-projection` derives rows and
346
+ relationships from that extension; `kerf-catalog-demo --write` emits a typed
347
+ module and `--check` catches drift. See the [catalog guide](./docs/catalog.md)
348
+ for repository base and source path configuration.
345
349
 
346
350
  Composition-aware consumers use
347
351
  [`component-composition-extension.schema.json`](./ai/component-composition-extension.schema.json),
@@ -52,6 +52,14 @@
52
52
  "items": { "type": "string" },
53
53
  "uniqueItems": true
54
54
  },
55
+ "uses": {
56
+ "description": "Directly composed Kerf or consumer catalog entry ids.",
57
+ "type": "array",
58
+ "items": { "type": "string", "minLength": 1 },
59
+ "uniqueItems": true
60
+ },
61
+ "source": { "$ref": "#/$defs/repositoryPath" },
62
+ "demoSource": { "$ref": "#/$defs/repositoryPath" },
55
63
  "geometry": { "$ref": "#/$defs/geometry" },
56
64
  "documentation": { "type": "string", "minLength": 1 }
57
65
  },
@@ -74,6 +82,11 @@
74
82
  },
75
83
  "geometryOwner": {
76
84
  "enum": ["self", "parent", "child", "none", "conditional"]
85
+ },
86
+ "repositoryPath": {
87
+ "description": "A repository-relative POSIX path without traversal or empty segments.",
88
+ "type": "string",
89
+ "pattern": "^(?!.*(?:^|/)\\.{1,2}(?:/|$))[A-Za-z0-9._-]+(?:/[A-Za-z0-9._-]+)*$"
77
90
  }
78
91
  }
79
92
  }
@@ -1165,6 +1165,11 @@
1165
1165
  "import": "@kerfjs/ui/wire-workbench",
1166
1166
  "required": false,
1167
1167
  "stateAttributes": [
1168
+ {
1169
+ "name": "data-responsive-overlay-active",
1170
+ "on": "kui-workbench__rail and kui-workbench__drawer",
1171
+ "meaning": "Present while a panel's numeric responsiveOverlayAt threshold applies to the Workbench width; the same measurement drives overlay layout and collapsed-state transitions."
1172
+ },
1168
1173
  {
1169
1174
  "name": "data-handle-inset",
1170
1175
  "on": "kui-workbench__rail",
@@ -1206,7 +1211,8 @@
1206
1211
  "kui-workbench__panel-content",
1207
1212
  "kui-workbench__handle",
1208
1213
  "kui-workbench__handle-icon",
1209
- "kui-workbench__restore"
1214
+ "kui-workbench__restore",
1215
+ "kui-workbench__backdrop"
1210
1216
  ],
1211
1217
  "publicTokens": [
1212
1218
  "--kui-workbench-rail-width",
@@ -3102,7 +3108,7 @@
3102
3108
  "border": "self",
3103
3109
  "padding": "self",
3104
3110
  "notes": [
3105
- "Public resting background and border, hover border, and selected border tokens can be scoped to a row or its containing list without changing the default tones."
3111
+ "Public resting, hover, and selected text, fill, and border tokens can be scoped to a row or its containing list without changing the default tones."
3106
3112
  ]
3107
3113
  },
3108
3114
  "delivery": {
@@ -1091,6 +1091,12 @@
1091
1091
  "helpers": ["wireWorkbench", "wireScrollDividers"],
1092
1092
  "obligations": [],
1093
1093
  "stateAttributes": [
1094
+ {
1095
+ "name": "data-responsive-overlay-active",
1096
+ "on": "kui-workbench__rail and kui-workbench__drawer",
1097
+ "helper": "wireWorkbench",
1098
+ "meaning": "Present while a panel's numeric responsiveOverlayAt threshold applies to the Workbench width; the same measurement drives overlay layout and collapsed-state transitions."
1099
+ },
1094
1100
  {
1095
1101
  "name": "data-handle-inset",
1096
1102
  "on": "kui-workbench__rail",
@@ -1152,7 +1158,8 @@
1152
1158
  "kui-workbench__panel-content",
1153
1159
  "kui-workbench__handle",
1154
1160
  "kui-workbench__handle-icon",
1155
- "kui-workbench__restore"
1161
+ "kui-workbench__restore",
1162
+ "kui-workbench__backdrop"
1156
1163
  ],
1157
1164
  "publicTokens": [
1158
1165
  "--kui-workbench-rail-width",
@@ -2538,7 +2545,7 @@
2538
2545
  "border": "self",
2539
2546
  "padding": "self",
2540
2547
  "notes": [
2541
- "Public resting background and border, hover border, and selected border tokens can be scoped to a row or its containing list without changing the default tones."
2548
+ "Public resting, hover, and selected text, fill, and border tokens can be scoped to a row or its containing list without changing the default tones."
2542
2549
  ]
2543
2550
  }
2544
2551
  },
@@ -69,7 +69,7 @@ No wiring helper.
69
69
 
70
70
  Margin: self · border: self · padding: self (layout role: navigation). `self` means the component already owns it — do not add wrapper padding, margin, or borders around it.
71
71
 
72
- - Public resting background and border, hover border, and selected border tokens can be scoped to a row or its containing list without changing the default tones.
72
+ - Public resting, hover, and selected text, fill, and border tokens can be scoped to a row or its containing list without changing the default tones.
73
73
 
74
74
  ## Accessibility
75
75
 
@@ -76,6 +76,7 @@ Zones (a zone is bound to JSX only through its listed prop; never assume the zon
76
76
 
77
77
  **Wiring-owned state attributes** — never render, remove, or branch on these as app state:
78
78
 
79
+ - `data-responsive-overlay-active` on `kui-workbench__rail and kui-workbench__drawer` (`wireWorkbench`): Present while a panel's numeric responsiveOverlayAt threshold applies to the Workbench width; the same measurement drives overlay layout and collapsed-state transitions.
79
80
  - `data-handle-inset` on `kui-workbench__rail` (`wireWorkbench`): Written by the shared resize wiring when the work-area minimum or a parent clamp holds a rail's maximum near its size. It carries no Workbench styling; the Workbench handle stays at the rail's inner edge.
80
81
  - `data-resizing` on `kui-workbench__rail` (`wireWorkbench`): Present on a resizable rail or the drawer while a pointer drag resizes it.
81
82
  - `data-scroll-overflow` on `kui-pane__content of each panel and work-area Pane` (`wireScrollDividers`): The physical edges, in canonical t/r/b/l order, beyond which content is scrolled out of view; absent when nothing is hidden (content that fits never reports its far edges). Re-applied if a re-render drops it.
@@ -99,9 +100,9 @@ Margin: none · border: self · padding: child (layout role: structure). `self`
99
100
 
100
101
  The component owns its own styles. Configure it through its props and variants; do not override its internals.
101
102
 
102
- Public class hooks (select for layout placement only, never to change the component's look): `kui-workbench`, `kui-workbench__rail`, `kui-workbench__rail--left`, `kui-workbench__rail--right`, `kui-workbench__drawer`, `kui-workbench__center`, `kui-workbench__main`, `kui-workbench__panel-content`, `kui-workbench__handle`, `kui-workbench__handle-icon`, `kui-workbench__restore`.
103
+ Public class hooks (select for layout placement only, never to change the component's look): `kui-workbench`, `kui-workbench__rail`, `kui-workbench__rail--left`, `kui-workbench__rail--right`, `kui-workbench__drawer`, `kui-workbench__center`, `kui-workbench__main`, `kui-workbench__panel-content`, `kui-workbench__handle`, `kui-workbench__handle-icon`, `kui-workbench__restore`, `kui-workbench__backdrop`.
103
104
 
104
- Never put `kui-workbench`, `kui-workbench__rail`, `kui-workbench__rail--left`, `kui-workbench__rail--right`, `kui-workbench__drawer`, `kui-workbench__center`, `kui-workbench__main`, `kui-workbench__panel-content`, `kui-workbench__handle`, `kui-workbench__handle-icon`, `kui-workbench__restore` on an element you write; render `Workbench` instead (`KUI-L103`).
105
+ Never put `kui-workbench`, `kui-workbench__rail`, `kui-workbench__rail--left`, `kui-workbench__rail--right`, `kui-workbench__drawer`, `kui-workbench__center`, `kui-workbench__main`, `kui-workbench__panel-content`, `kui-workbench__handle`, `kui-workbench__handle-icon`, `kui-workbench__restore`, `kui-workbench__backdrop` on an element you write; render `Workbench` instead (`KUI-L103`).
105
106
 
106
107
  Public tokens it reads: `--kui-workbench-rail-width`, `--kui-workbench-drawer-height`, `--kui-workbench-popup-z`, `--kui-workbench-overlay-z`, `--kui-workbench-overlay-max-width`, `--kui-workbench-overlay-max-height`, `--kui-workbench-restore-inset`, `--kui-workbench-restore-z`, `--kui-workbench-overlay-dismiss-margin`. Set a token only where its public contract allows; prefer a prop.
107
108
 
@@ -1,6 +1,6 @@
1
1
  # Public API signatures for the UI authoring corpus
2
2
 
3
- Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.62` and `kerfjs@5.0.0-beta.62`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
3
+ Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.63` and `kerfjs@5.0.0-beta.63`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
4
4
 
5
5
  ## `@kerfjs/ui/css-values`
6
6
 
@@ -146,11 +146,14 @@ import { PaneSeparatorSide } from './pane.js';
146
146
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
147
147
  import { S as Sides } from './sides-BPSWde0A.js';
148
148
 
149
+ type ToolbarPosition = 'header' | 'footer';
149
150
  interface ToolbarProps {
150
151
  leading?: KerfUiContent;
151
152
  center?: KerfUiContent;
152
153
  trailing?: KerfUiContent;
153
154
  label?: string;
155
+ /** Use footer semantics for a bottom toolbar; defaults to header. */
156
+ position?: ToolbarPosition;
154
157
  /**
155
158
  * Physical divider edges in canonical top/right/bottom/left order, drawn
156
159
  * always. Defaults to none: a toolbar pinned over or under scrolling content
@@ -200,9 +203,9 @@ interface ToolbarProps {
200
203
  * toolbar) forwards, so the app configures that toolbar instead of styling it.
201
204
  */
202
205
  type ToolbarConfig = Pick<ToolbarProps, 'dividerSides' | 'centerAlign' | 'responsive' | 'responsiveAt' | 'safeAreaEdges'>;
203
- declare function Toolbar({ leading, center, trailing, label, dividerSides, centerAlign, responsive, responsiveAt, safeAreaEdges, className, slot, }: ToolbarProps): kerfjs.SafeHtml;
206
+ declare function Toolbar({ leading, center, trailing, label, position, dividerSides, centerAlign, responsive, responsiveAt, safeAreaEdges, className, slot, }: ToolbarProps): kerfjs.SafeHtml;
204
207
 
205
- export { Sides, Toolbar, type ToolbarConfig, type ToolbarProps };
208
+ export { Sides, Toolbar, type ToolbarConfig, type ToolbarPosition, type ToolbarProps };
206
209
  ```
207
210
 
208
211
  ## `@kerfjs/ui/toolbar-text`
@@ -321,6 +324,10 @@ interface ToolbarControlGroupProps {
321
324
  relocateOnCollapse?: boolean;
322
325
  /** Add contrast behind photo-backed avatar content. */
323
326
  scrim?: boolean;
327
+ /** Block the group's controls and show a spinner without changing its dimensions. */
328
+ busy?: boolean;
329
+ /** Announced status while busy; defaults to “Working”. */
330
+ busyLabel?: string;
324
331
  /**
325
332
  * Avatar image URL. A single-control group paints it on the group; a
326
333
  * multi-control group paints it only on the pressed selection highlight.
@@ -329,7 +336,7 @@ interface ToolbarControlGroupProps {
329
336
  /** Native named-slot assignment when composed inside a web component. */
330
337
  slot?: string;
331
338
  }
332
- declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, buttonAppearance, shape, size, density, content, focusRing, selectedChrome, selectedTone, nestedDropdown, menuInset, overflow, visibility, relocateOnCollapse, scrim, avatarImage, slot, }: ToolbarControlGroupProps): kerfjs.SafeHtml;
339
+ declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, buttonAppearance, shape, size, density, content, focusRing, selectedChrome, selectedTone, nestedDropdown, menuInset, overflow, visibility, relocateOnCollapse, scrim, busy, busyLabel, avatarImage, slot, }: ToolbarControlGroupProps): kerfjs.SafeHtml;
333
340
 
334
341
  export { ToolbarActionLink, type ToolbarActionLinkProps, ToolbarControlGroup, type ToolbarControlGroupAppearance, type ToolbarControlGroupButtonAppearance, type ToolbarControlGroupContent, type ToolbarControlGroupDensity, type ToolbarControlGroupFocusRing, type ToolbarControlGroupMenuInset, type ToolbarControlGroupOverflow, type ToolbarControlGroupProps, type ToolbarControlGroupSelectedChrome, type ToolbarControlGroupSelectedTone, type ToolbarControlGroupShape, type ToolbarControlGroupSize, type ToolbarControlGroupTone, type ToolbarControlGroupVisibility };
335
342
  ```
@@ -413,9 +420,9 @@ interface PopupMenuItem {
413
420
  value?: string;
414
421
  /** Leading icon, typically a `LucideIcon`; it is placed in the item's icon slot. */
415
422
  icon?: SafeHtml;
416
- /** A checked menu choice, including nested choices. */
423
+ /** A checkbox choice, including nested choices; omit for a plain command. */
417
424
  checked?: boolean;
418
- /** Trailing safe content, such as a selected-choice tick. */
425
+ /** Trailing safe content, such as secondary status. */
419
426
  details?: SafeHtml;
420
427
  /** Destructive command styling. */
421
428
  tone?: 'default' | 'danger';
@@ -870,10 +877,22 @@ import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
870
877
  type ContentItemFrame = 'none' | 'framed';
871
878
  /** Corner shape: the 12px rounded rectangle or the 22px pill. */
872
879
  type ContentItemShape = 'rounded' | 'pill';
880
+ /** `single` uses option selection; `toggle` uses a pressed button. */
881
+ type ContentItemSelectionMode = 'none' | 'single' | 'toggle';
873
882
  type ContentItemRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
874
883
  'data-component'?: never;
875
884
  }>;
876
- interface ContentItemProps {
885
+ type ContentItemInteractiveRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
886
+ 'data-component'?: never;
887
+ 'data-action'?: never;
888
+ 'data-item-id'?: never;
889
+ 'data-interactive'?: never;
890
+ 'data-selected'?: never;
891
+ 'data-disabled'?: never;
892
+ 'data-selection-mode'?: never;
893
+ 'data-kui-pressed'?: never;
894
+ }>;
895
+ interface ContentItemBaseProps {
877
896
  /** Item content; a plain string is allowed for bare copy. */
878
897
  children?: KerfUiContent | string;
879
898
  /**
@@ -896,19 +915,38 @@ interface ContentItemProps {
896
915
  */
897
916
  focusTarget?: boolean;
898
917
  className?: string;
899
- /** Safe `data-*` metadata; component-owned structural attributes stay protected. */
900
- rootAttributes?: ContentItemRootAttributes;
901
918
  /** Native named-slot assignment when composed inside a web component. */
902
919
  slot?: string;
903
920
  }
921
+ type ContentItemProps = ContentItemBaseProps & ({
922
+ interactive?: false;
923
+ action?: never;
924
+ itemId?: never;
925
+ selectionMode?: never;
926
+ selected?: never;
927
+ disabled?: never;
928
+ /** Existing static `data-*` metadata remains available. */
929
+ rootAttributes?: ContentItemRootAttributes;
930
+ } | {
931
+ /** Enable a keyboard reachable card; wire `wireContentItems` once on its containing root. */
932
+ interactive: true;
933
+ /** Delegated action dispatched by pointer, Enter, or Space. */
934
+ action: string;
935
+ itemId?: string;
936
+ selectionMode?: ContentItemSelectionMode;
937
+ selected?: boolean;
938
+ disabled?: boolean;
939
+ /** Safe app metadata; interaction attributes are component-owned. */
940
+ rootAttributes?: ContentItemInteractiveRootAttributes;
941
+ });
904
942
  /**
905
943
  * One self-contained `.kui-content` child: an 8px inline margin, a real 1px
906
944
  * border (transparent unless `framed`), 8px padding, and a rounded or pill
907
945
  * radius. It owns that whole geometry, so wrappers must not add more.
908
946
  */
909
- declare function ContentItem({ children, frame, shape, ariaLabel, focusTarget, className, rootAttributes, slot, }: ContentItemProps): kerfjs.SafeHtml;
947
+ declare function ContentItem({ children, frame, shape, ariaLabel, focusTarget, interactive, action, itemId, selectionMode, selected, disabled, className, rootAttributes, slot, }: ContentItemProps): kerfjs.SafeHtml;
910
948
 
911
- export { ContentItem, type ContentItemFrame, type ContentItemProps, type ContentItemShape };
949
+ export { ContentItem, type ContentItemFrame, type ContentItemProps, type ContentItemSelectionMode, type ContentItemShape };
912
950
  ```
913
951
 
914
952
  ## `@kerfjs/ui/value-table`
@@ -1428,7 +1466,8 @@ interface PaneProps {
1428
1466
  chromePlacement?: PaneChromePlacement;
1429
1467
  /**
1430
1468
  * The divider under the header and over the footer, where they meet the
1431
- * scrolling content. `scroll` (default) shows the header's divider only
1469
+ * scrolling content. Omitted defaults to `scroll` for a plain pane and
1470
+ * `always` for `appearance="sunken"`. `scroll` shows the header's divider only
1432
1471
  * while the content is scrolled down, and the footer's only while more
1433
1472
  * content lies below — never when the content fits — once
1434
1473
  * `wireScrollDividers` (`@kerfjs/ui/wire-scroll-dividers`) is wired above
@@ -1492,7 +1531,7 @@ import { ListConfig } from './list.js';
1492
1531
  import { PaneConfig } from './pane.js';
1493
1532
  import { ResizableRegionSeparator, ResizableRegionCollapseMotion, ResizableRegionContentOverflow, ResizableRegionPresentation, ResizableRegionRestorePosition } from './resizable-region.js';
1494
1533
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
1495
- import { a as PanelToolbar, b as PanelToggle } from './panel-toolbar-DqwtBxQL.js';
1534
+ import { a as PanelToolbar, b as PanelChromePlacement, c as PanelBottomToolbar, d as PanelToggle } from './panel-toolbar-DDKh4uKd.js';
1496
1535
  import { ToolbarConfig } from './toolbar.js';
1497
1536
  import './css-values.js';
1498
1537
  import './flex-alignment-4ms8ZbV8.js';
@@ -1511,6 +1550,7 @@ type WorkbenchPanelToggle = PanelToggle;
1511
1550
  * `FloatingToolbar` in the work area's bottom-end corner.
1512
1551
  */
1513
1552
  type WorkbenchPanelToolbar = PanelToolbar;
1553
+ type WorkbenchPanelBottomToolbar = PanelBottomToolbar;
1514
1554
  /**
1515
1555
  * The work area's top toolbar; collapsed rails add their groups to it. Its
1516
1556
  * configuration forwards to its `Toolbar`. It draws no divider of its own by
@@ -1546,7 +1586,7 @@ interface WorkbenchMainBottomToolbar extends ToolbarConfig {
1546
1586
  * the Pane's `chromePlacement="auto"`; it applies to the pinned header and
1547
1587
  * footer together).
1548
1588
  */
1549
- type WorkbenchChromePlacement = 'fixed' | 'scroll' | 'auto';
1589
+ type WorkbenchChromePlacement = PanelChromePlacement;
1550
1590
 
1551
1591
  /**
1552
1592
  * The Workbench container breakpoint below which a panel presents as an
@@ -1554,7 +1594,7 @@ type WorkbenchChromePlacement = 'fixed' | 'scroll' | 'auto';
1554
1594
  * breakpoints as `ResizableRegion`'s `responsiveFillAt` — or `never` to keep
1555
1595
  * it inline at every width.
1556
1596
  */
1557
- type WorkbenchResponsiveOverlayAt = 'compact' | 'narrow' | 'never';
1597
+ type WorkbenchResponsiveOverlayAt = 'compact' | 'narrow' | 'never' | number;
1558
1598
  /**
1559
1599
  * How wide a rail's overlay is in a compact (448px or less) Workbench: `inset`
1560
1600
  * fills the Workbench less a dismiss margin on the side away from the rail's
@@ -1577,8 +1617,20 @@ interface WorkbenchPanel {
1577
1617
  * collapsed. With it, `content` renders in a `Pane` below the toolbar.
1578
1618
  */
1579
1619
  toolbar?: WorkbenchPanelToolbar;
1580
- /** Optional bottom toolbar under a `toolbar` panel's content. */
1620
+ /** Fixed content below a toolbar panel's top toolbar, above its scroll region. */
1621
+ header?: KerfUiContent;
1622
+ /** List layout for `header`; omitted fields keep List defaults. */
1623
+ headerList?: ListConfig;
1624
+ /** Placement of the top toolbar and header together; default `fixed`. */
1625
+ headerPlacement?: WorkbenchChromePlacement;
1626
+ /** Fixed content above a toolbar panel's bottom toolbar. */
1581
1627
  footer?: KerfUiContent;
1628
+ /** List layout for `footer`; omitted fields keep List defaults. */
1629
+ footerList?: ListConfig;
1630
+ /** Fixed toolbar below `footer`, using footer semantics. */
1631
+ bottomToolbar?: WorkbenchPanelBottomToolbar;
1632
+ /** Placement of the footer and bottom toolbar together; default `fixed`. */
1633
+ footerPlacement?: WorkbenchChromePlacement;
1582
1634
  /**
1583
1635
  * Configuration for a `toolbar` panel's `Pane` (`contentElement`,
1584
1636
  * `contentLabel`, `separators`, `safeAreaEdges`, `chromeDividers`) — for example
@@ -1610,8 +1662,9 @@ interface WorkbenchPanel {
1610
1662
  presentation?: ResizableRegionPresentation;
1611
1663
  /**
1612
1664
  * Present the panel as an overlay, without a separator, below a Workbench
1613
- * container breakpoint, and inline above it — the CSS decides, so the app
1614
- * needs no device-class check. A rail overlays from its side at full
1665
+ * container breakpoint, and inline above it. `compact` and `narrow` use
1666
+ * CSS container queries; a positive number is a pixel threshold measured
1667
+ * by `wireWorkbench` and requires a `collapsed` signal. A rail overlays from its side at full
1615
1668
  * height, over the work area and an open drawer; the bottom drawer
1616
1669
  * overlays the bottom of the work-area column. Rails default to `narrow`
1617
1670
  * (pass `never` to keep one inline); the drawer defaults to inline.
@@ -1711,6 +1764,8 @@ interface WorkbenchProps {
1711
1764
  * shorter. Workbenches without a drawer ignore it.
1712
1765
  */
1713
1766
  mainMinHeight?: number;
1767
+ /** Dim the work area below any open overlay and absorb outside presses; off by default. */
1768
+ overlayBackdrop?: boolean;
1714
1769
  className?: string;
1715
1770
  /** Native named-slot assignment when composed inside a web component. */
1716
1771
  slot?: string;
@@ -1728,9 +1783,9 @@ interface WorkbenchProps {
1728
1783
  * lives outside it and stays reachable). A panel may opt in to drag and keyboard resizing with
1729
1784
  * `resizable`, which `wireWorkbench` drives. See `docs/23-app-layouts.md` §3.3.
1730
1785
  */
1731
- declare function Workbench({ id, label, main, leftRail, rightRail, bottomDrawer, mainToolbar, mainHeader, mainFooter, mainBottomToolbar, mainHeaderPlacement, mainFooterPlacement, mainPane, mainHeaderList, mainFooterList, mainMinSize, mainMinHeight, className, slot, }: WorkbenchProps): SafeHtml;
1786
+ declare function Workbench({ id, label, main, leftRail, rightRail, bottomDrawer, mainToolbar, mainHeader, mainFooter, mainBottomToolbar, mainHeaderPlacement, mainFooterPlacement, mainPane, mainHeaderList, mainFooterList, mainMinSize, mainMinHeight, overlayBackdrop, className, slot, }: WorkbenchProps): SafeHtml;
1732
1787
 
1733
- export { Workbench, type WorkbenchChromePlacement, type WorkbenchCompactOverlay, type WorkbenchMainBottomToolbar, type WorkbenchMainToolbar, type WorkbenchPanel, type WorkbenchPanelResizable, type WorkbenchPanelToggle, type WorkbenchPanelToolbar, type WorkbenchProps, type WorkbenchResponsiveOverlayAt };
1788
+ export { Workbench, type WorkbenchChromePlacement, type WorkbenchCompactOverlay, type WorkbenchMainBottomToolbar, type WorkbenchMainToolbar, type WorkbenchPanel, type WorkbenchPanelBottomToolbar, type WorkbenchPanelResizable, type WorkbenchPanelToggle, type WorkbenchPanelToolbar, type WorkbenchProps, type WorkbenchResponsiveOverlayAt };
1734
1789
  ```
1735
1790
 
1736
1791
  ## `@kerfjs/ui/wire-workbench`
@@ -1770,6 +1825,13 @@ interface WireWorkbenchPanel {
1770
1825
  * keeps Tab inside it, and it closes on Escape or a press outside it.
1771
1826
  */
1772
1827
  collapsed?: Signal<boolean>;
1828
+ /**
1829
+ * Treat presses in a portal surface launched by this panel (for example a
1830
+ * body-level menu or dialog) as inside it. The predicate receives each Node
1831
+ * in the press's composed path; return true for the portal root. Ordinary
1832
+ * presses outside the panel and its allowed surfaces still dismiss it.
1833
+ */
1834
+ keepOpenOn?: (target: Node) => boolean;
1773
1835
  }
1774
1836
  /** A resize the user made, after `wireWorkbench` wrote it to the size signal. */
1775
1837
  interface WorkbenchResize {
@@ -1851,16 +1913,18 @@ export { type WireWorkbenchOptions, type WireWorkbenchPanel, type WorkbenchPanel
1851
1913
 
1852
1914
  ```ts
1853
1915
  import { SafeHtml } from 'kerfjs';
1916
+ import { ListConfig } from './list.js';
1854
1917
  import { PaneConfig } from './pane.js';
1855
- import { P as PanelSide, a as PanelToolbar, b as PanelToggle } from './panel-toolbar-DqwtBxQL.js';
1856
- export { c as collapsiblePanelToggleIcon } from './panel-toolbar-DqwtBxQL.js';
1918
+ import { P as PanelSide, a as PanelToolbar, b as PanelChromePlacement, c as PanelBottomToolbar, d as PanelToggle } from './panel-toolbar-DDKh4uKd.js';
1919
+ export { e as collapsiblePanelToggleIcon } from './panel-toolbar-DDKh4uKd.js';
1857
1920
  import { ResizableRegionSeparator, ResizableRegionCollapseMotion, ResizableRegionContentOverflow, ResizableRegionPresentation, ResizableRegionRestorePosition } from './resizable-region.js';
1858
1921
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
1922
+ import './css-values.js';
1923
+ import './flex-alignment-4ms8ZbV8.js';
1924
+ import './sides-BPSWde0A.js';
1859
1925
  import './lucide-icon.js';
1860
1926
  import 'lucide';
1861
1927
  import './toolbar.js';
1862
- import './sides-BPSWde0A.js';
1863
- import './css-values.js';
1864
1928
 
1865
1929
  /** Which edge a {@link CollapsiblePanel} docks to. */
1866
1930
  type CollapsiblePanelSide = PanelSide;
@@ -1873,6 +1937,8 @@ type CollapsiblePanelToolbarToggle = PanelToggle;
1873
1937
  * {@link CollapsiblePanelRelocated} while it is collapsed.
1874
1938
  */
1875
1939
  type CollapsiblePanelToolbar = PanelToolbar;
1940
+ type CollapsiblePanelBottomToolbar = PanelBottomToolbar;
1941
+ type CollapsiblePanelChromePlacement = PanelChromePlacement;
1876
1942
  interface CollapsiblePanelToggleProps {
1877
1943
  /** The panel this toggle controls. */
1878
1944
  side: CollapsiblePanelSide;
@@ -1916,8 +1982,15 @@ interface CollapsiblePanelProps {
1916
1982
  * marked groups and toggle stay reachable while the panel is collapsed.
1917
1983
  */
1918
1984
  toolbar?: CollapsiblePanelToolbar;
1919
- /** Optional bottom toolbar under a `toolbar` panel's content. */
1985
+ /** Fixed content below a toolbar panel's top toolbar. */
1986
+ header?: KerfUiContent;
1987
+ headerList?: ListConfig;
1988
+ headerPlacement?: CollapsiblePanelChromePlacement;
1989
+ /** Fixed content above a toolbar panel's bottom toolbar. */
1920
1990
  footer?: KerfUiContent;
1991
+ footerList?: ListConfig;
1992
+ bottomToolbar?: CollapsiblePanelBottomToolbar;
1993
+ footerPlacement?: CollapsiblePanelChromePlacement;
1921
1994
  /**
1922
1995
  * Configuration for a `toolbar` panel's `Pane` (`contentElement`,
1923
1996
  * `contentLabel`, `separators`, `safeAreaEdges`, `chromeDividers`) — for example
@@ -1951,7 +2024,7 @@ interface CollapsiblePanelProps {
1951
2024
  * and persistence semantics, and with `CollapsiblePanelToggle` for the standard
1952
2025
  * affordance. See `ui/docs/collapsible-panel.md` and `docs/23-app-layouts.md`.
1953
2026
  */
1954
- declare function CollapsiblePanel({ id, side, collapsed, size, label, children, toolbar, footer, pane, separator, collapseMotion, contentOverflow, presentation, restoreControl, restorePosition, className, }: CollapsiblePanelProps): SafeHtml;
2027
+ declare function CollapsiblePanel({ id, side, collapsed, size, label, children, toolbar, header, headerList, headerPlacement, footer, footerList, bottomToolbar, footerPlacement, pane, separator, collapseMotion, contentOverflow, presentation, restoreControl, restorePosition, className, }: CollapsiblePanelProps): SafeHtml;
1955
2028
  interface CollapsiblePanelRelocatedProps {
1956
2029
  /** The panel's `id`. */
1957
2030
  panelId: string;
@@ -1971,7 +2044,7 @@ interface CollapsiblePanelRelocatedProps {
1971
2044
  */
1972
2045
  declare function CollapsiblePanelRelocated({ panelId, side, collapsed, toolbar, }: CollapsiblePanelRelocatedProps): SafeHtml;
1973
2046
 
1974
- export { CollapsiblePanel, type CollapsiblePanelProps, CollapsiblePanelRelocated, type CollapsiblePanelRelocatedProps, type CollapsiblePanelSide, CollapsiblePanelToggle, type CollapsiblePanelToggleProps, type CollapsiblePanelToolbar, type CollapsiblePanelToolbarToggle };
2047
+ export { CollapsiblePanel, type CollapsiblePanelBottomToolbar, type CollapsiblePanelChromePlacement, type CollapsiblePanelProps, CollapsiblePanelRelocated, type CollapsiblePanelRelocatedProps, type CollapsiblePanelSide, CollapsiblePanelToggle, type CollapsiblePanelToggleProps, type CollapsiblePanelToolbar, type CollapsiblePanelToolbarToggle };
1975
2048
  ```
1976
2049
 
1977
2050
  ## `@kerfjs/ui/wire-sidebar`
@@ -2304,7 +2377,7 @@ import './list.js';
2304
2377
  import './css-values.js';
2305
2378
  import './flex-alignment-4ms8ZbV8.js';
2306
2379
  import './resizable-region.js';
2307
- import './panel-toolbar-DqwtBxQL.js';
2380
+ import './panel-toolbar-DDKh4uKd.js';
2308
2381
  import './lucide-icon.js';
2309
2382
  import 'lucide';
2310
2383
 
@@ -2397,7 +2470,7 @@ import './list.js';
2397
2470
  import './css-values.js';
2398
2471
  import './flex-alignment-4ms8ZbV8.js';
2399
2472
  import './resizable-region.js';
2400
- import './panel-toolbar-DqwtBxQL.js';
2473
+ import './panel-toolbar-DDKh4uKd.js';
2401
2474
  import './lucide-icon.js';
2402
2475
  import 'lucide';
2403
2476
 
@@ -2799,6 +2872,7 @@ export { Skeleton, type SkeletonProps };
2799
2872
 
2800
2873
  ```ts
2801
2874
  import * as kerfjs from 'kerfjs';
2875
+ import { CssFlexKeyword, CssFlex } from './css-values.js';
2802
2876
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
2803
2877
 
2804
2878
  type SunkenPanelShape = 'rounded' | 'square';
@@ -2808,6 +2882,10 @@ interface SunkenPanelProps {
2808
2882
  ariaLabel?: string;
2809
2883
  /** Corner shape: a rounded rectangle (default) or square corners. */
2810
2884
  shape?: SunkenPanelShape;
2885
+ /** Grow or shrink within a flex parent, using Grid's typed flex contract. */
2886
+ flex?: boolean | CssFlexKeyword | CssFlex;
2887
+ /** Fill a parent with a definite height; use flex inside a flex layout. */
2888
+ fill?: boolean;
2811
2889
  className?: string;
2812
2890
  /** Native named-slot assignment when composed inside a web component. */
2813
2891
  slot?: string;
@@ -2817,7 +2895,7 @@ interface SunkenPanelProps {
2817
2895
  * stack. The panel owns its background and padding; children own their own
2818
2896
  * borders and internal geometry.
2819
2897
  */
2820
- declare function SunkenPanel({ children, ariaLabel, shape, className, slot, }: SunkenPanelProps): kerfjs.SafeHtml;
2898
+ declare function SunkenPanel({ children, ariaLabel, shape, flex, fill, className, slot, }: SunkenPanelProps): kerfjs.SafeHtml;
2821
2899
 
2822
2900
  export { SunkenPanel, type SunkenPanelProps, type SunkenPanelShape };
2823
2901
  ```
@@ -3091,8 +3169,8 @@ import { SafeHtml } from 'kerfjs';
3091
3169
  import { BadgeTone, BadgeAppearance, BadgeShape, BadgeSize } from './badge.js';
3092
3170
 
3093
3171
  interface ChipCommonProps {
3094
- /** Visible, non-interactive chip content. */
3095
- children: SafeHtml | string | number;
3172
+ /** Decorative leading icon, normally an unsized LucideIcon. */
3173
+ icon?: SafeHtml;
3096
3174
  tone?: BadgeTone;
3097
3175
  appearance?: BadgeAppearance;
3098
3176
  shape?: BadgeShape;
@@ -3106,6 +3184,12 @@ interface ChipCommonProps {
3106
3184
  }
3107
3185
  /** A removable chip needs both a delegated action and a specific accessible name. */
3108
3186
  type ChipProps = ChipCommonProps & ({
3187
+ children: SafeHtml | string | number;
3188
+ truncate?: false;
3189
+ } | {
3190
+ children: string;
3191
+ truncate: true;
3192
+ }) & ({
3109
3193
  removeAction: string;
3110
3194
  removeLabel: string;
3111
3195
  } | {
@@ -3113,7 +3197,7 @@ type ChipProps = ChipCommonProps & ({
3113
3197
  removeLabel?: never;
3114
3198
  });
3115
3199
  /** A short label with an optional native remove button. The application owns removal. */
3116
- declare function Chip({ children, tone, appearance, shape, size, disabled, itemId, className, slot, ...remove }: ChipProps): SafeHtml;
3200
+ declare function Chip({ children, icon, truncate, tone, appearance, shape, size, disabled, itemId, className, slot, ...remove }: ChipProps): SafeHtml;
3117
3201
 
3118
3202
  export { Chip, type ChipProps };
3119
3203
  ```
@@ -3125,18 +3209,21 @@ import * as kerfjs from 'kerfjs';
3125
3209
  import { IconNode } from 'lucide';
3126
3210
 
3127
3211
  type LucideNode = IconNode;
3212
+ type LucideIconSize = 'xs' | 's' | 'm' | 'l' | 'xl' | number;
3128
3213
  interface LucideIconProps {
3129
3214
  icon: LucideNode;
3130
3215
  name: string;
3131
3216
  className?: string;
3132
3217
  label?: string;
3218
+ /** Named icon scale or positive pixel size, converted to rem. Omit for 1em. */
3219
+ size?: LucideIconSize;
3133
3220
  /** Native named-slot assignment when composed inside a web component. */
3134
3221
  slot?: string;
3135
3222
  }
3136
3223
  /** Render a Lucide-compatible icon node without copying icon SVG strings. */
3137
- declare function LucideIcon({ icon, name, className, label, slot, }: LucideIconProps): kerfjs.SafeHtml;
3224
+ declare function LucideIcon({ icon, name, className, label, size, slot, }: LucideIconProps): kerfjs.SafeHtml;
3138
3225
 
3139
- export { LucideIcon, type LucideIconProps, type LucideNode };
3226
+ export { LucideIcon, type LucideIconProps, type LucideIconSize, type LucideNode };
3140
3227
  ```
3141
3228
 
3142
3229
  ## `@kerfjs/ui/surface-scaffold`
@@ -3187,8 +3274,9 @@ type TextSize = 'compact' | 'default' | 'large' | 'xlarge';
3187
3274
  type TextFont = 'default' | 'monospace';
3188
3275
  type TextBorder = 'transparent' | 'none';
3189
3276
  type TextLineHeight = 'default' | 'tight';
3277
+ type TextWrap = 'normal' | 'anywhere' | 'nowrap' | 'truncate';
3190
3278
  type TextContent = KerfUiContent | string | number | readonly TextContent[];
3191
- type TextProps = Omit<KerfBaseAttrs, 'children' | 'class' | 'className'> & {
3279
+ type TextCommonProps = Omit<KerfBaseAttrs, 'children' | 'class' | 'className'> & {
3192
3280
  /** Native heading, paragraph, or inline span element to render. Defaults to `p`. */
3193
3281
  variant?: TextVariant;
3194
3282
  /** Semantic foreground treatment. Defaults to the inherited foreground. */
@@ -3207,14 +3295,24 @@ type TextProps = Omit<KerfBaseAttrs, 'children' | 'class' | 'className'> & {
3207
3295
  class?: string;
3208
3296
  className?: string;
3209
3297
  };
3298
+ type TextProps = TextCommonProps & ({
3299
+ /** Wrap normally or break long unbroken strings. Defaults to normal. */
3300
+ wrap?: 'normal' | 'anywhere';
3301
+ /** Cap wrapped text to this positive number of lines. */
3302
+ maxLines?: number;
3303
+ } | {
3304
+ /** Keep one line, with or without an ellipsis. */
3305
+ wrap: 'nowrap' | 'truncate';
3306
+ maxLines?: never;
3307
+ });
3210
3308
  /**
3211
3309
  * Semantic heading, paragraph, or inline text. Block variants use the standard
3212
3310
  * content-item padding; `span` adds no box geometry.
3213
3311
  * All ordinary native heading/paragraph attributes pass through to the element.
3214
3312
  */
3215
- declare function Text({ variant: Variant, tone, size, font, border, flush, lineHeight, children, class: classValue, className, ...attributes }: TextProps): kerfjs.SafeHtml;
3313
+ declare function Text({ variant: Variant, tone, size, font, border, flush, lineHeight, wrap, maxLines, children, class: classValue, className, ...attributes }: TextProps): kerfjs.SafeHtml;
3216
3314
 
3217
- export { Text, type TextBorder, type TextContent, type TextFont, type TextLineHeight, type TextProps, type TextSize, type TextTone, type TextVariant };
3315
+ export { Text, type TextBorder, type TextContent, type TextFont, type TextLineHeight, type TextProps, type TextSize, type TextTone, type TextVariant, type TextWrap };
3218
3316
  ```
3219
3317
 
3220
3318
  ## `@kerfjs/ui/row`