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

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 (169) hide show
  1. package/README.md +4 -0
  2. package/ai/component-catalog-extension.schema.json +13 -0
  3. package/ai/component-catalog.json +13 -2
  4. package/ai/component-composition.json +15 -2
  5. package/ai/components/list-item.md +1 -1
  6. package/ai/components/workbench.md +4 -2
  7. package/ai/public-api-signatures-v1.md +151 -44
  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 +2 -2
  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-UCKKT6KO.js → chunk-2EKHENQK.js} +7 -1
  27. package/dist/chunk-2EKHENQK.js.map +1 -0
  28. package/dist/{chunk-OD2VXAPL.js → chunk-3BYFWTP3.js} +4 -3
  29. package/dist/chunk-3BYFWTP3.js.map +1 -0
  30. package/dist/{chunk-5Q3N6EV7.js → chunk-5IJ6UGNZ.js} +3 -3
  31. package/dist/{chunk-5Q3N6EV7.js.map → chunk-5IJ6UGNZ.js.map} +1 -1
  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-VCBTX62E.js → chunk-J3KGJ6P6.js} +2 -2
  47. package/dist/chunk-J3KGJ6P6.js.map +1 -0
  48. package/dist/{chunk-X6ADHJNI.js → chunk-KFYANKJI.js} +25 -6
  49. package/dist/chunk-KFYANKJI.js.map +1 -0
  50. package/dist/{chunk-A3CKOW2R.js → chunk-M5H2RMCH.js} +165 -26
  51. package/dist/chunk-M5H2RMCH.js.map +1 -0
  52. package/dist/chunk-MOSIE4Z2.js +51 -0
  53. package/dist/chunk-MOSIE4Z2.js.map +1 -0
  54. package/dist/{chunk-RRB26JRJ.js → chunk-NSVLUDUW.js} +19 -4
  55. package/dist/chunk-NSVLUDUW.js.map +1 -0
  56. package/dist/{chunk-7JUBXOIV.js → chunk-NXWE5S57.js} +25 -6
  57. package/dist/chunk-NXWE5S57.js.map +1 -0
  58. package/dist/chunk-RGS4WX2M.js +44 -0
  59. package/dist/chunk-RGS4WX2M.js.map +1 -0
  60. package/dist/chunk-SH6F3CCG.js +80 -0
  61. package/dist/chunk-SH6F3CCG.js.map +1 -0
  62. package/dist/{chunk-EAC4CDY7.js → chunk-SMZGAPCU.js} +15 -2
  63. package/dist/chunk-SMZGAPCU.js.map +1 -0
  64. package/dist/{chunk-NNMLEDMD.js → chunk-TJK44RQC.js} +64 -11
  65. package/dist/chunk-TJK44RQC.js.map +1 -0
  66. package/dist/{chunk-6ZXOQEAN.js → chunk-WF75U3V4.js} +7 -1
  67. package/dist/chunk-WF75U3V4.js.map +1 -0
  68. package/dist/collapsible-panel.d.ts +18 -7
  69. package/dist/collapsible-panel.js +19 -3
  70. package/dist/collapsible-panel.js.map +1 -1
  71. package/dist/content-item.d.ts +40 -5
  72. package/dist/content-item.js +1 -1
  73. package/dist/disclosure-arrow.js +2 -1
  74. package/dist/grid.d.ts +5 -1
  75. package/dist/grid.js +1 -1
  76. package/dist/index.d.ts +3 -3
  77. package/dist/index.js +20 -20
  78. package/dist/list-action-row.js +1 -1
  79. package/dist/list-header.js +1 -1
  80. package/dist/list-item.js +1 -1
  81. package/dist/lucide-icon.d.ts +5 -2
  82. package/dist/lucide-icon.js +2 -1
  83. package/dist/nav-stack.js +2 -1
  84. package/dist/pane.d.ts +2 -1
  85. package/dist/pane.js +1 -1
  86. package/dist/{panel-toolbar-DqwtBxQL.d.ts → panel-toolbar-DDKh4uKd.d.ts} +11 -2
  87. package/dist/popup-menu-register.js +216 -3
  88. package/dist/popup-menu-register.js.map +1 -1
  89. package/dist/popup-menu.d.ts +4 -3
  90. package/dist/popup-menu.js +1 -1
  91. package/dist/select.js +1 -1
  92. package/dist/split-view.js +2 -1
  93. package/dist/split-view.js.map +1 -1
  94. package/dist/styles/catalog/components/catalog-example.css +4 -0
  95. package/dist/styles/chip.css +14 -0
  96. package/dist/styles/content-item.css +45 -0
  97. package/dist/styles/grid.css +7 -0
  98. package/dist/styles/list-action-row.css +4 -3
  99. package/dist/styles/list-header.css +4 -3
  100. package/dist/styles/list-item.css +21 -11
  101. package/dist/styles/lucide-icon.css +5 -0
  102. package/dist/styles/pane.css +3 -2
  103. package/dist/styles/popup-menu.css +24 -10
  104. package/dist/styles/segmented-control.css +3 -0
  105. package/dist/styles/select.css +11 -0
  106. package/dist/styles/sunken-panel.css +7 -0
  107. package/dist/styles/text.css +29 -0
  108. package/dist/styles/token-search-field.css +51 -11
  109. package/dist/styles/toolbar-control-group.css +49 -0
  110. package/dist/styles/workbench.css +130 -2
  111. package/dist/sunken-panel.d.ts +6 -1
  112. package/dist/sunken-panel.js +1 -1
  113. package/dist/text.d.ts +14 -3
  114. package/dist/text.js +1 -1
  115. package/dist/{token-search-field-DvgFLhLL.d.ts → token-search-field-Xk8jiw8Y.d.ts} +18 -4
  116. package/dist/token-search-field.d.ts +1 -1
  117. package/dist/token-search-field.js +2 -1
  118. package/dist/token-search-model.d.ts +1 -1
  119. package/dist/toolbar-control-group.d.ts +5 -1
  120. package/dist/toolbar-control-group.js +2 -1
  121. package/dist/toolbar.d.ts +5 -2
  122. package/dist/toolbar.js +1 -1
  123. package/dist/wire-catalog.js +1 -1
  124. package/dist/wire-content-items.d.ts +9 -0
  125. package/dist/wire-content-items.js +66 -0
  126. package/dist/wire-content-items.js.map +1 -0
  127. package/dist/wire-token-search-fields.d.ts +1 -1
  128. package/dist/wire-token-search-fields.js +2 -1
  129. package/dist/wire-workbench.d.ts +7 -0
  130. package/dist/wire-workbench.js +1 -1
  131. package/dist/workbench.d.ts +24 -8
  132. package/dist/workbench.js +2 -1
  133. package/docs/accessibility.md +30 -6
  134. package/docs/catalog.md +42 -2
  135. package/docs/collapsible-panel.md +8 -1
  136. package/docs/component-contract.md +43 -5
  137. package/docs/component-selection.md +46 -8
  138. package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -1
  139. package/docs/design/templates/toolbar/title-and-actions.svg +1 -1
  140. package/docs/design/templates/toolbar-dark.svg +1 -1
  141. package/docs/design/templates/toolbar.svg +1 -1
  142. package/docs/examples/component-catalog-extension.json +6 -0
  143. package/docs/layout.md +56 -9
  144. package/docs/sunken-panel.md +22 -0
  145. package/docs/surface-scaffold.md +6 -3
  146. package/docs/ui-analyzer.md +4 -0
  147. package/docs/ux-demo.md +1 -0
  148. package/docs/workbench.md +42 -4
  149. package/llms.txt +9 -5
  150. package/package.json +16 -2
  151. package/scripts/component-catalog-extension-validation.mjs +28 -0
  152. package/dist/chunk-4R777DUZ.js +0 -34
  153. package/dist/chunk-4R777DUZ.js.map +0 -1
  154. package/dist/chunk-6ZXOQEAN.js.map +0 -1
  155. package/dist/chunk-7JUBXOIV.js.map +0 -1
  156. package/dist/chunk-A3CKOW2R.js.map +0 -1
  157. package/dist/chunk-AUKT3KMG.js.map +0 -1
  158. package/dist/chunk-EAC4CDY7.js.map +0 -1
  159. package/dist/chunk-ENGVYQPG.js.map +0 -1
  160. package/dist/chunk-MA73TA6D.js +0 -42
  161. package/dist/chunk-MA73TA6D.js.map +0 -1
  162. package/dist/chunk-N2DRU35S.js +0 -45
  163. package/dist/chunk-N2DRU35S.js.map +0 -1
  164. package/dist/chunk-NNMLEDMD.js.map +0 -1
  165. package/dist/chunk-OD2VXAPL.js.map +0 -1
  166. package/dist/chunk-RRB26JRJ.js.map +0 -1
  167. package/dist/chunk-UCKKT6KO.js.map +0 -1
  168. package/dist/chunk-VCBTX62E.js.map +0 -1
  169. package/dist/chunk-X6ADHJNI.js.map +0 -1
