@kerfjs/ui 5.0.0-beta.17 → 5.0.0-beta.21

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 (274) hide show
  1. package/README.md +221 -81
  2. package/ai/application-ui-diagnostic-ids-v1.json +92 -0
  3. package/ai/application-ui-profile-sync.cjs +529 -0
  4. package/ai/application-ui-profile.d.mts +1 -0
  5. package/ai/application-ui-profile.d.ts +102 -0
  6. package/ai/application-ui-profile.defaults.json +41 -0
  7. package/ai/application-ui-profile.mjs +626 -0
  8. package/ai/application-ui-profile.schema.json +130 -0
  9. package/ai/catalog-authoring.json +25 -0
  10. package/ai/catalog-authoring.schema.json +61 -0
  11. package/ai/compile-time-contracts-v1.json +101 -0
  12. package/ai/compile-time-contracts-v1.schema.json +49 -0
  13. package/ai/component-catalog-extension-v2.d.ts +7 -0
  14. package/ai/component-catalog-extension-v2.schema.json +7 -0
  15. package/ai/component-catalog-extension.schema.json +79 -0
  16. package/ai/component-catalog-v2-overrides.json +326 -0
  17. package/ai/component-catalog-v2.d.ts +67 -0
  18. package/ai/component-catalog-v2.json +4441 -0
  19. package/ai/component-catalog-v2.schema.json +246 -0
  20. package/ai/component-catalog.json +649 -6
  21. package/ai/component-catalog.schema.json +15 -0
  22. package/ai/public-api-signatures-v1.md +357 -91
  23. package/ai/skill.md +95 -50
  24. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  25. package/analyzer/cli.mjs +46 -0
  26. package/analyzer/index.d.mts +45 -0
  27. package/analyzer/index.mjs +743 -0
  28. package/analyzer/report.schema.json +66 -0
  29. package/dist/app-tab.d.ts +1 -1
  30. package/dist/app-tab.js +1 -1
  31. package/dist/browser/pane.js +3 -0
  32. package/dist/browser/sunken-panel.js +3 -0
  33. package/dist/catalog-resources.d.ts +34 -0
  34. package/dist/catalog-resources.js +22 -0
  35. package/dist/catalog-resources.js.map +1 -0
  36. package/dist/catalog.d.ts +29 -4
  37. package/dist/catalog.js +302 -84
  38. package/dist/catalog.js.map +1 -1
  39. package/dist/chunk-5VTB2BKP.js +35 -0
  40. package/dist/chunk-5VTB2BKP.js.map +1 -0
  41. package/dist/chunk-6WTETUZ6.js +21 -0
  42. package/dist/chunk-6WTETUZ6.js.map +1 -0
  43. package/dist/chunk-7KEUJIIC.js +218 -0
  44. package/dist/chunk-7KEUJIIC.js.map +1 -0
  45. package/dist/chunk-7L6EHUMV.js +31 -0
  46. package/dist/chunk-7L6EHUMV.js.map +1 -0
  47. package/dist/{chunk-XXMOARTH.js → chunk-AASLYRGE.js} +57 -16
  48. package/dist/chunk-AASLYRGE.js.map +1 -0
  49. package/dist/chunk-BBRXX6PF.js +108 -0
  50. package/dist/chunk-BBRXX6PF.js.map +1 -0
  51. package/dist/{chunk-6NLRBSVX.js → chunk-CN2XNTAM.js} +129 -72
  52. package/dist/chunk-CN2XNTAM.js.map +1 -0
  53. package/dist/chunk-DPDBVKNA.js +113 -0
  54. package/dist/chunk-DPDBVKNA.js.map +1 -0
  55. package/dist/chunk-DSNIYOZ3.js +114 -0
  56. package/dist/chunk-DSNIYOZ3.js.map +1 -0
  57. package/dist/chunk-ELSJX4W7.js +68 -0
  58. package/dist/chunk-ELSJX4W7.js.map +1 -0
  59. package/dist/{chunk-AHQI52QO.js → chunk-FEY65TBV.js} +6 -2
  60. package/dist/chunk-FEY65TBV.js.map +1 -0
  61. package/dist/chunk-JRKSK2HX.js +79 -0
  62. package/dist/chunk-JRKSK2HX.js.map +1 -0
  63. package/dist/chunk-K57KRAOV.js +117 -0
  64. package/dist/chunk-K57KRAOV.js.map +1 -0
  65. package/dist/chunk-LPOMRC4C.js +25 -0
  66. package/dist/chunk-LPOMRC4C.js.map +1 -0
  67. package/dist/chunk-M7JBER5U.js +41 -0
  68. package/dist/chunk-M7JBER5U.js.map +1 -0
  69. package/dist/chunk-NENBUYX5.js +79 -0
  70. package/dist/chunk-NENBUYX5.js.map +1 -0
  71. package/dist/chunk-OHU6CI22.js +83 -0
  72. package/dist/chunk-OHU6CI22.js.map +1 -0
  73. package/dist/{chunk-YGN7OMLT.js → chunk-OZWU5ZPZ.js} +2 -2
  74. package/dist/chunk-OZWU5ZPZ.js.map +1 -0
  75. package/dist/chunk-PIDTEQ3U.js +105 -0
  76. package/dist/chunk-PIDTEQ3U.js.map +1 -0
  77. package/dist/chunk-PX3YSS5C.js +32 -0
  78. package/dist/chunk-PX3YSS5C.js.map +1 -0
  79. package/dist/chunk-PZQVSDLH.js +61 -0
  80. package/dist/chunk-PZQVSDLH.js.map +1 -0
  81. package/dist/chunk-QO55FN2Y.js +20 -0
  82. package/dist/chunk-QO55FN2Y.js.map +1 -0
  83. package/dist/chunk-QQFJMRIB.js +45 -0
  84. package/dist/chunk-QQFJMRIB.js.map +1 -0
  85. package/dist/chunk-RYRIFZCT.js +58 -0
  86. package/dist/chunk-RYRIFZCT.js.map +1 -0
  87. package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
  88. package/dist/chunk-SRSJO5QE.js.map +1 -0
  89. package/dist/chunk-VLYV65LK.js +38 -0
  90. package/dist/chunk-VLYV65LK.js.map +1 -0
  91. package/dist/chunk-W4CXQYSG.js +23 -0
  92. package/dist/chunk-W4CXQYSG.js.map +1 -0
  93. package/dist/{chunk-WXMGNX2Y.js → chunk-W7YD6E4N.js} +2 -2
  94. package/dist/chunk-W7YD6E4N.js.map +1 -0
  95. package/dist/{chunk-56RJXPHG.js → chunk-Y6LYKFXY.js} +1 -1
  96. package/dist/{chunk-56RJXPHG.js.map → chunk-Y6LYKFXY.js.map} +1 -1
  97. package/dist/collapsible-panel.d.ts +2 -2
  98. package/dist/collapsible-panel.js +47 -6
  99. package/dist/collapsible-panel.js.map +1 -1
  100. package/dist/device-class.js +33 -5
  101. package/dist/device-class.js.map +1 -1
  102. package/dist/disclosure-arrow.js +1 -1
  103. package/dist/empty-state.d.ts +1 -1
  104. package/dist/empty-state.js +1 -1
  105. package/dist/floating-toolbar.d.ts +1 -1
  106. package/dist/floating-toolbar.js +1 -1
  107. package/dist/index.d.ts +6 -4
  108. package/dist/index.js +27 -25
  109. package/dist/list-action-row.d.ts +1 -1
  110. package/dist/list-action-row.js +1 -1
  111. package/dist/list-header.d.ts +30 -9
  112. package/dist/list-header.js +1 -1
  113. package/dist/list-inset-control.d.ts +1 -1
  114. package/dist/list-inset-control.js +1 -1
  115. package/dist/list-inset-text.d.ts +1 -1
  116. package/dist/list-inset-text.js +1 -1
  117. package/dist/list-item.d.ts +1 -1
  118. package/dist/list-item.js +1 -1
  119. package/dist/loading-spinner.js +1 -1
  120. package/dist/nav-stack.d.ts +1 -1
  121. package/dist/nav-stack.js +1 -1
  122. package/dist/pane.d.ts +49 -0
  123. package/dist/pane.js +4 -0
  124. package/dist/pane.js.map +1 -0
  125. package/dist/panel-header.d.ts +10 -4
  126. package/dist/panel-header.js +1 -1
  127. package/dist/resizable-region.d.ts +1 -1
  128. package/dist/resizable-region.js +1 -1
  129. package/dist/segmented-control.d.ts +6 -6
  130. package/dist/segmented-control.js +1 -1
  131. package/dist/select.d.ts +11 -5
  132. package/dist/select.js +1 -1
  133. package/dist/skeleton.d.ts +1 -1
  134. package/dist/skeleton.js +1 -1
  135. package/dist/split-view.d.ts +1 -1
  136. package/dist/split-view.js +70 -10
  137. package/dist/split-view.js.map +1 -1
  138. package/dist/state-banner.d.ts +4 -3
  139. package/dist/state-banner.js +1 -1
  140. package/dist/styles/catalog.css +32 -6
  141. package/dist/styles/layout.css +2 -20
  142. package/dist/styles/pane.css +62 -0
  143. package/dist/styles/segmented-control.css +3 -7
  144. package/dist/styles/sunken-panel.css +18 -0
  145. package/dist/sunken-panel.d.ts +16 -0
  146. package/dist/sunken-panel.js +3 -0
  147. package/dist/sunken-panel.js.map +1 -0
  148. package/dist/tab-bar.d.ts +4 -3
  149. package/dist/tab-bar.js +1 -1
  150. package/dist/tab-scaffold.d.ts +6 -6
  151. package/dist/tab-scaffold.js +43 -8
  152. package/dist/tab-scaffold.js.map +1 -1
  153. package/dist/token-search-field.d.ts +25 -9
  154. package/dist/token-search-field.js +1 -1
  155. package/dist/toolbar-control-group.d.ts +10 -6
  156. package/dist/toolbar-control-group.js +1 -1
  157. package/dist/toolbar-text.d.ts +10 -11
  158. package/dist/toolbar-text.js +1 -1
  159. package/dist/toolbar.d.ts +1 -1
  160. package/dist/toolbar.js +1 -1
  161. package/dist/value-table.d.ts +2 -2
  162. package/dist/value-table.js +1 -1
  163. package/dist/wire-catalog.d.ts +31 -2
  164. package/dist/wire-catalog.js +203 -8
  165. package/dist/wire-catalog.js.map +1 -1
  166. package/dist/wire-nav-stack.js +22 -7
  167. package/dist/wire-nav-stack.js.map +1 -1
  168. package/dist/wire-resizable-regions.d.ts +1 -1
  169. package/dist/wire-resizable-regions.js +1 -1
  170. package/dist/wire-sidebar.js +52 -41
  171. package/dist/wire-sidebar.js.map +1 -1
  172. package/dist/wire-tab-bars.d.ts +5 -2
  173. package/dist/wire-tab-bars.js +1 -1
  174. package/dist/wire-tab-scaffold.js +9 -4
  175. package/dist/wire-tab-scaffold.js.map +1 -1
  176. package/dist/wire-token-search-fields.d.ts +12 -7
  177. package/dist/wire-token-search-fields.js +1 -1
  178. package/dist/workbench.d.ts +1 -1
  179. package/dist/workbench.js +56 -9
  180. package/dist/workbench.js.map +1 -1
  181. package/docs/app-layouts.md +7 -7
  182. package/docs/catalog.md +249 -46
  183. package/docs/collapsible-panel.md +38 -11
  184. package/docs/component-contract.md +132 -7
  185. package/docs/component-selection.md +79 -67
  186. package/docs/design/templates.md +1 -1
  187. package/docs/design-philosophy.md +7 -9
  188. package/docs/device-class.md +8 -8
  189. package/docs/examples/application-ui-profile.json +60 -0
  190. package/docs/examples/command-palette-adapter.tsx +67 -17
  191. package/docs/examples/component-catalog-extension-v2.json +81 -0
  192. package/docs/examples/component-catalog-extension.json +45 -0
  193. package/docs/layout.md +51 -32
  194. package/docs/nav-stack.md +15 -6
  195. package/docs/recipes.md +4 -4
  196. package/docs/split-view.md +3 -3
  197. package/docs/sunken-panel.md +43 -0
  198. package/docs/tab-scaffold.md +16 -7
  199. package/docs/type-contracts.md +99 -0
  200. package/docs/ui-analyzer.md +81 -0
  201. package/docs/ui-doctor.md +77 -0
  202. package/docs/ui-evaluator.md +122 -0
  203. package/docs/webawesome-theme.md +8 -8
  204. package/docs/workbench.md +18 -5
  205. package/doctor/cli.mjs +115 -0
  206. package/doctor/config.schema.json +68 -0
  207. package/doctor/index.d.mts +116 -0
  208. package/doctor/index.mjs +1256 -0
  209. package/doctor/report.schema.json +118 -0
  210. package/evaluator/cli.mjs +89 -0
  211. package/evaluator/index.d.mts +90 -0
  212. package/evaluator/index.mjs +1138 -0
  213. package/evaluator/report.schema.json +152 -0
  214. package/llms.txt +58 -15
  215. package/package.json +70 -10
  216. package/ux-demo/recipes/app-shell.tsx +206 -10
  217. package/ux-demo/recipes/collapsible-sidebar.tsx +167 -44
  218. package/ux-demo/recipes/compact-toolbar.tsx +114 -12
  219. package/ux-demo/recipes/composer-form.tsx +106 -18
  220. package/ux-demo/recipes/list-detail-dialog.tsx +144 -8
  221. package/ux-demo/recipes/list-workspace-states.tsx +165 -8
  222. package/ux-demo/recipes/loaders.ts +5 -2
  223. package/ux-demo/recipes/loading-inspector.tsx +124 -41
  224. package/ux-demo/recipes/mount-recipe.ts +27 -6
  225. package/ux-demo/recipes/navigation-sidebar.tsx +120 -9
  226. package/ux-demo/recipes/navigation-stack.tsx +61 -19
  227. package/ux-demo/recipes/types.ts +3 -1
  228. package/ux-demo/recipes/workspace-header.tsx +57 -2
  229. package/dist/chunk-2Z5TWHKQ.js +0 -34
  230. package/dist/chunk-2Z5TWHKQ.js.map +0 -1
  231. package/dist/chunk-37T3VNIZ.js +0 -19
  232. package/dist/chunk-37T3VNIZ.js.map +0 -1
  233. package/dist/chunk-55DATV3A.js +0 -10
  234. package/dist/chunk-55DATV3A.js.map +0 -1
  235. package/dist/chunk-5ATCDSQS.js +0 -42
  236. package/dist/chunk-5ATCDSQS.js.map +0 -1
  237. package/dist/chunk-5E2HVJ33.js +0 -10
  238. package/dist/chunk-5E2HVJ33.js.map +0 -1
  239. package/dist/chunk-6NLRBSVX.js.map +0 -1
  240. package/dist/chunk-7BR3DO2A.js.map +0 -1
  241. package/dist/chunk-7JB7VPRI.js +0 -34
  242. package/dist/chunk-7JB7VPRI.js.map +0 -1
  243. package/dist/chunk-7LDCTU7D.js +0 -134
  244. package/dist/chunk-7LDCTU7D.js.map +0 -1
  245. package/dist/chunk-AHQI52QO.js.map +0 -1
  246. package/dist/chunk-AQNKJRFH.js +0 -79
  247. package/dist/chunk-AQNKJRFH.js.map +0 -1
  248. package/dist/chunk-AVZHJN6C.js +0 -14
  249. package/dist/chunk-AVZHJN6C.js.map +0 -1
  250. package/dist/chunk-B24C4A6T.js +0 -22
  251. package/dist/chunk-B24C4A6T.js.map +0 -1
  252. package/dist/chunk-CH4SQ6H5.js +0 -39
  253. package/dist/chunk-CH4SQ6H5.js.map +0 -1
  254. package/dist/chunk-DAFFDO33.js +0 -14
  255. package/dist/chunk-DAFFDO33.js.map +0 -1
  256. package/dist/chunk-I7INRJO4.js +0 -17
  257. package/dist/chunk-I7INRJO4.js.map +0 -1
  258. package/dist/chunk-L4OKFDJY.js +0 -24
  259. package/dist/chunk-L4OKFDJY.js.map +0 -1
  260. package/dist/chunk-M5JRI6MN.js +0 -27
  261. package/dist/chunk-M5JRI6MN.js.map +0 -1
  262. package/dist/chunk-RNPGFQ33.js +0 -10
  263. package/dist/chunk-RNPGFQ33.js.map +0 -1
  264. package/dist/chunk-VPCTCUED.js +0 -10
  265. package/dist/chunk-VPCTCUED.js.map +0 -1
  266. package/dist/chunk-WRTAQ7BZ.js +0 -23
  267. package/dist/chunk-WRTAQ7BZ.js.map +0 -1
  268. package/dist/chunk-WVPYVDXY.js +0 -15
  269. package/dist/chunk-WVPYVDXY.js.map +0 -1
  270. package/dist/chunk-WXMGNX2Y.js.map +0 -1
  271. package/dist/chunk-XXMOARTH.js.map +0 -1
  272. package/dist/chunk-YGN7OMLT.js.map +0 -1
  273. package/dist/chunk-ZQQ6P4SV.js +0 -20
  274. package/dist/chunk-ZQQ6P4SV.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.17` and `kerfjs@5.0.0-beta.17`. 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.21` and `kerfjs@5.0.0-beta.21`. 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/disclosure-arrow`
6
6
 
@@ -34,7 +34,7 @@ interface ToolbarProps {
34
34
  divider?: boolean;
35
35
  className?: string;
36
36
  }
37
- declare function Toolbar({ leading, center, trailing, label, divider, className }: ToolbarProps): SafeHtml;
37
+ declare function Toolbar({ leading, center, trailing, label, divider, className, }: ToolbarProps): SafeHtml;
38
38
 
39
39
  export { Toolbar, type ToolbarProps };
40
40
  ```
@@ -47,7 +47,7 @@ import * as kerfjs from 'kerfjs';
47
47
  type ToolbarTextSize = 'xlarge' | 'large' | 'default' | 'small';
48
48
  /** ARIA heading level for a title exposed as a heading landmark. */
49
49
  type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
50
- interface ToolbarTextProps {
50
+ interface ToolbarTextBaseProps {
51
51
  text: string;
52
52
  size?: ToolbarTextSize;
53
53
  className?: string;
@@ -61,23 +61,22 @@ interface ToolbarTextProps {
61
61
  headingLevel?: HeadingLevel;
62
62
  /** Render the text as an unanimated loading skeleton instead of its value. */
63
63
  placeholder?: boolean;
64
- /**
65
- * Wrap onto multiple lines when the text does not fit, instead of the default
66
- * single line. Combine with `maxLines` to cap the number of lines. Default false.
67
- */
68
- wrap?: boolean;
69
64
  /**
70
65
  * Show a trailing ellipsis (…) where the text is truncated — on the single line
71
66
  * (default), or at the `maxLines` boundary when wrapping. Set false to hard-clip
72
67
  * instead. Default true.
73
68
  */
74
69
  ellipsis?: boolean;
75
- /**
76
- * Cap wrapped text to this many lines, truncating past it. Only takes effect with
77
- * `wrap`; ignored on a single line. `null`/omitted wraps without a line cap. Default null.
78
- */
79
- maxLines?: number | null;
80
70
  }
71
+ type ToolbarTextWrappingProps = {
72
+ /** Wrap onto multiple lines; combine with `maxLines` to cap them. */
73
+ wrap: true;
74
+ maxLines?: number | null;
75
+ } | {
76
+ wrap?: false;
77
+ maxLines?: never;
78
+ };
79
+ type ToolbarTextProps = ToolbarTextBaseProps & ToolbarTextWrappingProps;
81
80
  declare function ToolbarText({ text, size, className, id, headingLevel, placeholder, wrap, ellipsis, maxLines, }: ToolbarTextProps): kerfjs.SafeHtml;
82
81
 
83
82
  export { type HeadingLevel, ToolbarText, type ToolbarTextProps, type ToolbarTextSize };
@@ -88,21 +87,25 @@ export { type HeadingLevel, ToolbarText, type ToolbarTextProps, type ToolbarText
88
87
  ```ts
89
88
  import { SafeHtml } from 'kerfjs';
90
89
 
90
+ type ToolbarControlGroupAppearance = 'contained' | 'borderless';
91
+ type ToolbarControlGroupTone = 'default' | 'dark';
92
+ type ToolbarControlGroupButtonAppearance = 'plain' | 'push';
93
+ type ToolbarControlGroupShape = 'pill' | 'rounded';
91
94
  interface ToolbarControlGroupProps {
92
95
  children: SafeHtml | SafeHtml[];
93
96
  label?: string;
94
97
  className?: string;
95
98
  expanded?: boolean;
96
99
  single?: boolean;
97
- appearance?: 'contained' | 'borderless';
98
- tone?: 'default' | 'dark';
99
- buttonAppearance?: 'plain' | 'push';
100
+ appearance?: ToolbarControlGroupAppearance;
101
+ tone?: ToolbarControlGroupTone;
102
+ buttonAppearance?: ToolbarControlGroupButtonAppearance;
100
103
  /** Corner shape: fully round `pill` (default) or a softer `rounded` rectangle. */
101
- shape?: 'pill' | 'rounded';
104
+ shape?: ToolbarControlGroupShape;
102
105
  }
103
- declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, buttonAppearance, shape }: ToolbarControlGroupProps): SafeHtml;
106
+ declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, buttonAppearance, shape, }: ToolbarControlGroupProps): SafeHtml;
104
107
 
105
- export { ToolbarControlGroup, type ToolbarControlGroupProps };
108
+ export { ToolbarControlGroup, type ToolbarControlGroupAppearance, type ToolbarControlGroupButtonAppearance, type ToolbarControlGroupProps, type ToolbarControlGroupShape, type ToolbarControlGroupTone };
106
109
  ```
107
110
 
108
111
  ## `@kerfjs/ui/floating-toolbar`
@@ -133,7 +136,7 @@ interface FloatingToolbarProps {
133
136
  * top toolbar's own inset); override that token to move it. The app owns the
134
137
  * controls and their behavior — wire them with `delegate()` as usual.
135
138
  */
136
- declare function FloatingToolbar({ children, label, position, className }: FloatingToolbarProps): SafeHtml;
139
+ declare function FloatingToolbar({ children, label, position, className, }: FloatingToolbarProps): SafeHtml;
137
140
 
138
141
  export { FloatingToolbar, type FloatingToolbarPosition, type FloatingToolbarProps };
139
142
  ```
@@ -159,18 +162,39 @@ type ListHeaderTriggerAttributes = Readonly<Record<`data-${string}`, string | un
159
162
  }>;
160
163
  interface ListHeaderBaseProps {
161
164
  label: string;
162
- action?: string;
163
- actionLabel?: string;
164
- actionIcon?: SafeHtml;
165
- actionDisabled?: boolean;
166
- disabledReason?: string;
167
- expanded?: boolean;
168
- toggle?: boolean;
169
165
  /** Render as an unanimated loading skeleton: keep the label and action affordance, disable interaction. */
170
166
  placeholder?: boolean;
171
167
  rootAttributes?: ListHeaderRootAttributes;
172
168
  triggerAttributes?: ListHeaderTriggerAttributes;
173
169
  }
170
+ type ListHeaderModeProps = {
171
+ /** Render the title as a controlled disclosure trigger. */
172
+ toggle: true;
173
+ action: string;
174
+ expanded: boolean;
175
+ actionIcon?: SafeHtml;
176
+ actionLabel?: never;
177
+ actionDisabled?: boolean;
178
+ disabledReason?: string;
179
+ } | {
180
+ /** Render a separately named trailing action. */
181
+ toggle?: false;
182
+ action: string;
183
+ actionLabel: string;
184
+ actionIcon: SafeHtml;
185
+ expanded?: never;
186
+ actionDisabled?: boolean;
187
+ disabledReason?: string;
188
+ } | {
189
+ /** Render a passive section heading. */
190
+ toggle?: false;
191
+ action?: never;
192
+ actionLabel?: never;
193
+ actionIcon?: never;
194
+ expanded?: never;
195
+ actionDisabled?: never;
196
+ disabledReason?: never;
197
+ };
174
198
  type ListHeaderIndicatorProps = {
175
199
  count: number;
176
200
  countLabel: string;
@@ -180,8 +204,8 @@ type ListHeaderIndicatorProps = {
180
204
  countLabel?: never;
181
205
  badge?: SafeHtml;
182
206
  };
183
- type ListHeaderProps = ListHeaderBaseProps & ListHeaderIndicatorProps;
184
- declare function ListHeader({ label, count, countLabel, badge, action, actionLabel, actionIcon, actionDisabled, disabledReason, expanded, toggle, placeholder, rootAttributes, triggerAttributes }: ListHeaderProps): SafeHtml;
207
+ type ListHeaderProps = ListHeaderBaseProps & ListHeaderIndicatorProps & ListHeaderModeProps;
208
+ declare function ListHeader({ label, count, countLabel, badge, action, actionLabel, actionIcon, actionDisabled, disabledReason, expanded, toggle, placeholder, rootAttributes, triggerAttributes, }: ListHeaderProps): SafeHtml;
185
209
 
186
210
  export { ListHeader, type ListHeaderProps };
187
211
  ```
@@ -238,7 +262,7 @@ interface ListActionRowProps {
238
262
  rootAttributes?: ListActionRowRootAttributes;
239
263
  trailingActionAttributes?: ListActionRowTrailingAttributes;
240
264
  }
241
- declare function ListActionRow({ label, icon, action, itemId, selected, pressed, accessibleLabel, title, multiline, state, disabled, tabIndex, placeholder, trailingAction, trailingActionLabel, trailingActionIcon, trailingActionDisabled, trailingActionTitle, className, style, rootAttributes, trailingActionAttributes }: ListActionRowProps): SafeHtml;
265
+ declare function ListActionRow({ label, icon, action, itemId, selected, pressed, accessibleLabel, title, multiline, state, disabled, tabIndex, placeholder, trailingAction, trailingActionLabel, trailingActionIcon, trailingActionDisabled, trailingActionTitle, className, style, rootAttributes, trailingActionAttributes, }: ListActionRowProps): SafeHtml;
242
266
 
243
267
  export { ListActionRow, type ListActionRowProps };
244
268
  ```
@@ -276,7 +300,7 @@ interface ListItemProps {
276
300
  placeholder?: boolean;
277
301
  rootAttributes?: ListItemRootAttributes;
278
302
  }
279
- declare function ListItem({ label, icon, trailing, selected, action, itemId, className, style, pressed, accessibleLabel, title, multiline, state, disabled, tabIndex, placeholder, rootAttributes }: ListItemProps): SafeHtml;
303
+ declare function ListItem({ label, icon, trailing, selected, action, itemId, className, style, pressed, accessibleLabel, title, multiline, state, disabled, tabIndex, placeholder, rootAttributes, }: ListItemProps): SafeHtml;
280
304
 
281
305
  export { ListItem, type ListItemProps };
282
306
  ```
@@ -297,7 +321,7 @@ interface ListInsetControlProps {
297
321
  * Use it for controls that carry their own border and padding but no outer margin
298
322
  * — the wrapper adds only the alignment margin and layout, not a second inset.
299
323
  */
300
- declare function ListInsetControl({ children, className }: ListInsetControlProps): SafeHtml;
324
+ declare function ListInsetControl({ children, className, }: ListInsetControlProps): SafeHtml;
301
325
 
302
326
  export { ListInsetControl, type ListInsetControlProps };
303
327
  ```
@@ -327,7 +351,7 @@ interface ListInsetTextProps {
327
351
  * Pass `horizontalOnly` to keep the horizontal inset but drop the vertical box
328
352
  * space for tight text layout.
329
353
  */
330
- declare function ListInsetText({ children, horizontalOnly, className }: ListInsetTextProps): SafeHtml;
354
+ declare function ListInsetText({ children, horizontalOnly, className, }: ListInsetTextProps): SafeHtml;
331
355
 
332
356
  export { ListInsetText, type ListInsetTextProps };
333
357
  ```
@@ -338,11 +362,9 @@ export { ListInsetText, type ListInsetTextProps };
338
362
  import { SafeHtml } from 'kerfjs';
339
363
  import { HeadingLevel } from './toolbar-text.js';
340
364
 
341
- interface PanelHeaderProps {
365
+ interface PanelHeaderBaseProps {
342
366
  title: string;
343
367
  titleId: string;
344
- summary?: string;
345
- summaryId?: string;
346
368
  icon?: SafeHtml;
347
369
  iconClassName?: string;
348
370
  actions?: SafeHtml;
@@ -356,6 +378,14 @@ interface PanelHeaderProps {
356
378
  /** Render the title and summary as unanimated loading skeletons, keeping the icon and actions. */
357
379
  placeholder?: boolean;
358
380
  }
381
+ type PanelHeaderSummaryProps = {
382
+ summary: string;
383
+ summaryId?: string;
384
+ } | {
385
+ summary?: never;
386
+ summaryId?: never;
387
+ };
388
+ type PanelHeaderProps = PanelHeaderBaseProps & PanelHeaderSummaryProps;
359
389
  /**
360
390
  * The heading of a panel, dialog, or page: a plain `Toolbar` whose leading zone
361
391
  * holds an optional icon control group and the title as extra-large `ToolbarText`,
@@ -368,7 +398,7 @@ interface PanelHeaderProps {
368
398
  * is passed straight into the toolbar's trailing zone; the app supplies whatever
369
399
  * trailing controls it needs (typically a `ToolbarControlGroup`).
370
400
  */
371
- declare function PanelHeader({ title, titleId, summary, summaryId, icon, iconClassName, actions, headingLevel, placeholder }: PanelHeaderProps): SafeHtml;
401
+ declare function PanelHeader({ title, titleId, summary, summaryId, icon, iconClassName, actions, headingLevel, placeholder, }: PanelHeaderProps): SafeHtml;
372
402
 
373
403
  export { PanelHeader, type PanelHeaderProps };
374
404
  ```
@@ -386,14 +416,14 @@ interface ValueTableRowProps {
386
416
  /** Render the value as an unanimated loading skeleton, keeping the field label. */
387
417
  placeholder?: boolean;
388
418
  }
389
- declare function ValueTableRow({ label, value, icon, className, placeholder }: ValueTableRowProps): SafeHtml;
419
+ declare function ValueTableRow({ label, value, icon, className, placeholder, }: ValueTableRowProps): SafeHtml;
390
420
 
391
421
  interface ValueTableProps {
392
422
  label: string;
393
423
  className?: string;
394
424
  children: SafeHtml | readonly SafeHtml[];
395
425
  }
396
- declare function ValueTable({ label, className, children }: ValueTableProps): SafeHtml;
426
+ declare function ValueTable({ label, className, children, }: ValueTableProps): SafeHtml;
397
427
 
398
428
  export { ValueTable, type ValueTableProps, ValueTableRow, type ValueTableRowProps };
399
429
  ```
@@ -428,7 +458,7 @@ interface AppTabProps {
428
458
  placeholder?: boolean;
429
459
  rootAttributes?: AppTabRootAttributes;
430
460
  }
431
- declare function AppTab({ id, name, selected, closable, draggable, leading, trailing, closeIcon, selectAction, closeAction, className, placeholder, rootAttributes }: AppTabProps): SafeHtml;
461
+ declare function AppTab({ id, name, selected, closable, draggable, leading, trailing, closeIcon, selectAction, closeAction, className, placeholder, rootAttributes, }: AppTabProps): SafeHtml;
432
462
 
433
463
  export { AppTab, type AppTabProps };
434
464
  ```
@@ -438,6 +468,7 @@ export { AppTab, type AppTabProps };
438
468
  ```ts
439
469
  import { SafeHtml } from 'kerfjs';
440
470
 
471
+ type TabActivation = 'automatic' | 'manual';
441
472
  interface TabBarProps {
442
473
  id: string;
443
474
  label: string;
@@ -451,17 +482,20 @@ interface TabBarProps {
451
482
  * selects on arrow / Home / End; `'manual'` moves roving focus only and the user
452
483
  * selects with Enter / Space / click — use it when selecting a tab is a heavy action.
453
484
  */
454
- activation?: 'automatic' | 'manual';
485
+ activation?: TabActivation;
455
486
  }
456
487
  /** Render a controlled tab strip. The application owns selection, order, and persistence. */
457
- declare function TabBar({ id, label, children, leading, trailing, className, activation }: TabBarProps): SafeHtml;
488
+ declare function TabBar({ id, label, children, leading, trailing, className, activation, }: TabBarProps): SafeHtml;
458
489
 
459
- export { TabBar, type TabBarProps };
490
+ export { type TabActivation, TabBar, type TabBarProps };
460
491
  ```
461
492
 
462
493
  ## `@kerfjs/ui/wire-tab-bars`
463
494
 
464
495
  ```ts
496
+ import { TabActivation } from './tab-bar.js';
497
+ import 'kerfjs';
498
+
465
499
  type TabReorderSource = 'pointer' | 'keyboard';
466
500
  type TabDropPosition = 'before' | 'after';
467
501
  interface TabReorder {
@@ -471,7 +505,7 @@ interface TabReorder {
471
505
  position: TabDropPosition;
472
506
  source: TabReorderSource;
473
507
  }
474
- type TabActivation = 'automatic' | 'manual';
508
+
475
509
  interface WireTabBarsOptions {
476
510
  onReorder: (change: TabReorder) => void;
477
511
  /**
@@ -491,7 +525,7 @@ declare function reorderTabs<T>(items: readonly T[], getId: (item: T) => string,
491
525
  /** Wire reordering and keyboard navigation while leaving controlled state in the application. */
492
526
  declare function wireTabBars(root: HTMLElement | Document, { onReorder, activation }: WireTabBarsOptions): () => void;
493
527
 
494
- export { type TabActivation, type TabDropPosition, type TabReorder, type TabReorderSource, type WireTabBarsOptions, reorderTabs, wireTabBars };
528
+ export { TabActivation, type TabDropPosition, type TabReorder, type TabReorderSource, type WireTabBarsOptions, reorderTabs, wireTabBars };
495
529
  ```
496
530
 
497
531
  ## `@kerfjs/ui/nav-stack`
@@ -532,7 +566,7 @@ interface NavStackProps {
532
566
  * cross-fades the chrome across a change. A single-pane layout is a `NavStack`
533
567
  * with one entry. See `docs/23-app-layouts.md` §3.1.
534
568
  */
535
- declare function NavStack({ id, label, views, backLabel, hideToolbar, bottomToolbar, className }: NavStackProps): SafeHtml;
569
+ declare function NavStack({ id, label, views, backLabel, hideToolbar, bottomToolbar, className, }: NavStackProps): SafeHtml;
536
570
 
537
571
  export { NavStack, type NavStackProps, type NavStackView };
538
572
  ```
@@ -599,11 +633,65 @@ interface SplitViewProps {
599
633
  * resizable wiring with `wireResizableRegions` and the compact back with
600
634
  * `wireNavStack`.
601
635
  */
602
- declare function SplitView({ id, label, list, detail, compact, detailActive, listTitle, detailTitle, backLabel, resizable, className }: SplitViewProps): SafeHtml;
636
+ declare function SplitView({ id, label, list, detail, compact, detailActive, listTitle, detailTitle, backLabel, resizable, className, }: SplitViewProps): SafeHtml;
603
637
 
604
638
  export { SplitView, type SplitViewProps, type SplitViewResizable };
605
639
  ```
606
640
 
641
+ ## `@kerfjs/ui/pane`
642
+
643
+ ```ts
644
+ import { SafeHtml } from 'kerfjs';
645
+
646
+ /** Logical sides that can show a {@link Pane} separator. */
647
+ type PaneSeparatorSide = 'block-start' | 'block-end' | 'inline-start' | 'inline-end';
648
+ /** Semantic root elements supported by {@link Pane}. */
649
+ type PaneElement = 'article' | 'aside' | 'div' | 'main' | 'section';
650
+ /** Semantic elements supported by the scrolling content slot. */
651
+ type PaneContentElement = 'div' | 'main' | 'nav' | 'section';
652
+ type PaneRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
653
+ 'data-component'?: never;
654
+ 'data-separator-block-start'?: never;
655
+ 'data-separator-block-end'?: never;
656
+ 'data-separator-inline-start'?: never;
657
+ 'data-separator-inline-end'?: never;
658
+ }>;
659
+ interface PaneProps {
660
+ /** Optional fixed chrome above the scrolling content, arranged vertically. */
661
+ header?: SafeHtml | readonly SafeHtml[];
662
+ /** The pane's primary vertical, scrolling content stack. */
663
+ children?: SafeHtml | readonly SafeHtml[];
664
+ /** Optional fixed chrome below the scrolling content. */
665
+ footer?: SafeHtml | readonly SafeHtml[];
666
+ /** Root semantics. Defaults to `div`. */
667
+ element?: PaneElement;
668
+ /** Scrolling content semantics. Defaults to `div`. */
669
+ contentElement?: PaneContentElement;
670
+ /** Independent logical-edge separator lines. Defaults to none. */
671
+ separators?: readonly PaneSeparatorSide[];
672
+ id?: string;
673
+ /** Accessible name for a landmark root such as `aside` or `main`. */
674
+ label?: string;
675
+ /** Accessible name for a landmark scrolling slot such as `nav`. */
676
+ contentLabel?: string;
677
+ className?: string;
678
+ headerClassName?: string;
679
+ contentClassName?: string;
680
+ footerClassName?: string;
681
+ /** Safe `data-*` metadata; Pane-owned structural attributes remain protected. */
682
+ rootAttributes?: PaneRootAttributes;
683
+ }
684
+ /**
685
+ * An unpadded application column with optional fixed header/footer slots and one
686
+ * scrolling vertical content owner. Separator lines are independently opt-in on
687
+ * each logical edge, so the same component works as a sidebar, main area,
688
+ * inspector, or dialog column.
689
+ */
690
+ declare function Pane({ header, children, footer, element, contentElement, separators, id, label, contentLabel, className, headerClassName, contentClassName, footerClassName, rootAttributes, }: PaneProps): SafeHtml;
691
+
692
+ export { Pane, type PaneContentElement, type PaneElement, type PaneProps, type PaneSeparatorSide };
693
+ ```
694
+
607
695
  ## `@kerfjs/ui/workbench`
608
696
 
609
697
  ```ts
@@ -637,7 +725,7 @@ interface WorkbenchProps {
637
725
  * work area relayouts once, not per frame. The app owns each `collapsed` flag;
638
726
  * the collapse is pure CSS (no wire). See `docs/23-app-layouts.md` §3.3.
639
727
  */
640
- declare function Workbench({ id, label, main, leftRail, rightRail, bottomDrawer, className }: WorkbenchProps): SafeHtml;
728
+ declare function Workbench({ id, label, main, leftRail, rightRail, bottomDrawer, className, }: WorkbenchProps): SafeHtml;
641
729
 
642
730
  export { Workbench, type WorkbenchPanel, type WorkbenchProps };
643
731
  ```
@@ -682,7 +770,7 @@ interface CollapsiblePanelToggleProps {
682
770
  * put it in the panel's own header (to collapse) and somewhere always-visible
683
771
  * (to expand while collapsed).
684
772
  */
685
- declare function CollapsiblePanelToggle({ side, collapsed, action, panelId, label, className }: CollapsiblePanelToggleProps): SafeHtml;
773
+ declare function CollapsiblePanelToggle({ side, collapsed, action, panelId, label, className, }: CollapsiblePanelToggleProps): SafeHtml;
686
774
  interface CollapsiblePanelProps {
687
775
  /** A stable id for the panel — `wireSidebar` targets it and toggles reference it. */
688
776
  id: string;
@@ -708,7 +796,7 @@ interface CollapsiblePanelProps {
708
796
  * and persistence semantics, and with `CollapsiblePanelToggle` for the standard
709
797
  * affordance. See `docs/24-collapsible-panel.md`.
710
798
  */
711
- declare function CollapsiblePanel({ id, side, collapsed, size, label, children, className }: CollapsiblePanelProps): SafeHtml;
799
+ declare function CollapsiblePanel({ id, side, collapsed, size, label, children, className, }: CollapsiblePanelProps): SafeHtml;
712
800
 
713
801
  export { CollapsiblePanel, type CollapsiblePanelProps, type CollapsiblePanelSide, CollapsiblePanelToggle, type CollapsiblePanelToggleProps, collapsiblePanelToggleIcon };
714
802
  ```
@@ -766,21 +854,21 @@ export { type SidebarStorage, type WireSidebarOptions, type WireSidebarPanel, wi
766
854
  ```ts
767
855
  import { SafeHtml } from 'kerfjs';
768
856
 
769
- interface TabScaffoldTab {
770
- id: string;
857
+ interface TabScaffoldTab<Id extends string = string> {
858
+ id: Id;
771
859
  label: string;
772
860
  /** Decorative icon shown above the label in the bottom bar. */
773
861
  icon?: SafeHtml;
774
862
  /** The tab's content — typically a `NavStack` so each tab keeps its own stack. */
775
863
  content: SafeHtml;
776
864
  }
777
- interface TabScaffoldProps {
865
+ interface TabScaffoldProps<Id extends string = string> {
778
866
  id: string;
779
867
  /** Accessible name for the tab bar. */
780
868
  label: string;
781
- tabs: TabScaffoldTab[];
869
+ tabs: readonly TabScaffoldTab<Id>[];
782
870
  /** The controlled active tab id (the app owns selection). */
783
- active: string;
871
+ active: NoInfer<Id>;
784
872
  className?: string;
785
873
  }
786
874
  /**
@@ -791,7 +879,7 @@ interface TabScaffoldProps {
791
879
  * On larger classes, promote the tabs to a `Workbench` rail or sidebar instead of
792
880
  * a bottom bar. See `docs/23-app-layouts.md` §3.4.
793
881
  */
794
- declare function TabScaffold({ id, label, tabs, active, className }: TabScaffoldProps): SafeHtml;
882
+ declare function TabScaffold<Id extends string>({ id, label, tabs, active, className, }: TabScaffoldProps<Id>): SafeHtml;
795
883
 
796
884
  export { TabScaffold, type TabScaffoldProps, type TabScaffoldTab };
797
885
  ```
@@ -835,7 +923,7 @@ interface ResizableRegionProps {
835
923
  }
836
924
  declare const clampRegionSize: (size: number, min: number, max: number) => number;
837
925
  declare const resizeRegionFromPointer: (startSize: number, delta: number, edge: ResizableRegionEdge) => number;
838
- declare function ResizableRegion({ id, label, size, min, max, axis, edge, collapsed, transitioning, handleIcon, children }: ResizableRegionProps): SafeHtml;
926
+ declare function ResizableRegion({ id, label, size, min, max, axis, edge, collapsed, transitioning, handleIcon, children, }: ResizableRegionProps): SafeHtml;
839
927
 
840
928
  export { ResizableRegion, type ResizableRegionAxis, type ResizableRegionEdge, type ResizableRegionProps, clampRegionSize, resizeRegionFromPointer };
841
929
  ```
@@ -855,7 +943,7 @@ interface WireResizableRegionsOptions {
855
943
  onCommit: (change: ResizeCommit) => void;
856
944
  }
857
945
  /** Wire pointer and separator-keyboard behavior for every ResizableRegion below root. */
858
- declare function wireResizableRegions(root: HTMLElement, { step, largeStep, onPreview, onCommit }: WireResizableRegionsOptions): () => void;
946
+ declare function wireResizableRegions(root: HTMLElement, { step, largeStep, onPreview, onCommit, }: WireResizableRegionsOptions): () => void;
859
947
 
860
948
  export { type ResizeCommit, type WireResizableRegionsOptions, wireResizableRegions };
861
949
  ```
@@ -998,6 +1086,13 @@ interface CatalogProps {
998
1086
  sidebarFooter?: SafeHtml;
999
1087
  /** Status line content shown at the start of the detail footer. */
1000
1088
  status?: SafeHtml;
1089
+ /**
1090
+ * Whether to highlight transparent specimens' outer bounds and non-zero
1091
+ * margins. Pass a boolean (rather than omitting the prop) when the active
1092
+ * entry can switch between component and composition previews;
1093
+ * `wireCatalogGeometryOverlay` keeps the overlay synchronized.
1094
+ */
1095
+ geometryOverlay?: boolean;
1001
1096
  selectAction?: string;
1002
1097
  toggleSidebarAction?: string;
1003
1098
  toggleThemeAction?: string;
@@ -1013,7 +1108,7 @@ interface CatalogProps {
1013
1108
  * `collapsed`, and `theme` signals and computes `content` from `active` in its own
1014
1109
  * render; wire the sidebar/collapse/theme actions with `wireCatalog`.
1015
1110
  */
1016
- declare function Catalog({ brand, sections, active, content, collapsed, theme, headerActions, secondarySections, sidebarFooter, status, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, className, }: CatalogProps): SafeHtml;
1111
+ declare function Catalog({ brand, sections, active, content, collapsed, theme, headerActions, secondarySections, sidebarFooter, status, geometryOverlay, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, className, }: CatalogProps): SafeHtml;
1017
1112
  /**
1018
1113
  * How a {@link CatalogExample}'s content aligns its visible left edge with the
1019
1114
  * example's `ListHeader` label (which sits 16px in — 8px title + 8px label):
@@ -1022,6 +1117,16 @@ declare function Catalog({ brand, sections, active, content, collapsed, theme, h
1022
1117
  * - `'none'` — a content-item / composition that owns its geometry and already aligns; no inset (default).
1023
1118
  */
1024
1119
  type CatalogExampleAlign = 'glyph' | 'inline-control' | 'none';
1120
+ type CatalogExampleRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
1121
+ 'data-catalog-example'?: never;
1122
+ 'data-catalog-example-stack'?: never;
1123
+ 'data-align'?: never;
1124
+ }>;
1125
+ type CatalogExampleStackRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
1126
+ 'data-catalog-example'?: never;
1127
+ 'data-catalog-example-stack'?: never;
1128
+ 'data-align'?: never;
1129
+ }>;
1025
1130
  interface CatalogExampleProps {
1026
1131
  /** The example's label, shown as a `ListHeader` above the specimen. Omit for a bare specimen. */
1027
1132
  label?: string;
@@ -1029,6 +1134,8 @@ interface CatalogExampleProps {
1029
1134
  note?: SafeHtml | string;
1030
1135
  /** Alignment inset for the specimen — see {@link CatalogExampleAlign}. Default `'none'`. */
1031
1136
  align?: CatalogExampleAlign;
1137
+ /** Safe authoring `data-*` metadata for the rendered section. Helper-owned structural attributes remain protected. */
1138
+ rootAttributes?: CatalogExampleRootAttributes;
1032
1139
  className?: string;
1033
1140
  children?: SafeHtml | readonly SafeHtml[];
1034
1141
  }
@@ -1040,19 +1147,64 @@ interface CatalogExampleProps {
1040
1147
  * `--kui-catalog-example-align` custom property so a debug overlay can exclude it
1041
1148
  * from a specimen's measured margin.
1042
1149
  */
1043
- declare function CatalogExample({ label, note, align, className, children }: CatalogExampleProps): SafeHtml;
1150
+ declare function CatalogExample({ label, note, align, rootAttributes, className, children, }: CatalogExampleProps): SafeHtml;
1044
1151
  interface CatalogExampleStackProps {
1045
1152
  /** Accessible label for the stack region. */
1046
1153
  label?: string;
1154
+ /** Safe authoring `data-*` metadata for the rendered stack. Helper-owned structural attributes remain protected. */
1155
+ rootAttributes?: CatalogExampleStackRootAttributes;
1047
1156
  className?: string;
1048
1157
  children?: SafeHtml | readonly SafeHtml[];
1049
1158
  }
1050
- /** A vertically-stacked group of {@link CatalogExample}s with the catalog's example rhythm. */
1051
- declare function CatalogExampleStack({ label, className, children }: CatalogExampleStackProps): SafeHtml;
1159
+ /**
1160
+ * A vertically-stacked group of {@link CatalogExample}s with the catalog's
1161
+ * example rhythm. The semantic `section` becomes a named `region` when `label`
1162
+ * is supplied; an unlabeled stack remains an ordinary grouping.
1163
+ */
1164
+ declare function CatalogExampleStack({ label, rootAttributes, className, children, }: CatalogExampleStackProps): SafeHtml;
1052
1165
 
1053
1166
  export { Catalog, type CatalogBrand, type CatalogEntry, CatalogExample, type CatalogExampleAlign, type CatalogExampleProps, CatalogExampleStack, type CatalogExampleStackProps, type CatalogProps, type CatalogRelated, type CatalogResource, type CatalogSecondaryGroup, type CatalogSection };
1054
1167
  ```
1055
1168
 
1169
+ ## `@kerfjs/ui/catalog-resources`
1170
+
1171
+ ```ts
1172
+ import { CatalogResource } from './catalog.js';
1173
+ import 'kerfjs';
1174
+
1175
+ /**
1176
+ * Standard resource labels for a Kerf catalog detail footer. Keep these labels
1177
+ * stable across catalogs so people and AI-generated integrations see the same
1178
+ * choices in the same vocabulary.
1179
+ */
1180
+ type CatalogResourceKind = 'demoSource' | 'componentSource' | 'designTemplate' | 'guidance' | 'integrationGuidance';
1181
+ type CatalogGuidanceKind = 'guidance' | 'integrationGuidance';
1182
+ interface CatalogResourceTarget {
1183
+ href: string;
1184
+ /** Optional monospace detail, normally the repository-relative source path. */
1185
+ detail?: string;
1186
+ }
1187
+ interface CatalogResourcesInput {
1188
+ /** Required source for the runnable demonstration. */
1189
+ demoSource: CatalogResourceTarget;
1190
+ /** Source for the production component; omit for recipes and integrations. */
1191
+ componentSource?: CatalogResourceTarget;
1192
+ /** Optional design-tool template associated with the component. */
1193
+ designTemplate?: CatalogResourceTarget;
1194
+ /** Required UI or integration guidance. */
1195
+ guidance: CatalogResourceTarget;
1196
+ /** Use `integrationGuidance` when the component implementation is upstream. */
1197
+ guidanceKind?: CatalogGuidanceKind;
1198
+ }
1199
+ /**
1200
+ * Build the standard catalog resource group in its canonical order: demo,
1201
+ * component, optional design template, then guidance.
1202
+ */
1203
+ declare function catalogResources(input: CatalogResourcesInput): CatalogResource[];
1204
+
1205
+ export { type CatalogGuidanceKind, type CatalogResourceKind, type CatalogResourceTarget, type CatalogResourcesInput, catalogResources };
1206
+ ```
1207
+
1056
1208
  ## `@kerfjs/ui/wire-catalog`
1057
1209
 
1058
1210
  ```ts
@@ -1067,11 +1219,40 @@ interface WireCatalogOptions {
1067
1219
  onToggleSecondary?: () => void;
1068
1220
  /** When set, `?<urlParam>=<id>` is written on select via `history.replaceState`. */
1069
1221
  urlParam?: string;
1222
+ /**
1223
+ * Reveal the chosen sidebar row after selection. `true` uses desktop-safe
1224
+ * defaults; pass options to customize scroll alignment or the media guard.
1225
+ */
1226
+ revealSelection?: boolean | CatalogRevealOptions;
1070
1227
  selectAction?: string;
1071
1228
  toggleSidebarAction?: string;
1072
1229
  toggleThemeAction?: string;
1073
1230
  toggleSecondaryAction?: string;
1074
1231
  }
1232
+ interface CatalogRevealOptions {
1233
+ /** Scroll alignment within the sidebar. Default `'nearest'`. */
1234
+ block?: ScrollLogicalPosition;
1235
+ /** Cross-axis alignment. Default `'nearest'`. */
1236
+ inline?: ScrollLogicalPosition;
1237
+ /** Scroll behavior. Default `'auto'`. */
1238
+ behavior?: ScrollBehavior;
1239
+ /**
1240
+ * Only reveal when this media query matches. Defaults to the Catalog's
1241
+ * desktop layout; pass `false` to reveal at every viewport size.
1242
+ */
1243
+ media?: string | false;
1244
+ }
1245
+ /**
1246
+ * Reveal one Catalog sidebar entry after the controlled render settles without
1247
+ * moving focus. Returns a cancellation function for rapid selection changes.
1248
+ */
1249
+ declare function revealCatalogEntry(root: HTMLElement, id: string, { block, inline, behavior, media, }?: CatalogRevealOptions): () => void;
1250
+ /**
1251
+ * Keep a Catalog's opt-in geometry overlay synchronized with its preview.
1252
+ * Transparent specimens receive a dashed outer bound and positive margins use
1253
+ * devtools-style orange bands. Returns a disposer.
1254
+ */
1255
+ declare function wireCatalogGeometryOverlay(root: HTMLElement): () => void;
1075
1256
  /**
1076
1257
  * Wire a {@link Catalog}'s interactions with one delegated listener set: sidebar
1077
1258
  * item selection (and the related-entry popup menu), the sidebar collapse toggle, and
@@ -1079,9 +1260,9 @@ interface WireCatalogOptions {
1079
1260
  * them in the callbacks; optionally mirror the active id into the URL via `urlParam`.
1080
1261
  * Returns a disposer.
1081
1262
  */
1082
- declare function wireCatalog(root: HTMLElement, { onSelect, onToggleSidebar, onToggleTheme, onToggleSecondary, urlParam, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, }: WireCatalogOptions): () => void;
1263
+ declare function wireCatalog(root: HTMLElement, { onSelect, onToggleSidebar, onToggleTheme, onToggleSecondary, urlParam, revealSelection, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, }: WireCatalogOptions): () => void;
1083
1264
 
1084
- export { type WireCatalogOptions, wireCatalog };
1265
+ export { type CatalogRevealOptions, type WireCatalogOptions, revealCatalogEntry, wireCatalog, wireCatalogGeometryOverlay };
1085
1266
  ```
1086
1267
 
1087
1268
  ## `@kerfjs/ui/segmented-control`
@@ -1093,18 +1274,18 @@ type SegmentedControlAppearance = 'filled' | 'outlined' | 'toolbar';
1093
1274
  type SegmentedControlShape = 'rounded' | 'pill';
1094
1275
  type SegmentedControlSize = 'small' | 'default';
1095
1276
  type SegmentedControlLayout = 'content' | 'equal';
1096
- interface SegmentedControlChoice {
1097
- value: string;
1277
+ interface SegmentedControlChoice<Value extends string = string> {
1278
+ value: Value;
1098
1279
  label: string;
1099
1280
  content?: SafeHtml;
1100
1281
  title?: string;
1101
1282
  disabled?: boolean;
1102
1283
  }
1103
- interface SegmentedControlProps {
1284
+ interface SegmentedControlProps<Value extends string = string> {
1104
1285
  id: string;
1105
1286
  label: string;
1106
- value: string;
1107
- choices: readonly SegmentedControlChoice[];
1287
+ value: NoInfer<Value>;
1288
+ choices: readonly SegmentedControlChoice<Value>[];
1108
1289
  action?: string;
1109
1290
  appearance?: SegmentedControlAppearance;
1110
1291
  shape?: SegmentedControlShape;
@@ -1114,31 +1295,74 @@ interface SegmentedControlProps {
1114
1295
  /** Render as an unanimated loading skeleton, disabling every segment. */
1115
1296
  placeholder?: boolean;
1116
1297
  }
1117
- declare function SegmentedControl({ id, label, value, choices, action, appearance, shape, size, layout, className, placeholder, }: SegmentedControlProps): SafeHtml;
1298
+ declare function SegmentedControl<Value extends string>({ id, label, value, choices, action, appearance, shape, size, layout, className, placeholder, }: SegmentedControlProps<Value>): SafeHtml;
1118
1299
 
1119
1300
  export { SegmentedControl, type SegmentedControlAppearance, type SegmentedControlChoice, type SegmentedControlLayout, type SegmentedControlProps, type SegmentedControlShape, type SegmentedControlSize };
1120
1301
  ```
1121
1302
 
1303
+ ## `@kerfjs/ui/select`
1304
+
1305
+ ```ts
1306
+ import { SafeHtml } from 'kerfjs';
1307
+ import { LucideNode } from './lucide-icon.js';
1308
+ import 'lucide';
1309
+
1310
+ interface SelectChoice<Value extends string = string> {
1311
+ value: Value;
1312
+ label: string;
1313
+ icon?: LucideNode;
1314
+ iconName?: string;
1315
+ color?: string;
1316
+ group?: string;
1317
+ separatorBefore?: boolean;
1318
+ }
1319
+ type SelectAccessibleName = {
1320
+ label: string;
1321
+ ariaLabel?: string;
1322
+ } | {
1323
+ label?: never;
1324
+ ariaLabel: string;
1325
+ };
1326
+ interface SelectBaseProps<Value extends string = string> {
1327
+ name: string;
1328
+ value: NoInfer<Value>;
1329
+ choices: readonly SelectChoice<Value>[];
1330
+ className?: string;
1331
+ /** Empty-value hint text shown in the closed control (the native select placeholder). */
1332
+ placeholderText?: string;
1333
+ disabled?: boolean;
1334
+ fitMenu?: boolean;
1335
+ renderSelected?: (choice: SelectChoice<Value>) => SafeHtml;
1336
+ /** Render as an unanimated loading skeleton: the label above a static, empty control box. */
1337
+ placeholder?: boolean;
1338
+ }
1339
+ type SelectProps<Value extends string = string> = SelectBaseProps<Value> & SelectAccessibleName;
1340
+ declare function Select<Value extends string>({ name, value, label, ariaLabel, choices, className, placeholderText, disabled, fitMenu, renderSelected, placeholder, }: SelectProps<Value>): SafeHtml;
1341
+
1342
+ export { Select, type SelectChoice, type SelectProps };
1343
+ ```
1344
+
1122
1345
  ## `@kerfjs/ui/state-banner`
1123
1346
 
1124
1347
  ```ts
1125
1348
  import { SafeHtml } from 'kerfjs';
1126
1349
 
1127
1350
  type StateBannerTone = 'neutral' | 'info' | 'success' | 'warning' | 'danger';
1351
+ type StateBannerUrgency = 'status' | 'alert';
1128
1352
  interface StateBannerProps {
1129
1353
  title: string;
1130
1354
  detail?: string;
1131
1355
  icon?: SafeHtml;
1132
1356
  action?: SafeHtml;
1133
1357
  tone?: StateBannerTone;
1134
- urgency?: 'status' | 'alert';
1358
+ urgency?: StateBannerUrgency;
1135
1359
  className?: string;
1136
1360
  /** Render the title and detail as unanimated loading skeletons, keeping the icon and tone. */
1137
1361
  placeholder?: boolean;
1138
1362
  }
1139
- declare function StateBanner({ title, detail, icon, action, tone, urgency, className, placeholder }: StateBannerProps): SafeHtml;
1363
+ declare function StateBanner({ title, detail, icon, action, tone, urgency, className, placeholder, }: StateBannerProps): SafeHtml;
1140
1364
 
1141
- export { StateBanner, type StateBannerProps, type StateBannerTone };
1365
+ export { StateBanner, type StateBannerProps, type StateBannerTone, type StateBannerUrgency };
1142
1366
  ```
1143
1367
 
1144
1368
  ## `@kerfjs/ui/empty-state`
@@ -1154,7 +1378,7 @@ interface EmptyStateProps {
1154
1378
  busy?: boolean;
1155
1379
  className?: string;
1156
1380
  }
1157
- declare function EmptyState({ title, detail, icon, action, busy, className }: EmptyStateProps): SafeHtml;
1381
+ declare function EmptyState({ title, detail, icon, action, busy, className, }: EmptyStateProps): SafeHtml;
1158
1382
 
1159
1383
  export { EmptyState, type EmptyStateProps };
1160
1384
  ```
@@ -1198,11 +1422,32 @@ interface SkeletonProps {
1198
1422
  * `placeholder` prop. Decorative by default (`aria-hidden`); pass `label` to
1199
1423
  * announce it. Sizes to its slot unless `width`/`height` are given.
1200
1424
  */
1201
- declare function Skeleton({ width, height, radius, lines, label, className }: SkeletonProps): kerfjs.SafeHtml;
1425
+ declare function Skeleton({ width, height, radius, lines, label, className, }: SkeletonProps): kerfjs.SafeHtml;
1202
1426
 
1203
1427
  export { Skeleton, type SkeletonProps };
1204
1428
  ```
1205
1429
 
1430
+ ## `@kerfjs/ui/sunken-panel`
1431
+
1432
+ ```ts
1433
+ import { SafeHtml } from 'kerfjs';
1434
+
1435
+ interface SunkenPanelProps {
1436
+ children?: SafeHtml | readonly SafeHtml[];
1437
+ /** Optional accessible landmark name for a distinct application region. */
1438
+ ariaLabel?: string;
1439
+ className?: string;
1440
+ }
1441
+ /**
1442
+ * A lowered application surface with one compact inset and a vertical content
1443
+ * stack. The panel owns its background and padding; children own their own
1444
+ * borders and internal geometry.
1445
+ */
1446
+ declare function SunkenPanel({ children, ariaLabel, className, }: SunkenPanelProps): SafeHtml;
1447
+
1448
+ export { SunkenPanel, type SunkenPanelProps };
1449
+ ```
1450
+
1206
1451
  ## `@kerfjs/ui/token-search-field`
1207
1452
 
1208
1453
  ```ts
@@ -1214,7 +1459,15 @@ interface TokenSearchToken {
1214
1459
  offset?: number;
1215
1460
  accessibleLabel?: string;
1216
1461
  }
1217
- interface TokenSearchFieldProps {
1462
+ type TokenSearchEditorAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
1463
+ 'data-component'?: never;
1464
+ 'data-key'?: never;
1465
+ 'data-morph-skip'?: never;
1466
+ 'data-token-search-editor'?: never;
1467
+ 'data-token-count'?: never;
1468
+ 'data-placeholder'?: never;
1469
+ }>;
1470
+ interface TokenSearchFieldBaseProps {
1218
1471
  id: string;
1219
1472
  label: string;
1220
1473
  query?: string;
@@ -1223,12 +1476,6 @@ interface TokenSearchFieldProps {
1223
1476
  tokenPlaceholder?: string;
1224
1477
  disabled?: boolean;
1225
1478
  autofocus?: boolean;
1226
- /** Allow an empty field to render as one iconic action. */
1227
- collapsible?: boolean;
1228
- /** Keep an empty collapsible field open while the application owns focus. */
1229
- expanded?: boolean;
1230
- expandAction?: string;
1231
- expandLabel?: string;
1232
1479
  leading?: SafeHtml;
1233
1480
  trailing?: SafeHtml;
1234
1481
  editAction?: string;
@@ -1236,8 +1483,22 @@ interface TokenSearchFieldProps {
1236
1483
  clearAction?: string;
1237
1484
  clearLabel?: string;
1238
1485
  className?: string;
1239
- editorAttributes?: Readonly<Record<`data-${string}`, string>>;
1486
+ editorAttributes?: TokenSearchEditorAttributes;
1240
1487
  }
1488
+ type TokenSearchCollapsibleProps = {
1489
+ /** Allow an empty field to render as one iconic action. */
1490
+ collapsible: true;
1491
+ /** Keep an empty collapsible field open while the application owns focus. */
1492
+ expanded?: boolean;
1493
+ expandAction?: string;
1494
+ expandLabel?: string;
1495
+ } | {
1496
+ collapsible?: false;
1497
+ expanded?: never;
1498
+ expandAction?: never;
1499
+ expandLabel?: never;
1500
+ };
1501
+ type TokenSearchFieldProps = TokenSearchFieldBaseProps & TokenSearchCollapsibleProps;
1241
1502
  interface TokenSearchFieldValue {
1242
1503
  query: string;
1243
1504
  tokens: TokenSearchToken[];
@@ -1248,7 +1509,7 @@ declare function readTokenSearchField(editor: HTMLElement, knownTokens?: readonl
1248
1509
  /** Focus an editor and place its caret at a text offset, skipping atomic token chips. */
1249
1510
  declare function placeTokenSearchCaret(editor: HTMLElement, offset?: number): void;
1250
1511
 
1251
- export { TokenSearchField, type TokenSearchFieldProps, type TokenSearchFieldValue, type TokenSearchToken, placeTokenSearchCaret, readTokenSearchField };
1512
+ export { type TokenSearchEditorAttributes, TokenSearchField, type TokenSearchFieldProps, type TokenSearchFieldValue, type TokenSearchToken, placeTokenSearchCaret, readTokenSearchField };
1252
1513
  ```
1253
1514
 
1254
1515
  ## `@kerfjs/ui/wire-token-search-fields`
@@ -1285,21 +1546,26 @@ interface TokenSearchTokenRemoval {
1285
1546
  * for the caller to apply, while caret movement past a chip is a pure ephemeral
1286
1547
  * mechanic the helper performs itself.
1287
1548
  */
1288
- interface TokenSearchKeyboardOptions {
1549
+ interface TokenSearchKeyboardBaseOptions {
1289
1550
  /**
1290
1551
  * From a collapsed caret with no selection, Backspace removes the token
1291
1552
  * immediately before it and Delete the token immediately after — reported via
1292
1553
  * `onRemoveToken` — instead of deleting a character. Default: true.
1293
1554
  */
1294
- removeAdjacentToken?: boolean;
1295
1555
  /**
1296
1556
  * ArrowRight moves the caret past a trailing atomic token so text typed next
1297
1557
  * lands after the chip. Default: true.
1298
1558
  */
1299
1559
  moveCaretPastToken?: boolean;
1300
- /** Apply the reported removal to your controlled state, then re-render. */
1301
- onRemoveToken?: (removal: TokenSearchTokenRemoval) => void;
1302
1560
  }
1561
+ type TokenSearchKeyboardOptions = TokenSearchKeyboardBaseOptions & ({
1562
+ removeAdjacentToken?: true;
1563
+ /** Apply the reported removal to your controlled state, then re-render. */
1564
+ onRemoveToken: (removal: TokenSearchTokenRemoval) => void;
1565
+ } | {
1566
+ removeAdjacentToken: false;
1567
+ onRemoveToken?: never;
1568
+ });
1303
1569
  /**
1304
1570
  * Managed collapsible behavior for the iconic TokenSearchField. Every piece is on
1305
1571
  * by default; disable a specific one to own it in the app. Provide `signals` to
@@ -1332,8 +1598,8 @@ interface WireTokenSearchFieldsOptions {
1332
1598
  onEdit?: (edit: TokenSearchEdit) => void;
1333
1599
  /** Managed collapsible transient behavior. `true`/omitted = on with defaults; `false` = fully off. */
1334
1600
  collapsible?: boolean | TokenSearchCollapsibleOptions;
1335
- /** Opt-in atomic-chip keyboard behavior (off by default). `true` = on with defaults. */
1336
- keyboard?: boolean | TokenSearchKeyboardOptions;
1601
+ /** Opt-in atomic-chip keyboard behavior (off by default). */
1602
+ keyboard?: false | TokenSearchKeyboardOptions;
1337
1603
  }
1338
1604
  /**
1339
1605
  * The value returned from {@link wireTokenSearchFields}: call it (or `dispose()`) to
@@ -1357,7 +1623,7 @@ interface TokenSearchFieldsHandle {
1357
1623
  * expand/collapse/focus. Returns a {@link TokenSearchFieldsHandle} — a disposer that also
1358
1624
  * exposes the managed `expanded` state per field id.
1359
1625
  */
1360
- declare function wireTokenSearchFields(root: HTMLElement, { onSubmit, onEdit, collapsible, keyboard }?: WireTokenSearchFieldsOptions): TokenSearchFieldsHandle;
1626
+ declare function wireTokenSearchFields(root: HTMLElement, { onSubmit, onEdit, collapsible, keyboard, }?: WireTokenSearchFieldsOptions): TokenSearchFieldsHandle;
1361
1627
 
1362
1628
  export { type TokenSearchCollapsibleOptions, type TokenSearchEdit, type TokenSearchFieldsHandle, type TokenSearchKeyboardOptions, type TokenSearchSubmit, type TokenSearchTokenRemoval, type WireTokenSearchFieldsOptions, wireTokenSearchFields };
1363
1629
  ```