@@ -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.64` and `kerfjs@5.0.0-beta.64`. 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';
@@ -487,7 +494,8 @@ declare function closePopupMenu(menu: PopupMenuElement): void;
487
494
  * `nestedDropdown`) or a `PopupSurface` sizes and insets it as usual. Items
488
495
  * dispatch through delegated `data-action`s; the app owns the commands and any
489
496
  * open-state reaction. Import `@kerfjs/ui/popup-menu/register` once to register
490
- * the Web Awesome elements.
497
+ * the Web Awesome elements. At viewport widths up to 480px, submenus appear
498
+ * above or below their parent menu so their rows do not cover the parent list.
491
499
  */
492
500
  declare function PopupMenu({ text, label, icon, items, placement, caret, disabled, rootAttributes, slot, context, }: PopupMenuProps): SafeHtml;
493
501
 
@@ -870,10 +878,22 @@ import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
870
878
  type ContentItemFrame = 'none' | 'framed';
871
879
  /** Corner shape: the 12px rounded rectangle or the 22px pill. */
872
880
  type ContentItemShape = 'rounded' | 'pill';
881
+ /** `single` uses option selection; `toggle` uses a pressed button. */
882
+ type ContentItemSelectionMode = 'none' | 'single' | 'toggle';
873
883
  type ContentItemRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
874
884
  'data-component'?: never;
875
885
  }>;
876
- interface ContentItemProps {
886
+ type ContentItemInteractiveRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
887
+ 'data-component'?: never;
888
+ 'data-action'?: never;
889
+ 'data-item-id'?: never;
890
+ 'data-interactive'?: never;
891
+ 'data-selected'?: never;
892
+ 'data-disabled'?: never;
893
+ 'data-selection-mode'?: never;
894
+ 'data-kui-pressed'?: never;
895
+ }>;
896
+ interface ContentItemBaseProps {
877
897
  /** Item content; a plain string is allowed for bare copy. */
878
898
  children?: KerfUiContent | string;
879
899
  /**
@@ -882,8 +902,12 @@ interface ContentItemProps {
882
902
  * marks a real distinction. Defaults to `none` (transparent border).
883
903
  */
884
904
  frame?: ContentItemFrame;
905
+ /** Remove block padding and block borders while retaining inline geometry. */
906
+ flush?: boolean;
885
907
  /** Corner shape. Defaults to `rounded`. */
886
908
  shape?: ContentItemShape;
909
+ /** Native hover tooltip. */
910
+ title?: string;
887
911
  /**
888
912
  * Names the item as a distinct region (`role="region"`). Omit it for an
889
913
  * ordinary item, which stays a non-landmark grouping.
@@ -896,19 +920,38 @@ interface ContentItemProps {
896
920
  */
897
921
  focusTarget?: boolean;
898
922
  className?: string;
899
- /** Safe `data-*` metadata; component-owned structural attributes stay protected. */
900
- rootAttributes?: ContentItemRootAttributes;
901
923
  /** Native named-slot assignment when composed inside a web component. */
902
924
  slot?: string;
903
925
  }
926
+ type ContentItemProps = ContentItemBaseProps & ({
927
+ interactive?: false;
928
+ action?: never;
929
+ itemId?: never;
930
+ selectionMode?: never;
931
+ selected?: never;
932
+ disabled?: never;
933
+ /** Existing static `data-*` metadata remains available. */
934
+ rootAttributes?: ContentItemRootAttributes;
935
+ } | {
936
+ /** Enable a keyboard reachable card; wire `wireContentItems` once on its containing root. */
937
+ interactive: true;
938
+ /** Delegated action dispatched by pointer, Enter, or Space. */
939
+ action: string;
940
+ itemId?: string;
941
+ selectionMode?: ContentItemSelectionMode;
942
+ selected?: boolean;
943
+ disabled?: boolean;
944
+ /** Safe app metadata; interaction attributes are component-owned. */
945
+ rootAttributes?: ContentItemInteractiveRootAttributes;
946
+ });
904
947
  /**
905
948
  * One self-contained `.kui-content` child: an 8px inline margin, a real 1px
906
949
  * border (transparent unless `framed`), 8px padding, and a rounded or pill
907
950
  * radius. It owns that whole geometry, so wrappers must not add more.
908
951
  */
909
- declare function ContentItem({ children, frame, shape, ariaLabel, focusTarget, className, rootAttributes, slot, }: ContentItemProps): kerfjs.SafeHtml;
952
+ declare function ContentItem({ children, frame, flush, shape, title, ariaLabel, focusTarget, interactive, action, itemId, selectionMode, selected, disabled, className, rootAttributes, slot, }: ContentItemProps): kerfjs.SafeHtml;
910
953
 
911
- export { ContentItem, type ContentItemFrame, type ContentItemProps, type ContentItemShape };
954
+ export { ContentItem, type ContentItemFrame, type ContentItemProps, type ContentItemSelectionMode, type ContentItemShape };
912
955
  ```
913
956
 
914
957
  ## `@kerfjs/ui/value-table`
@@ -1428,7 +1471,8 @@ interface PaneProps {
1428
1471
  chromePlacement?: PaneChromePlacement;
1429
1472
  /**
1430
1473
  * The divider under the header and over the footer, where they meet the
1431
- * scrolling content. `scroll` (default) shows the header's divider only
1474
+ * scrolling content. Omitted defaults to `scroll` for a plain pane and
1475
+ * `always` for `appearance="sunken"`. `scroll` shows the header's divider only
1432
1476
  * while the content is scrolled down, and the footer's only while more
1433
1477
  * content lies below — never when the content fits — once
1434
1478
  * `wireScrollDividers` (`@kerfjs/ui/wire-scroll-dividers`) is wired above
@@ -1492,7 +1536,7 @@ import { ListConfig } from './list.js';
1492
1536
  import { PaneConfig } from './pane.js';
1493
1537
  import { ResizableRegionSeparator, ResizableRegionCollapseMotion, ResizableRegionContentOverflow, ResizableRegionPresentation, ResizableRegionRestorePosition } from './resizable-region.js';
1494
1538
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
1495
- import { a as PanelToolbar, b as PanelToggle } from './panel-toolbar-DqwtBxQL.js';
1539
+ import { a as PanelToolbar, b as PanelChromePlacement, c as PanelBottomToolbar, d as PanelToggle } from './panel-toolbar-DDKh4uKd.js';
1496
1540
  import { ToolbarConfig } from './toolbar.js';
1497
1541
  import './css-values.js';
1498
1542
  import './flex-alignment-4ms8ZbV8.js';
@@ -1511,6 +1555,7 @@ type WorkbenchPanelToggle = PanelToggle;
1511
1555
  * `FloatingToolbar` in the work area's bottom-end corner.
1512
1556
  */
1513
1557
  type WorkbenchPanelToolbar = PanelToolbar;
1558
+ type WorkbenchPanelBottomToolbar = PanelBottomToolbar;
1514
1559
  /**
1515
1560
  * The work area's top toolbar; collapsed rails add their groups to it. Its
1516
1561
  * configuration forwards to its `Toolbar`. It draws no divider of its own by
@@ -1546,7 +1591,7 @@ interface WorkbenchMainBottomToolbar extends ToolbarConfig {
1546
1591
  * the Pane's `chromePlacement="auto"`; it applies to the pinned header and
1547
1592
  * footer together).
1548
1593
  */
1549
- type WorkbenchChromePlacement = 'fixed' | 'scroll' | 'auto';
1594
+ type WorkbenchChromePlacement = PanelChromePlacement;
1550
1595
 
1551
1596
  /**
1552
1597
  * The Workbench container breakpoint below which a panel presents as an
@@ -1554,7 +1599,7 @@ type WorkbenchChromePlacement = 'fixed' | 'scroll' | 'auto';
1554
1599
  * breakpoints as `ResizableRegion`'s `responsiveFillAt` — or `never` to keep
1555
1600
  * it inline at every width.
1556
1601
  */
1557
- type WorkbenchResponsiveOverlayAt = 'compact' | 'narrow' | 'never';
1602
+ type WorkbenchResponsiveOverlayAt = 'compact' | 'narrow' | 'never' | number;
1558
1603
  /**
1559
1604
  * How wide a rail's overlay is in a compact (448px or less) Workbench: `inset`
1560
1605
  * fills the Workbench less a dismiss margin on the side away from the rail's
@@ -1577,8 +1622,20 @@ interface WorkbenchPanel {
1577
1622
  * collapsed. With it, `content` renders in a `Pane` below the toolbar.
1578
1623
  */
1579
1624
  toolbar?: WorkbenchPanelToolbar;
1580
- /** Optional bottom toolbar under a `toolbar` panel's content. */
1625
+ /** Fixed content below a toolbar panel's top toolbar, above its scroll region. */
1626
+ header?: KerfUiContent;
1627
+ /** List layout for `header`; omitted fields keep List defaults. */
1628
+ headerList?: ListConfig;
1629
+ /** Placement of the top toolbar and header together; default `fixed`. */
1630
+ headerPlacement?: WorkbenchChromePlacement;
1631
+ /** Fixed content above a toolbar panel's bottom toolbar. */
1581
1632
  footer?: KerfUiContent;
1633
+ /** List layout for `footer`; omitted fields keep List defaults. */
1634
+ footerList?: ListConfig;
1635
+ /** Fixed toolbar below `footer`, using footer semantics. */
1636
+ bottomToolbar?: WorkbenchPanelBottomToolbar;
1637
+ /** Placement of the footer and bottom toolbar together; default `fixed`. */
1638
+ footerPlacement?: WorkbenchChromePlacement;
1582
1639
  /**
1583
1640
  * Configuration for a `toolbar` panel's `Pane` (`contentElement`,
1584
1641
  * `contentLabel`, `separators`, `safeAreaEdges`, `chromeDividers`) — for example
@@ -1610,8 +1667,9 @@ interface WorkbenchPanel {
1610
1667
  presentation?: ResizableRegionPresentation;
1611
1668
  /**
1612
1669
  * 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
1670
+ * container breakpoint, and inline above it. `compact` and `narrow` use
1671
+ * CSS container queries; a positive number is a pixel threshold measured
1672
+ * by `wireWorkbench` and requires a `collapsed` signal. A rail overlays from its side at full
1615
1673
  * height, over the work area and an open drawer; the bottom drawer
1616
1674
  * overlays the bottom of the work-area column. Rails default to `narrow`
1617
1675
  * (pass `never` to keep one inline); the drawer defaults to inline.
@@ -1711,6 +1769,8 @@ interface WorkbenchProps {
1711
1769
  * shorter. Workbenches without a drawer ignore it.
1712
1770
  */
1713
1771
  mainMinHeight?: number;
1772
+ /** Dim the work area below any open overlay and absorb outside presses; off by default. */
1773
+ overlayBackdrop?: boolean;
1714
1774
  className?: string;
1715
1775
  /** Native named-slot assignment when composed inside a web component. */
1716
1776
  slot?: string;
@@ -1728,9 +1788,9 @@ interface WorkbenchProps {
1728
1788
  * lives outside it and stays reachable). A panel may opt in to drag and keyboard resizing with
1729
1789
  * `resizable`, which `wireWorkbench` drives. See `docs/23-app-layouts.md` §3.3.
1730
1790
  */
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;
1791
+ 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
1792
 
1733
- export { Workbench, type WorkbenchChromePlacement, type WorkbenchCompactOverlay, type WorkbenchMainBottomToolbar, type WorkbenchMainToolbar, type WorkbenchPanel, type WorkbenchPanelResizable, type WorkbenchPanelToggle, type WorkbenchPanelToolbar, type WorkbenchProps, type WorkbenchResponsiveOverlayAt };
1793
+ 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
1794
  ```
1735
1795
 
1736
1796
  ## `@kerfjs/ui/wire-workbench`
@@ -1770,6 +1830,13 @@ interface WireWorkbenchPanel {
1770
1830
  * keeps Tab inside it, and it closes on Escape or a press outside it.
1771
1831
  */
1772
1832
  collapsed?: Signal<boolean>;
1833
+ /**
1834
+ * Treat presses in a portal surface launched by this panel (for example a
1835
+ * body-level menu or dialog) as inside it. The predicate receives each Node
1836
+ * in the press's composed path; return true for the portal root. Ordinary
1837
+ * presses outside the panel and its allowed surfaces still dismiss it.
1838
+ */
1839
+ keepOpenOn?: (target: Node) => boolean;
1773
1840
  }
1774
1841
  /** A resize the user made, after `wireWorkbench` wrote it to the size signal. */
1775
1842
  interface WorkbenchResize {
@@ -1851,16 +1918,18 @@ export { type WireWorkbenchOptions, type WireWorkbenchPanel, type WorkbenchPanel
1851
1918
 
1852
1919
  ```ts
1853
1920
  import { SafeHtml } from 'kerfjs';
1921
+ import { ListConfig } from './list.js';
1854
1922
  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';
1923
+ import { P as PanelSide, a as PanelToolbar, b as PanelChromePlacement, c as PanelBottomToolbar, d as PanelToggle } from './panel-toolbar-DDKh4uKd.js';
1924
+ export { e as collapsiblePanelToggleIcon } from './panel-toolbar-DDKh4uKd.js';
1857
1925
  import { ResizableRegionSeparator, ResizableRegionCollapseMotion, ResizableRegionContentOverflow, ResizableRegionPresentation, ResizableRegionRestorePosition } from './resizable-region.js';
1858
1926
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
1927
+ import './css-values.js';
1928
+ import './flex-alignment-4ms8ZbV8.js';
1929
+ import './sides-BPSWde0A.js';
1859
1930
  import './lucide-icon.js';
1860
1931
  import 'lucide';
1861
1932
  import './toolbar.js';
1862
- import './sides-BPSWde0A.js';
1863
- import './css-values.js';
1864
1933
 
1865
1934
  /** Which edge a {@link CollapsiblePanel} docks to. */
1866
1935
  type CollapsiblePanelSide = PanelSide;
@@ -1873,6 +1942,8 @@ type CollapsiblePanelToolbarToggle = PanelToggle;
1873
1942
  * {@link CollapsiblePanelRelocated} while it is collapsed.
1874
1943
  */
1875
1944
  type CollapsiblePanelToolbar = PanelToolbar;
1945
+ type CollapsiblePanelBottomToolbar = PanelBottomToolbar;
1946
+ type CollapsiblePanelChromePlacement = PanelChromePlacement;
1876
1947
  interface CollapsiblePanelToggleProps {
1877
1948
  /** The panel this toggle controls. */
1878
1949
  side: CollapsiblePanelSide;
@@ -1916,8 +1987,15 @@ interface CollapsiblePanelProps {
1916
1987
  * marked groups and toggle stay reachable while the panel is collapsed.
1917
1988
  */
1918
1989
  toolbar?: CollapsiblePanelToolbar;
1919
- /** Optional bottom toolbar under a `toolbar` panel's content. */
1990
+ /** Fixed content below a toolbar panel's top toolbar. */
1991
+ header?: KerfUiContent;
1992
+ headerList?: ListConfig;
1993
+ headerPlacement?: CollapsiblePanelChromePlacement;
1994
+ /** Fixed content above a toolbar panel's bottom toolbar. */
1920
1995
  footer?: KerfUiContent;
1996
+ footerList?: ListConfig;
1997
+ bottomToolbar?: CollapsiblePanelBottomToolbar;
1998
+ footerPlacement?: CollapsiblePanelChromePlacement;
1921
1999
  /**
1922
2000
  * Configuration for a `toolbar` panel's `Pane` (`contentElement`,
1923
2001
  * `contentLabel`, `separators`, `safeAreaEdges`, `chromeDividers`) — for example
@@ -1951,7 +2029,7 @@ interface CollapsiblePanelProps {
1951
2029
  * and persistence semantics, and with `CollapsiblePanelToggle` for the standard
1952
2030
  * affordance. See `ui/docs/collapsible-panel.md` and `docs/23-app-layouts.md`.
1953
2031
  */
1954
- declare function CollapsiblePanel({ id, side, collapsed, size, label, children, toolbar, footer, pane, separator, collapseMotion, contentOverflow, presentation, restoreControl, restorePosition, className, }: CollapsiblePanelProps): SafeHtml;
2032
+ 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
2033
  interface CollapsiblePanelRelocatedProps {
1956
2034
  /** The panel's `id`. */
1957
2035
  panelId: string;
@@ -1971,7 +2049,7 @@ interface CollapsiblePanelRelocatedProps {
1971
2049
  */
1972
2050
  declare function CollapsiblePanelRelocated({ panelId, side, collapsed, toolbar, }: CollapsiblePanelRelocatedProps): SafeHtml;
1973
2051
 
1974
- export { CollapsiblePanel, type CollapsiblePanelProps, CollapsiblePanelRelocated, type CollapsiblePanelRelocatedProps, type CollapsiblePanelSide, CollapsiblePanelToggle, type CollapsiblePanelToggleProps, type CollapsiblePanelToolbar, type CollapsiblePanelToolbarToggle };
2052
+ export { CollapsiblePanel, type CollapsiblePanelBottomToolbar, type CollapsiblePanelChromePlacement, type CollapsiblePanelProps, CollapsiblePanelRelocated, type CollapsiblePanelRelocatedProps, type CollapsiblePanelSide, CollapsiblePanelToggle, type CollapsiblePanelToggleProps, type CollapsiblePanelToolbar, type CollapsiblePanelToolbarToggle };
1975
2053
  ```
1976
2054
 
1977
2055
  ## `@kerfjs/ui/wire-sidebar`
@@ -2304,7 +2382,7 @@ import './list.js';
2304
2382
  import './css-values.js';
2305
2383
  import './flex-alignment-4ms8ZbV8.js';
2306
2384
  import './resizable-region.js';
2307
- import './panel-toolbar-DqwtBxQL.js';
2385
+ import './panel-toolbar-DDKh4uKd.js';
2308
2386
  import './lucide-icon.js';
2309
2387
  import 'lucide';
2310
2388
 
@@ -2318,7 +2396,7 @@ import 'lucide';
2318
2396
  declare function Catalog({ id, brand, sections, active, content, collapsed, theme, headerActions, secondarySections, sidebarFooter, status, geometryOverlay, stageRootAttributes, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, headerPlacement, footerPlacement, sidebar, mainToolbar, footerToolbar, className, slot, }: CatalogProps): kerfjs.SafeHtml;
2319
2397
 
2320
2398
  /** How a specimen aligns its visible edge with its `ListHeader` label. */
2321
- type CatalogExampleAlign = 'glyph' | 'inline-control' | 'none';
2399
+ type CatalogExampleAlign = 'glyph' | 'inline-control' | 'text-trigger' | 'none';
2322
2400
  interface CatalogExampleViewport {
2323
2401
  layout?: 'grid' | 'flex' | 'flex-column';
2324
2402
  width?: 'full' | 'compact' | 'medium' | 'wide' | 'text' | 'control';
@@ -2397,7 +2475,7 @@ import './list.js';
2397
2475
  import './css-values.js';
2398
2476
  import './flex-alignment-4ms8ZbV8.js';
2399
2477
  import './resizable-region.js';
2400
- import './panel-toolbar-DqwtBxQL.js';
2478
+ import './panel-toolbar-DDKh4uKd.js';
2401
2479
  import './lucide-icon.js';
2402
2480
  import 'lucide';
2403
2481
 
@@ -2799,6 +2877,7 @@ export { Skeleton, type SkeletonProps };
2799
2877
 
2800
2878
  ```ts
2801
2879
  import * as kerfjs from 'kerfjs';
2880
+ import { CssFlexKeyword, CssFlex } from './css-values.js';
2802
2881
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
2803
2882
 
2804
2883
  type SunkenPanelShape = 'rounded' | 'square';
@@ -2808,6 +2887,10 @@ interface SunkenPanelProps {
2808
2887
  ariaLabel?: string;
2809
2888
  /** Corner shape: a rounded rectangle (default) or square corners. */
2810
2889
  shape?: SunkenPanelShape;
2890
+ /** Grow or shrink within a flex parent, using Grid's typed flex contract. */
2891
+ flex?: boolean | CssFlexKeyword | CssFlex;
2892
+ /** Fill a parent with a definite height; use flex inside a flex layout. */
2893
+ fill?: boolean;
2811
2894
  className?: string;
2812
2895
  /** Native named-slot assignment when composed inside a web component. */
2813
2896
  slot?: string;
@@ -2817,7 +2900,7 @@ interface SunkenPanelProps {
2817
2900
  * stack. The panel owns its background and padding; children own their own
2818
2901
  * borders and internal geometry.
2819
2902
  */
2820
- declare function SunkenPanel({ children, ariaLabel, shape, className, slot, }: SunkenPanelProps): kerfjs.SafeHtml;
2903
+ declare function SunkenPanel({ children, ariaLabel, shape, flex, fill, className, slot, }: SunkenPanelProps): kerfjs.SafeHtml;
2821
2904
 
2822
2905
  export { SunkenPanel, type SunkenPanelProps, type SunkenPanelShape };
2823
2906
  ```
@@ -2827,14 +2910,14 @@ export { SunkenPanel, type SunkenPanelProps, type SunkenPanelShape };
2827
2910
  ```ts
2828
2911
  import 'kerfjs';
2829
2912
  import './semantic-content-BbzjvSu9.js';
2830
- export { T as TokenSearchEditorAttributes, a as TokenSearchField, b as TokenSearchFieldProps, c as TokenSearchFieldValue, j as TokenSearchToken, p as placeTokenSearchCaret, r as readTokenSearchField } from './token-search-field-DvgFLhLL.js';
2913
+ export { T as TokenSearchEditorAttributes, a as TokenSearchField, b as TokenSearchFieldProps, c as TokenSearchFieldValue, j as TokenSearchToken, k as TokenSearchTrailingAction, p as placeTokenSearchCaret, r as readTokenSearchField } from './token-search-field-Xk8jiw8Y.js';
2831
2914
  ```
2832
2915
 
2833
2916
  ## `@kerfjs/ui/wire-token-search-fields`
2834
2917
 
2835
2918
  ```ts
2836
2919
  import { Signal } from 'kerfjs';
2837
- import { d as TokenSearchModel } from './token-search-field-DvgFLhLL.js';
2920
+ import { d as TokenSearchModel } from './token-search-field-Xk8jiw8Y.js';
2838
2921
  import './semantic-content-BbzjvSu9.js';
2839
2922
 
2840
2923
  interface TokenSearchSubmit {
@@ -3091,8 +3174,8 @@ import { SafeHtml } from 'kerfjs';
3091
3174
  import { BadgeTone, BadgeAppearance, BadgeShape, BadgeSize } from './badge.js';
3092
3175
 
3093
3176
  interface ChipCommonProps {
3094
- /** Visible, non-interactive chip content. */
3095
- children: SafeHtml | string | number;
3177
+ /** Decorative leading icon, normally an unsized LucideIcon. */
3178
+ icon?: SafeHtml;
3096
3179
  tone?: BadgeTone;
3097
3180
  appearance?: BadgeAppearance;
3098
3181
  shape?: BadgeShape;
@@ -3106,6 +3189,12 @@ interface ChipCommonProps {
3106
3189
  }
3107
3190
  /** A removable chip needs both a delegated action and a specific accessible name. */
3108
3191
  type ChipProps = ChipCommonProps & ({
3192
+ children: SafeHtml | string | number;
3193
+ truncate?: false;
3194
+ } | {
3195
+ children: string;
3196
+ truncate: true;
3197
+ }) & ({
3109
3198
  removeAction: string;
3110
3199
  removeLabel: string;
3111
3200
  } | {
@@ -3113,7 +3202,7 @@ type ChipProps = ChipCommonProps & ({
3113
3202
  removeLabel?: never;
3114
3203
  });
3115
3204
  /** 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;
3205
+ declare function Chip({ children, icon, truncate, tone, appearance, shape, size, disabled, itemId, className, slot, ...remove }: ChipProps): SafeHtml;
3117
3206
 
3118
3207
  export { Chip, type ChipProps };
3119
3208
  ```
@@ -3125,18 +3214,21 @@ import * as kerfjs from 'kerfjs';
3125
3214
  import { IconNode } from 'lucide';
3126
3215
 
3127
3216
  type LucideNode = IconNode;
3217
+ type LucideIconSize = 'xs' | 's' | 'm' | 'l' | 'xl' | number;
3128
3218
  interface LucideIconProps {
3129
3219
  icon: LucideNode;
3130
3220
  name: string;
3131
3221
  className?: string;
3132
3222
  label?: string;
3223
+ /** Named icon scale or positive pixel size, converted to rem. Omit for 1em. */
3224
+ size?: LucideIconSize;
3133
3225
  /** Native named-slot assignment when composed inside a web component. */
3134
3226
  slot?: string;
3135
3227
  }
3136
3228
  /** Render a Lucide-compatible icon node without copying icon SVG strings. */
3137
- declare function LucideIcon({ icon, name, className, label, slot, }: LucideIconProps): kerfjs.SafeHtml;
3229
+ declare function LucideIcon({ icon, name, className, label, size, slot, }: LucideIconProps): kerfjs.SafeHtml;
3138
3230
 
3139
- export { LucideIcon, type LucideIconProps, type LucideNode };
3231
+ export { LucideIcon, type LucideIconProps, type LucideIconSize, type LucideNode };
3140
3232
  ```
3141
3233
 
3142
3234
  ## `@kerfjs/ui/surface-scaffold`
@@ -3187,8 +3279,9 @@ type TextSize = 'compact' | 'default' | 'large' | 'xlarge';
3187
3279
  type TextFont = 'default' | 'monospace';
3188
3280
  type TextBorder = 'transparent' | 'none';
3189
3281
  type TextLineHeight = 'default' | 'tight';
3282
+ type TextWrap = 'normal' | 'anywhere' | 'nowrap' | 'truncate';
3190
3283
  type TextContent = KerfUiContent | string | number | readonly TextContent[];
3191
- type TextProps = Omit<KerfBaseAttrs, 'children' | 'class' | 'className'> & {
3284
+ type TextCommonProps = Omit<KerfBaseAttrs, 'children' | 'class' | 'className'> & {
3192
3285
  /** Native heading, paragraph, or inline span element to render. Defaults to `p`. */
3193
3286
  variant?: TextVariant;
3194
3287
  /** Semantic foreground treatment. Defaults to the inherited foreground. */
@@ -3207,14 +3300,24 @@ type TextProps = Omit<KerfBaseAttrs, 'children' | 'class' | 'className'> & {
3207
3300
  class?: string;
3208
3301
  className?: string;
3209
3302
  };
3303
+ type TextProps = TextCommonProps & ({
3304
+ /** Wrap normally or break long unbroken strings. Defaults to normal. */
3305
+ wrap?: 'normal' | 'anywhere';
3306
+ /** Cap wrapped text to this positive number of lines. */
3307
+ maxLines?: number;
3308
+ } | {
3309
+ /** Keep one line, with or without an ellipsis. */
3310
+ wrap: 'nowrap' | 'truncate';
3311
+ maxLines?: never;
3312
+ });
3210
3313
  /**
3211
3314
  * Semantic heading, paragraph, or inline text. Block variants use the standard
3212
3315
  * content-item padding; `span` adds no box geometry.
3213
3316
  * All ordinary native heading/paragraph attributes pass through to the element.
3214
3317
  */
3215
- declare function Text({ variant: Variant, tone, size, font, border, flush, lineHeight, children, class: classValue, className, ...attributes }: TextProps): kerfjs.SafeHtml;
3318
+ declare function Text({ variant: Variant, tone, size, font, border, flush, lineHeight, wrap, maxLines, children, class: classValue, className, ...attributes }: TextProps): kerfjs.SafeHtml;
3216
3319
 
3217
- export { Text, type TextBorder, type TextContent, type TextFont, type TextLineHeight, type TextProps, type TextSize, type TextTone, type TextVariant };
3320
+ export { Text, type TextBorder, type TextContent, type TextFont, type TextLineHeight, type TextProps, type TextSize, type TextTone, type TextVariant, type TextWrap };
3218
3321
  ```
3219
3322
 
3220
3323
  ## `@kerfjs/ui/row`
@@ -3281,6 +3384,7 @@ type GridRootAttributes = Readonly<Record<`data-${string}`, string | undefined>
3281
3384
  'data-component'?: never;
3282
3385
  'data-columns'?: never;
3283
3386
  'data-min-column-width'?: never;
3387
+ 'data-auto-fill'?: never;
3284
3388
  'data-flex'?: never;
3285
3389
  'data-fill'?: never;
3286
3390
  }>;
@@ -3306,13 +3410,16 @@ type GridProps = GridCommonProps & ({
3306
3410
  /** Number of equal-width columns. Must be a positive safe integer. */
3307
3411
  columns: number;
3308
3412
  minColumnWidth?: never;
3413
+ autoFill?: never;
3309
3414
  } | {
3310
3415
  columns?: never;
3311
3416
  /** Fit equal columns of at least this width; collapse as the container narrows. */
3312
3417
  minColumnWidth: CssLength;
3418
+ /** Keep empty tracks instead of stretching a sparse row. Defaults to false. */
3419
+ autoFill?: boolean;
3313
3420
  });
3314
3421
  /** Render equal tracks with a fixed count or a responsive minimum width. */
3315
- declare function Grid({ children, columns, minColumnWidth, gap, flex, fill, className, rootAttributes, slot, }: GridProps): kerfjs.SafeHtml;
3422
+ declare function Grid({ children, columns, minColumnWidth, autoFill, gap, flex, fill, className, rootAttributes, slot, }: GridProps): kerfjs.SafeHtml;
3316
3423
 
3317
3424
  export { CssFlex, CssFlexKeyword, CssLength, Grid, type GridProps, UiSpaceName };
3318
3425
  ```
@@ -3344,6 +3451,6 @@ export { CssLength, Spacer, type SpacerProps, UiSpaceName };
3344
3451
 
3345
3452
  ```ts
3346
3453
  import 'kerfjs';
3347
- export { d as TokenSearchModel, e as TokenSearchModelOptions, f as TokenSearchResolvedToken, g as TokenSearchRule, h as TokenSearchState, i as TokenSearchSuggestion, k as createTokenSearchModel } from './token-search-field-DvgFLhLL.js';
3454
+ export { d as TokenSearchModel, e as TokenSearchModelOptions, f as TokenSearchResolvedToken, g as TokenSearchRule, h as TokenSearchState, i as TokenSearchSuggestion, l as createTokenSearchModel } from './token-search-field-Xk8jiw8Y.js';
3348
3455
  import './semantic-content-BbzjvSu9.js';
3349
3456
  ```
package/ai/skill.md CHANGED
@@ -70,8 +70,12 @@ Before choosing or aligning components, look for a consumer-owned catalog that
70
70
  conforms to `./component-catalog-extension.schema.json`. Treat its entries as a
71
71
  second, package-qualified input beside `./component-catalog.json`: search both,
72
72
  preserve their source identity, and use the shared `geometry` vocabulary across
73
- their composition boundary. When a consuming project has reusable visual
74
- components, prefer its generated `component-composition.json`. A package
73
+ their composition boundary. An extension entry's optional `uses` ids resolve
74
+ against both catalogs; its `source` and `demoSource` are repository-relative
75
+ files for consumer catalog links. When a consuming project has reusable visual
76
+ components, derive demo rows with `@kerfjs/ui/catalog-projection` or
77
+ `kerf-catalog-demo --write`, then guard drift with `--check`; see
78
+ `../docs/catalog.md`. Prefer its generated `component-composition.json`. A package
75
79
  scaffolded by `create-kerf-component` owns the decisions in
76
80
  `kerf.components.json`; run `npm run catalog:check` before using its output. If
77
81
  no generated extension exists, start from the checked examples and require the
@@ -195,7 +199,7 @@ Hard rules:
195
199
  4. Wire `data-action` hooks from one stable root with `delegate()` or `delegateActions()` and retain disposers.
196
200
  5. Configure components through their typed props; components own their own styles (see "Components own their styles; configure, never override" above). Use the opinionated `--kui-color-*` semantic ramps for theming, not to reshape a component. Use `pop` only for attractive non-status emphasis such as featured, novel, or celebratory content; never substitute it for info, success, warning, or danger. Set a theme token only at the narrowest useful scope, and never where an equivalent prop exists. `publicClasses` exist for diagnostics, tooling, tests, and package-owned composition, not application styling. Never target a Kerf or Web Awesome component from application CSS; add missing configuration to the owner.
197
201
  6. `Select` is pure until the app explicitly imports `@kerfjs/ui/select/register`; once registered, an icon-only `Select` (and, via `@kerfjs/ui/popup-menu/register`, an icon-only `PopupMenu`) shows an `aria-hidden` help tag repeating its accessible name (and a Select's current choice) on hover and keyboard focus, hidden while its popup is open — never add a `title` or your own tooltip to these triggers. The same installer tags an icon-only `<button>` or link in a `ToolbarControlGroup` named by `aria-label` (no visible text, no `title`); a toolbar with such buttons but no registered Select or PopupMenu imports `@kerfjs/ui/help-tags/register` once. Name those buttons with `aria-label`, not `title`: a `title` keeps the browser tooltip and skips the tag. Do not import Web Awesome's full registration bundle. When an app writes direct `wa-*` JSX, add `import type {} from '@kerfjs/ui/webawesome'` for the catalog-supported intrinsic-element declarations, import the CSS-only `@kerfjs/ui/webawesome.css` theme once, and keep importing individual Web Awesome component modules so their JavaScript remains tree-shakeable. The type boundary emits no code and registers nothing. Pass icon-bearing `choices` and `renderSelected` content normally: `Select` preserves its slotted option icons across Kerf rerenders and keys selected content by the controlled value, so app wrappers must not add competing morph-control attributes. Give it a visible `label` or an `ariaLabel` for a visually hidden name; the nonempty visible label takes precedence and the package names the actual shadow combobox, including `renderSelected`, without adding label geometry. Use `hint` for persistent supporting text below the control and `placeholderText` only for the empty value inside the closed control; loading placeholders retain the hint. For any number of choices set `multiple` with an array `value`: the popup stays open while choices toggle and closes on an outside press or Escape, the closed control summarizes the chosen labels, and `change` reports the value array; do not add app code to keep it open or to render tags. For a toolbar filter menu, add `selectedPresentation="icon-only"` plus a fixed `triggerIcon` (such as a funnel `LucideIcon`): the trigger shows that icon, a count badge while any choice is chosen, and ends its accessible name with the chosen labels ("Filter by label: Bug, Docs"); do not render your own count badge or rewrite the name. When testing name or description, target the element with the `combobox` role rather than the `wa-select` wrapper. Web Awesome's hint attribute and explicit hint slot both describe that shadow combobox across supported engines; do not add an `aria-description` mirror or application shadow-DOM patch.
198
- 7. Decorative icons are hidden; controls are named; focus is visible; state never relies on color alone; reduced motion and increased contrast remain usable. `DisclosureArrow` defaults to an 18px root-scaled visual; size it with its typed `size` prop (`size={remify(24)}`); it never becomes the interaction or accessible-name owner. Put it in an owning native control with a stable accessible name and controlled `aria-expanded`. `ListHeader` toggle mode supplies it when `actionIcon` is omitted, but the app must reveal matching content; a custom icon replaces it. Author replacement icon content facing right before its configured direction transform is applied. Direction changes take the shortest rotation path, with counterclockwise chosen for a 180-degree closed-to-open tie. Kerf `Select` separately keeps its intrinsic Web Awesome expand glyph at `--kui-disclosure-icon-scale: .5`; an icon-only toolbar Select may set `caret={false}` for a round trigger while preserving its help tag and keyboard listbox.
202
+ 7. Decorative icons are hidden; controls are named; focus is visible; state never relies on color alone; reduced motion and increased contrast remain usable. `DisclosureArrow` defaults to an 18px root-scaled visual; size it with its typed `size` prop (`size={remify(24)}`); it never becomes the interaction or accessible-name owner. Put it in an owning native control with a stable accessible name and controlled `aria-expanded`. `ListHeader` toggle mode supplies it when `actionIcon` is omitted, but the app must reveal matching content; a custom icon replaces it. Author replacement icon content facing right before its configured direction transform is applied. Direction changes take the shortest rotation path, with counterclockwise chosen for a 180-degree closed-to-open tie. Kerf `Select` separately keeps its intrinsic Web Awesome expand glyph at `--kui-disclosure-icon-scale: .5`; an icon-only toolbar Select may set `caret={false}` for a round trigger while preserving its help tag and keyboard listbox, and a custom `renderSelected` icon stays centered.
199
203
  8. `ResizableRegion` uses `wireResizableRegions()` for Arrow, Shift+Arrow, Home/End, and pointer behavior. The app owns size persistence. `handleIcon` replaces decorative dormant glyph content only. Set `responsiveFillAt="narrow"` or `"compact"` when a responsive composition exposes the pane as its only inline track; the component fills that track and hides its dormant separator. For compact overlays, set `presentation="overlay"` and the overlay maximum variables. A lone child (normally a `Pane`) fills the region and owns scrolling; several children stack at natural height. Do not add descendant width/height overrides.
200
204
  9. Use controlled `SegmentedControl` for a small exclusive choice set. Select `appearance="toolbar"` when nesting it inside `ToolbarControlGroup`; use rounded or pill shapes for standalone contexts. The package derives inset hover/selection radii from the owning outer shape through `--kui-layout-highlight-inset`; do not restyle an inner highlight to an independent radius. Handle its action, update `value`, keep meaningful choice labels, and preserve every enabled native button in sequential Tab order.
201
205
  10. Compose `AppTab` inside controlled `TabBar`; call `wireTabBars()` once and retain its disposer. It owns same-bar drag mechanics, including proximity-based horizontal edge autoscroll, while the app applies `onReorder` and owns order, selection, panels, close policy, routing, and persistence. For a tab-local action followed by a separately pinned workspace action, set `trailingPlacement="adjacent"`, put the local action in `trailing`, and the workspace action in `end`; TabBar owns the shrinking/scrolling tabs and fixed action geometry, so do not add descendant flex overrides. Arrow/Home/End select on move by default and restore focus by bar/tab identity when controlled activation replaces the strip; pass `activation: 'manual'` (or `TabBar activation="manual"` per strip) so arrow keys move focus only and the user selects with Enter/Space/click — use it when selecting a tab is a heavy action. Use runtime-filtered `rootAttributes` for domain metadata and keep an optional `closeIcon` decorative and noninteractive.
@@ -207,7 +211,7 @@ Hard rules:
207
211
  15. Build sidebars, main areas, inspectors, and dialogs by rendering `Pane` (`@kerfjs/ui/pane`): an unpadded `.kui-pane` root, an optional `header`, one scrolling `.kui-pane__content`, and an optional `footer`; pick landmarks with `element` / `contentElement`. Never write a component's anatomy classes (`kui-pane`, `kui-toolbar`, `kui-list-item`, …) onto your own element to recreate it — render the component (`KUI-L103`). Only the catalog's `placeableClasses` (the `.kui-content` / `.kui-scroll-owner` / `.kui-control-cluster` / `.kui-inline-metadata` layout utilities, `.kui-app-root`, and `.kui-content-item` geometry on a non-div carrier) belong on elements you write. Use `Row` instead of a hand-written flex-row wrapper, `List` instead of a hand-written flex-column wrapper, and `Grid` instead of repeated equal-track CSS when children need a fixed positive count of evenly distributed columns. `Row` defaults to left/full with an `xs` gap and no wrapping; Grid defaults to an `xs` gap and keeps each track at `minmax(0, 1fr)`; List retains full/top and zero-gap defaults. The app owns Grid's responsive column-count changes. When a Row, List, or Grid is the layout root of a definite-height parent (an app root or a fixed-height frame), pass `fill` so it takes that full height, and put route/test/recipe `data-*` markers in its `rootAttributes`; never wrap a layout in a frame `Pane` just for height or a root attribute, because its content slot becomes a scroll owner that never scrolls. Inside a flex layout use `flex`, not `fill`. Use `List` when rows or sections also need flex growth, one vertical scroll owner, or physical-edge dividers. `dividerSides`, `textInsets`, and `controlInsets` use canonical physical `t`/`r`/`b`/`l` order; text geometry wins where text and control selections overlap. `ListInsetText` and `ListInsetControl` inset all four sides by default and accept the same `sides` grammar for selective edges. A dialog body is generally a `List`: set `DialogSurface bodyInset="none"` when its list children own geometry, and wrap bare dialog prose in `ListInsetText` so it aligns with bordered siblings without a second inset. Add `.kui-content` for 24px major vertical separation and render each ordinary surface-like child as `ContentItem` (`@kerfjs/ui/content-item`) for a child-owned 8px inline margin, 1px border, 8px padding, and 12px radius. Choose `frame="framed"` (neutral border in the always-reserved 1px, same geometry) only for a real distinction and `shape="pill"` for 22px; do not hand-write `<div class="kui-content-item">` or its modifier classes. There is no filled variant: a lowered filled surface is `SunkenPanel`. Do not pad pane shells, duplicate item geometry in wrappers, or create nested scroll owners. Align text to text and icons to icons across a pane — a title, a row label, and bare prose share the same text column (`ListInsetText` puts bare text on it); a border is decoration and never the alignment anchor, so a bordered surface extends to the pane gutter instead of being indented to line its border up with a heading's text.
208
212
  15a. Use `Text` from `@kerfjs/ui/text` for ordinary headings, paragraphs, and inline secondary text outside toolbar title zones. Omit `variant` for the default `p`, pass `h1`–`h6` according to the document outline, or use `variant="span"` inside a row, label, or table cell; ordinary native attributes pass through. Express supporting, error, compact, or code text with the independent finite `tone="quiet|danger"`, `size="compact"`, and `font="monospace"` props instead of global utility classes or appearance-only heading choices. Block Text variants own a transparent 1px border and the standard item padding; `span` owns no box geometry. Keep toolbar identity/title content on `ToolbarText` and list-aligned bare prose on `ListInsetText`. `ToolbarText` below `xlarge` is intentionally quiet identity text with no tone option; a normal-color subsection title is `Text` with an `h2`–`h6` variant (or `ListHeader` for a list or menu section), never a recolored `ToolbarText`.
209
213
  16. Keep a visible collapsible pane's collapse control in its own toolbar. When hidden, move its restore control into the adjacent main toolbar on the corresponding logical edge: leading for an inline-start sidebar and trailing for an inline-end inspector. Collapse the pane completely; do not preserve an empty icon-only rail.
210
- 16a. Dividers between pinned chrome and scrolling content are scroll state, not decoration: a `Toolbar` draws none by default (`dividerSides` is for a permanent edge only). Call `wireScrollDividers(appRoot)` from `@kerfjs/ui/wire-scroll-dividers` once and retain its disposer; every `Pane` then draws the line under its header only while content is scrolled beneath it and over its footer only while more content lies below (never when the content fits), every `NavStack`'s top chrome and bottom toolbar and every `TabScaffold` bar do the same around the active view or scene (keyed on whatever actually scrolls there, including a sole `Pane`'s content), and every `TabBar` marks each side of its strip with tabs scrolled out of view. Configure a pane with `chromeDividers` (`scroll` default, `always`, `none`, also via `PaneConfig`), and a `NavStack` or `TabScaffold` with its own `chromeDividers` (same values: `always` draws the chrome lines without the wiring, `none` never, even when wired; a `SplitView` forwards it through `compactStack`); a `toolbarConfig.dividerSides` edge stays the Toolbar's own. Name app-owned chrome by id in `targets`. The wiring writes only `data-scroll-overflow` / `data-scroll-divider` state; never write a border onto a component to show a divider.
214
+ 16a. Dividers between pinned chrome and scrolling content are component chrome: a `Toolbar` draws none by default (`dividerSides` is for a permanent edge only). Call `wireScrollDividers(appRoot)` from `@kerfjs/ui/wire-scroll-dividers` once and retain its disposer; a plain `Pane` with `chromeDividers="scroll"` draws the line under its header only while content is scrolled beneath it and over its footer only while more content lies below (never when the content fits), every `NavStack`'s top chrome and bottom toolbar and every `TabScaffold` bar do the same around the active view or scene (keyed on whatever actually scrolls there, including a sole `Pane`'s content), and every `TabBar` marks each side of its strip with tabs scrolled out of view. Configure a pane with `chromeDividers` (`scroll` by default for plain panes, `always` by default for sunken panes, or explicit `scroll`, `always`, `none`, also via `PaneConfig`); `always` draws both lines even when content fits. A `NavStack` or `TabScaffold` has its own `chromeDividers` (same values: `always` draws the chrome lines without the wiring, `none` never, even when wired; a `SplitView` forwards it through `compactStack`); a `toolbarConfig.dividerSides` edge stays the Toolbar's own. Name app-owned chrome by id in `targets`. The wiring writes only `data-scroll-overflow` / `data-scroll-divider` state; never write a border onto a component to show a divider.
211
215
  17. The only direct children of a `Toolbar` zone (`leading`/`center`/`trailing`) are `ToolbarText` (identity/title text) and `ToolbarControlGroup`; never drop bare buttons, inputs, links, or arbitrary markup straight into a zone. Put identity/title text directly in the zone as `ToolbarText`; wrap interactive controls and icon tiles in `ToolbarControlGroup`. `SegmentedControl`, `Select`, a collapsible `TokenSearchField`, and Web Awesome controls all live inside a group. Configure zone behavior with `Toolbar.centerAlign` and its `responsive` / `responsiveAt` policy instead of selecting toolbar zone classes. No policy clips an action: trailing (and stacked center) zones wrap whole groups onto another row, and the center zone never compresses below its content (a leading title too long for the row truncates with an ellipsis instead), so never hide or shrink a toolbar control to make it fit; use `responsive="wrap"` for a heading whose title must stay whole, and move genuinely lower-priority commands into an app-owned "More" popup menu. For an ordinary icon/action control inside a group, use a plain `<button>` (the group styles `> button` fully) — that is the default; reach for `wa-button` only when you need a Web Awesome feature. A popup menu in a toolbar is a `PopupMenu` (`@kerfjs/ui/popup-menu`, registered once via `@kerfjs/ui/popup-menu/register`) in a `single` group with `nestedDropdown` and a `menuInset`: give it typed `items` (commands with `action`s, `heading`s, `divider`s) and a trigger `icon` plus visible `text` or an accessible `label`; never hand-write `wa-dropdown` / `wa-dropdown-item` markup for a menu. Let the group size that trigger from its icon, localized text, and caret; do not force a width on the menu or button. Nothing wraps inside a group: an icon sits beside its label on one row and a group's controls never break onto a second line — the group sizes to its content, so if it does not fit, the toolbar's `responsive` policy relocates whole groups. A `ToolbarText` is one line ending in an ellipsis by default; opt into `wrap` (capped by `maxLines`) or `ellipsis={false}` deliberately. Inside a group, a `Select` or `PopupMenu` trigger drops its focus ring while its popup is open (the open popup and its current row show where focus is) and the ring returns when the popup closes; a ring follows the control's shape (a pill for an icon-and-caret trigger, a circle for a compact icon button) — set `focusRingOwner="group"` on a Select whose group paints the composed ring, and never add CSS to show, hide, or reshape a ring. For a compact mixed group, keep the standard item padding and raised selected chrome; the selected item paints over the outer border without an internal separator. For an avatar control, set `content="avatar"` and `avatarImage` on the group instead of inserting an `img`: a lone control paints the contained image on the outer group and a multi-button group paints it only on the pressed selection highlight. Compose panel/dialog/page headings with a direct extra-large `ToolbarText`, optional grouped icon, grouped trailing controls, and app-owned supporting copy below. A non-interactive heading icon is an icon tile: put the `LucideIcon` directly in its `ToolbarControlGroup` (it takes an icon button's 40px slot and centers), never inside a `<button>` that does nothing. A group remains 44px outside (`calc(2px + remify(42px))`) when its border/background are transparent; use 8px between groups and inside items. Each zone item sits in the toolbar's top 44px control band, centered by its own size; a taller item (a wrapped title, a second trailing row) starts at the band's top and grows down without moving the others, so a wrapped `ToolbarText` keeps trailing controls beside its first line — do not add alignment CSS for this. Split dormant and interactive regions: `ListHeader` fills the available inline width by default; set `width="content"` to shrink-wrap while retaining its normal geometry, or `inline` when it belongs in surrounding text without outer margin, border, or padding. It keeps its label and mutually exclusive semantic count or non-count `badge` together, with an independent logical-end action unless disclosure mode makes the title cluster the button. Its action visual defaults to 18px through `--kui-list-header-action-icon-size` inside a fitted 36px hover square whose transparent hit layer keeps the pointer target at least 44px (44px wide by the 36px row in `density="compact"`); never shrink the target to match the visual, and never force the button to 44px. Pass every non-negative safe-integer section quantity through `count` with a localized full spoken `countLabel`; never concatenate it into `label` or put a number in `badge`. `ListItem.trailing` is dormant; use `ListActionRow` when primary and trailing actions need sibling native buttons. Its `label`, `icon`, and `trailingActionIcon` slots are also dormant and cannot contain controls. Let panes relocate at narrow widths instead of shrinking targets. Dividers are chrome and earn their place: a `Toolbar` draws none by default, and the line between pinned chrome and scrolling content comes from scroll state (rule 16a), so never add a border, a permanent `dividerSides`, or a margin to fake or adjust one.
212
216
  For a toolbar heading that must remain at the 20px `--kui-font-l` step, use `ToolbarText size="xlarge-fixed"`; `xlarge` retains the responsive page-title clamp. Pass `headingLevel` when it is a section landmark.
213
217
 
@@ -230,7 +234,7 @@ Use `--kui-resizable-region-background` for a region surface and `contentOverflo
230
234
 
231
235
  Use `ListItem density="spacious"` for larger option rows, `multiline` plus `multilineIconAlign="center"` when its icon should center on wrapped copy, `divider` for row separators, and `state="drag-target"` for the drop target treatment. Public `--kui-list-item-*` tokens adjust row, icon, label, and trailing geometry and color; ListHeader height, title padding, and border tokens adjust section density.
232
236
 
233
- For a filled command list, scope `--kui-list-item-background`, `--kui-list-item-border`, `--kui-list-item-hover-border`, and `--kui-list-item-selected-border` at the List or ListItem boundary. Keep global neutral and brand border colors semantic.
237
+ For a filled command list, scope `--kui-list-item-background`, `--kui-list-item-color`, `--kui-list-item-border`, `--kui-list-item-hover-background`, `--kui-list-item-hover-border`, `--kui-list-item-selected-background`, `--kui-list-item-selected-color`, and `--kui-list-item-selected-border` at the List or ListItem boundary. Keep global neutral and brand border colors semantic.
234
238
 
235
239
  Use `Toolbar responsive="trailing-priority"` when an expanded trailing search needs a full second row below its heading at `responsiveAt`. Configure a leading minimum width, trailing gap and justification, or zone inline padding with the public `--kui-toolbar-*` tokens rather than selectors into toolbar zones.
236
240
 
@@ -1,6 +1,6 @@
1
1
  # Web Awesome JSX signatures for the UI authoring corpus
2
2
 
3
- Generated from the emitted `@kerfjs/ui@5.0.0-beta.62` declaration boundary. Import `@kerfjs/ui/webawesome` for type effects when authoring direct `wa-*` JSX. The module emits no runtime behavior and does not register custom elements.
3
+ Generated from the emitted `@kerfjs/ui@5.0.0-beta.64` declaration boundary. Import `@kerfjs/ui/webawesome` for type effects when authoring direct `wa-*` JSX. The module emits no runtime behavior and does not register custom elements.
4
4
 
5
5
  ```ts
6
6
  import { KerfCustomElement } from 'kerfjs/jsx-runtime';