@kerfjs/ui 5.0.0-beta.6 → 5.0.0-beta.60

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 (706) hide show
  1. package/README.md +493 -138
  2. package/ai/application-ui-diagnostic-ids-v1.json +109 -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 +96 -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 +36 -0
  10. package/ai/catalog-authoring.schema.json +109 -0
  11. package/ai/compile-time-contracts-v1.json +149 -0
  12. package/ai/compile-time-contracts-v1.schema.json +52 -0
  13. package/ai/component-catalog-extension.schema.json +79 -0
  14. package/ai/component-catalog.json +3947 -607
  15. package/ai/component-catalog.schema.json +78 -1
  16. package/ai/component-class-owners.cjs +83 -0
  17. package/ai/component-composition-extension.d.ts +7 -0
  18. package/ai/component-composition-extension.schema.json +7 -0
  19. package/ai/component-composition-rules.json +516 -0
  20. package/ai/component-composition.d.ts +115 -0
  21. package/ai/component-composition.json +6972 -0
  22. package/ai/component-composition.schema.json +354 -0
  23. package/ai/components/README.md +170 -0
  24. package/ai/components/application-tabs.md +65 -0
  25. package/ai/components/badge.md +72 -0
  26. package/ai/components/collapsible-panel.md +102 -0
  27. package/ai/components/content-item.md +90 -0
  28. package/ai/components/disclosure-arrow.md +77 -0
  29. package/ai/components/document-baseline.md +75 -0
  30. package/ai/components/empty-state.md +80 -0
  31. package/ai/components/feedback.md +71 -0
  32. package/ai/components/floating-toolbar.md +82 -0
  33. package/ai/components/foundation.md +65 -0
  34. package/ai/components/grid.md +93 -0
  35. package/ai/components/headers.md +63 -0
  36. package/ai/components/layout.md +75 -0
  37. package/ai/components/list-action-row.md +91 -0
  38. package/ai/components/list-header.md +89 -0
  39. package/ai/components/list-inset-control.md +74 -0
  40. package/ai/components/list-inset-text.md +72 -0
  41. package/ai/components/list-item.md +91 -0
  42. package/ai/components/list.md +103 -0
  43. package/ai/components/loading-spinner.md +72 -0
  44. package/ai/components/lucide-icon.md +66 -0
  45. package/ai/components/nav-stack.md +103 -0
  46. package/ai/components/pane.md +100 -0
  47. package/ai/components/popup-menu.md +171 -0
  48. package/ai/components/recipe-app-shell.md +57 -0
  49. package/ai/components/recipe-collapsible-sidebar.md +57 -0
  50. package/ai/components/recipe-compact-toolbar.md +57 -0
  51. package/ai/components/recipe-composer-form.md +57 -0
  52. package/ai/components/recipe-list-detail-dialog.md +57 -0
  53. package/ai/components/recipe-list-workspace-states.md +57 -0
  54. package/ai/components/recipe-loading-inspector.md +57 -0
  55. package/ai/components/recipe-navigation-sidebar.md +57 -0
  56. package/ai/components/recipe-navigation-stack.md +57 -0
  57. package/ai/components/recipe-workspace-header.md +57 -0
  58. package/ai/components/resize.md +106 -0
  59. package/ai/components/row.md +96 -0
  60. package/ai/components/segmented-control.md +82 -0
  61. package/ai/components/select.md +109 -0
  62. package/ai/components/skeleton.md +84 -0
  63. package/ai/components/spacer.md +86 -0
  64. package/ai/components/split-view.md +102 -0
  65. package/ai/components/state-banner.md +94 -0
  66. package/ai/components/sunken-panel.md +79 -0
  67. package/ai/components/surface-scaffold.md +78 -0
  68. package/ai/components/tab-bar.md +112 -0
  69. package/ai/components/tab-scaffold.md +94 -0
  70. package/ai/components/tabs.md +91 -0
  71. package/ai/components/text.md +83 -0
  72. package/ai/components/token-search-field.md +103 -0
  73. package/ai/components/toolbar-control-group.md +102 -0
  74. package/ai/components/toolbar-text.md +78 -0
  75. package/ai/components/toolbar.md +96 -0
  76. package/ai/components/value-table.md +73 -0
  77. package/ai/components/wa-accordion-item.md +55 -0
  78. package/ai/components/wa-accordion.md +65 -0
  79. package/ai/components/wa-animated-image.md +55 -0
  80. package/ai/components/wa-animation.md +55 -0
  81. package/ai/components/wa-avatar.md +55 -0
  82. package/ai/components/wa-badge.md +55 -0
  83. package/ai/components/wa-breadcrumb-item.md +53 -0
  84. package/ai/components/wa-breadcrumb.md +55 -0
  85. package/ai/components/wa-button-group.md +59 -0
  86. package/ai/components/wa-button.md +55 -0
  87. package/ai/components/wa-callout.md +58 -0
  88. package/ai/components/wa-card.md +59 -0
  89. package/ai/components/wa-carousel-item.md +53 -0
  90. package/ai/components/wa-carousel.md +55 -0
  91. package/ai/components/wa-checkbox-group.md +55 -0
  92. package/ai/components/wa-checkbox.md +55 -0
  93. package/ai/components/wa-color-picker.md +55 -0
  94. package/ai/components/wa-comparison.md +55 -0
  95. package/ai/components/wa-copy-button.md +55 -0
  96. package/ai/components/wa-details.md +61 -0
  97. package/ai/components/wa-dialog.md +59 -0
  98. package/ai/components/wa-divider.md +53 -0
  99. package/ai/components/wa-drawer.md +55 -0
  100. package/ai/components/wa-dropdown-item.md +60 -0
  101. package/ai/components/wa-dropdown.md +60 -0
  102. package/ai/components/wa-format-bytes.md +53 -0
  103. package/ai/components/wa-format-date.md +53 -0
  104. package/ai/components/wa-format-number.md +53 -0
  105. package/ai/components/wa-icon.md +58 -0
  106. package/ai/components/wa-include.md +53 -0
  107. package/ai/components/wa-input.md +59 -0
  108. package/ai/components/wa-intersection-observer.md +53 -0
  109. package/ai/components/wa-known-date.md +53 -0
  110. package/ai/components/wa-markdown.md +53 -0
  111. package/ai/components/wa-mutation-observer.md +53 -0
  112. package/ai/components/wa-number-input.md +55 -0
  113. package/ai/components/wa-option.md +59 -0
  114. package/ai/components/wa-otp-input.md +53 -0
  115. package/ai/components/wa-page.md +53 -0
  116. package/ai/components/wa-pagination.md +55 -0
  117. package/ai/components/wa-popover.md +55 -0
  118. package/ai/components/wa-popup.md +53 -0
  119. package/ai/components/wa-progress-bar.md +53 -0
  120. package/ai/components/wa-progress-ring.md +53 -0
  121. package/ai/components/wa-qr-code.md +53 -0
  122. package/ai/components/wa-radio-group.md +59 -0
  123. package/ai/components/wa-radio.md +55 -0
  124. package/ai/components/wa-random-content.md +53 -0
  125. package/ai/components/wa-rating.md +55 -0
  126. package/ai/components/wa-relative-time.md +53 -0
  127. package/ai/components/wa-resize-observer.md +53 -0
  128. package/ai/components/wa-scroller.md +53 -0
  129. package/ai/components/wa-select.md +63 -0
  130. package/ai/components/wa-skeleton.md +53 -0
  131. package/ai/components/wa-slider.md +55 -0
  132. package/ai/components/wa-spinner.md +58 -0
  133. package/ai/components/wa-split-panel.md +58 -0
  134. package/ai/components/wa-switch.md +53 -0
  135. package/ai/components/wa-tab-group.md +69 -0
  136. package/ai/components/wa-tab-panel.md +60 -0
  137. package/ai/components/wa-tab.md +59 -0
  138. package/ai/components/wa-tag.md +59 -0
  139. package/ai/components/wa-textarea.md +53 -0
  140. package/ai/components/wa-time-input.md +55 -0
  141. package/ai/components/wa-toast-item.md +60 -0
  142. package/ai/components/wa-toast.md +60 -0
  143. package/ai/components/wa-tooltip.md +55 -0
  144. package/ai/components/wa-tree-item.md +55 -0
  145. package/ai/components/wa-tree.md +55 -0
  146. package/ai/components/wa-zoomable-frame.md +55 -0
  147. package/ai/components/workbench.md +114 -0
  148. package/ai/public-api-signatures-v1.md +2528 -197
  149. package/ai/skill.md +241 -65
  150. package/ai/webawesome-jsx-signatures-v1.md +9 -2
  151. package/analyzer/cli.mjs +49 -0
  152. package/analyzer/component-ownership.d.mts +56 -0
  153. package/analyzer/component-ownership.mjs +184 -0
  154. package/analyzer/index.d.mts +49 -0
  155. package/analyzer/index.mjs +1458 -0
  156. package/analyzer/loud-pairs.d.mts +49 -0
  157. package/analyzer/loud-pairs.mjs +357 -0
  158. package/analyzer/report.schema.json +66 -0
  159. package/analyzer/selectors.d.mts +21 -0
  160. package/analyzer/selectors.mjs +212 -0
  161. package/dist/app-tab.d.ts +31 -4
  162. package/dist/app-tab.js +3 -1
  163. package/dist/badge.d.ts +52 -0
  164. package/dist/badge.js +3 -0
  165. package/dist/badge.js.map +1 -0
  166. package/dist/browser/app-tab.js +1 -0
  167. package/dist/browser/badge.js +3 -0
  168. package/dist/browser/catalog.js +25 -0
  169. package/dist/browser/collapsible-panel.js +7 -0
  170. package/dist/browser/content-item.js +3 -0
  171. package/dist/browser/floating-toolbar.js +3 -0
  172. package/dist/browser/grid.js +3 -0
  173. package/dist/browser/list-action-row.js +5 -0
  174. package/dist/browser/list-header.js +8 -0
  175. package/dist/browser/list-inset-control.js +3 -0
  176. package/dist/browser/list-inset-text.js +3 -0
  177. package/dist/browser/list-item.js +5 -0
  178. package/dist/browser/list.js +3 -0
  179. package/dist/browser/{panel-header.js → nav-stack.js} +4 -2
  180. package/dist/browser/pane.js +3 -0
  181. package/dist/browser/popup-menu.js +3 -0
  182. package/dist/browser/row.js +3 -0
  183. package/dist/browser/select.js +2 -0
  184. package/dist/browser/skeleton.js +3 -0
  185. package/dist/browser/spacer.js +3 -0
  186. package/dist/browser/split-view.js +10 -0
  187. package/dist/browser/state-banner.js +2 -0
  188. package/dist/browser/sunken-panel.js +3 -0
  189. package/dist/browser/surface-scaffold.js +3 -0
  190. package/dist/browser/tab-scaffold.js +4 -0
  191. package/dist/browser/text.js +3 -0
  192. package/dist/browser/toolbar-text.js +1 -0
  193. package/dist/browser/value-table.js +1 -0
  194. package/dist/browser/workbench.js +10 -0
  195. package/dist/catalog-resources.d.ts +46 -0
  196. package/dist/catalog-resources.js +22 -0
  197. package/dist/catalog-resources.js.map +1 -0
  198. package/dist/catalog.d.ts +90 -0
  199. package/dist/catalog.js +501 -0
  200. package/dist/catalog.js.map +1 -0
  201. package/dist/chunk-2G2ZJQYK.js +152 -0
  202. package/dist/chunk-2G2ZJQYK.js.map +1 -0
  203. package/dist/chunk-2OXQHM7I.js +418 -0
  204. package/dist/chunk-2OXQHM7I.js.map +1 -0
  205. package/dist/chunk-3SXMEK3B.js +43 -0
  206. package/dist/chunk-3SXMEK3B.js.map +1 -0
  207. package/dist/{chunk-MQIZAD4A.js → chunk-46263QLK.js} +126 -22
  208. package/dist/chunk-46263QLK.js.map +1 -0
  209. package/dist/{chunk-W2FK7ZNY.js → chunk-4R777DUZ.js} +10 -2
  210. package/dist/chunk-4R777DUZ.js.map +1 -0
  211. package/dist/chunk-5I7OHCIP.js +96 -0
  212. package/dist/chunk-5I7OHCIP.js.map +1 -0
  213. package/dist/chunk-5I7QGQVT.js +24 -0
  214. package/dist/chunk-5I7QGQVT.js.map +1 -0
  215. package/dist/chunk-5PESG2VP.js +115 -0
  216. package/dist/chunk-5PESG2VP.js.map +1 -0
  217. package/dist/chunk-5Q3N6EV7.js +156 -0
  218. package/dist/chunk-5Q3N6EV7.js.map +1 -0
  219. package/dist/chunk-6ZXOQEAN.js +27 -0
  220. package/dist/chunk-6ZXOQEAN.js.map +1 -0
  221. package/dist/chunk-7JUBXOIV.js +103 -0
  222. package/dist/chunk-7JUBXOIV.js.map +1 -0
  223. package/dist/chunk-A3CKOW2R.js +622 -0
  224. package/dist/chunk-A3CKOW2R.js.map +1 -0
  225. package/dist/chunk-AGXQQFKZ.js +62 -0
  226. package/dist/chunk-AGXQQFKZ.js.map +1 -0
  227. package/dist/chunk-AHEG27M7.js +66 -0
  228. package/dist/chunk-AHEG27M7.js.map +1 -0
  229. package/dist/chunk-AUKT3KMG.js +37 -0
  230. package/dist/chunk-AUKT3KMG.js.map +1 -0
  231. package/dist/chunk-AYUHMAI6.js +48 -0
  232. package/dist/chunk-AYUHMAI6.js.map +1 -0
  233. package/dist/chunk-BFPBS5Y4.js +250 -0
  234. package/dist/chunk-BFPBS5Y4.js.map +1 -0
  235. package/dist/chunk-DG6G5EPF.js +35 -0
  236. package/dist/chunk-DG6G5EPF.js.map +1 -0
  237. package/dist/chunk-E36EVCKG.js +34 -0
  238. package/dist/chunk-E36EVCKG.js.map +1 -0
  239. package/dist/chunk-EZVNC4J6.js +104 -0
  240. package/dist/chunk-EZVNC4J6.js.map +1 -0
  241. package/dist/chunk-F4QMLOXJ.js +135 -0
  242. package/dist/chunk-F4QMLOXJ.js.map +1 -0
  243. package/dist/chunk-F7F7KRO2.js +187 -0
  244. package/dist/chunk-F7F7KRO2.js.map +1 -0
  245. package/dist/chunk-GLDWRCAM.js +49 -0
  246. package/dist/chunk-GLDWRCAM.js.map +1 -0
  247. package/dist/chunk-I3Q7KKYM.js +33 -0
  248. package/dist/chunk-I3Q7KKYM.js.map +1 -0
  249. package/dist/chunk-IA7TMD4Y.js +288 -0
  250. package/dist/chunk-IA7TMD4Y.js.map +1 -0
  251. package/dist/chunk-JCV4GXWB.js +249 -0
  252. package/dist/chunk-JCV4GXWB.js.map +1 -0
  253. package/dist/chunk-K47P7QZC.js +17 -0
  254. package/dist/chunk-K47P7QZC.js.map +1 -0
  255. package/dist/chunk-KLJKU6ZL.js +109 -0
  256. package/dist/chunk-KLJKU6ZL.js.map +1 -0
  257. package/dist/{chunk-56RJXPHG.js → chunk-KROD7KZK.js} +7 -4
  258. package/dist/chunk-KROD7KZK.js.map +1 -0
  259. package/dist/chunk-MA73TA6D.js +42 -0
  260. package/dist/chunk-MA73TA6D.js.map +1 -0
  261. package/dist/chunk-MERWRTBG.js +45 -0
  262. package/dist/chunk-MERWRTBG.js.map +1 -0
  263. package/dist/chunk-MEY33VWB.js +44 -0
  264. package/dist/chunk-MEY33VWB.js.map +1 -0
  265. package/dist/chunk-MP2GDBQZ.js +50 -0
  266. package/dist/chunk-MP2GDBQZ.js.map +1 -0
  267. package/dist/chunk-N3GKMPDW.js +51 -0
  268. package/dist/chunk-N3GKMPDW.js.map +1 -0
  269. package/dist/chunk-NAPE7WUS.js +75 -0
  270. package/dist/chunk-NAPE7WUS.js.map +1 -0
  271. package/dist/chunk-NN6GYOA2.js +47 -0
  272. package/dist/chunk-NN6GYOA2.js.map +1 -0
  273. package/dist/chunk-NNMLEDMD.js +399 -0
  274. package/dist/chunk-NNMLEDMD.js.map +1 -0
  275. package/dist/chunk-P7D3EMXM.js +52 -0
  276. package/dist/chunk-P7D3EMXM.js.map +1 -0
  277. package/dist/chunk-PSHUSWQH.js +18 -0
  278. package/dist/chunk-PSHUSWQH.js.map +1 -0
  279. package/dist/chunk-RRB26JRJ.js +247 -0
  280. package/dist/chunk-RRB26JRJ.js.map +1 -0
  281. package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
  282. package/dist/chunk-SRSJO5QE.js.map +1 -0
  283. package/dist/chunk-T57AXDFM.js +95 -0
  284. package/dist/chunk-T57AXDFM.js.map +1 -0
  285. package/dist/chunk-T66UNBXL.js +129 -0
  286. package/dist/chunk-T66UNBXL.js.map +1 -0
  287. package/dist/chunk-UIDKY4UB.js +14 -0
  288. package/dist/chunk-UIDKY4UB.js.map +1 -0
  289. package/dist/chunk-UWONG4QE.js +127 -0
  290. package/dist/chunk-UWONG4QE.js.map +1 -0
  291. package/dist/chunk-VZOFZPSO.js +71 -0
  292. package/dist/chunk-VZOFZPSO.js.map +1 -0
  293. package/dist/chunk-WPLIO5WJ.js +184 -0
  294. package/dist/chunk-WPLIO5WJ.js.map +1 -0
  295. package/dist/{chunk-TRNBHPNW.js → chunk-X5QSICJ3.js} +13 -7
  296. package/dist/chunk-X5QSICJ3.js.map +1 -0
  297. package/dist/chunk-ZLWQZUGF.js +27 -0
  298. package/dist/chunk-ZLWQZUGF.js.map +1 -0
  299. package/dist/collapsible-panel.d.ts +122 -0
  300. package/dist/collapsible-panel.js +115 -0
  301. package/dist/collapsible-panel.js.map +1 -0
  302. package/dist/content-item.d.ts +46 -0
  303. package/dist/content-item.js +4 -0
  304. package/dist/content-item.js.map +1 -0
  305. package/dist/css-values.d.ts +107 -0
  306. package/dist/css-values.js +3 -0
  307. package/dist/css-values.js.map +1 -0
  308. package/dist/device-class.js +33 -5
  309. package/dist/device-class.js.map +1 -1
  310. package/dist/disclosure-arrow.d.ts +6 -1
  311. package/dist/disclosure-arrow.js +1 -1
  312. package/dist/empty-state.d.ts +5 -2
  313. package/dist/empty-state.js +1 -1
  314. package/dist/flex-alignment-4ms8ZbV8.d.ts +5 -0
  315. package/dist/floating-toolbar.d.ts +51 -0
  316. package/dist/floating-toolbar.js +3 -0
  317. package/dist/floating-toolbar.js.map +1 -0
  318. package/dist/grid.d.ts +34 -0
  319. package/dist/grid.js +5 -0
  320. package/dist/grid.js.map +1 -0
  321. package/dist/help-tags-register.d.ts +13 -0
  322. package/dist/help-tags-register.js +9 -0
  323. package/dist/help-tags-register.js.map +1 -0
  324. package/dist/index.d.ts +34 -14
  325. package/dist/index.js +42 -22
  326. package/dist/list-action-row.d.ts +64 -0
  327. package/dist/list-action-row.js +8 -0
  328. package/dist/list-action-row.js.map +1 -0
  329. package/dist/list-header.d.ts +99 -0
  330. package/dist/list-header.js +10 -0
  331. package/dist/list-header.js.map +1 -0
  332. package/dist/list-inset-control.d.ts +22 -0
  333. package/dist/list-inset-control.js +3 -0
  334. package/dist/list-inset-control.js.map +1 -0
  335. package/dist/list-inset-text.d.ts +30 -0
  336. package/dist/list-inset-text.js +4 -0
  337. package/dist/list-inset-text.js.map +1 -0
  338. package/dist/list-item.d.ts +52 -0
  339. package/dist/list-item.js +8 -0
  340. package/dist/list-item.js.map +1 -0
  341. package/dist/list.d.ts +59 -0
  342. package/dist/list.js +6 -0
  343. package/dist/list.js.map +1 -0
  344. package/dist/loading-spinner.d.ts +3 -1
  345. package/dist/loading-spinner.js +1 -1
  346. package/dist/lucide-icon.d.ts +3 -1
  347. package/dist/lucide-icon.js +1 -1
  348. package/dist/nav-stack.d.ts +60 -10
  349. package/dist/nav-stack.js +6 -1
  350. package/dist/pane.d.ts +102 -0
  351. package/dist/pane.js +4 -0
  352. package/dist/pane.js.map +1 -0
  353. package/dist/panel-toolbar-DqwtBxQL.d.ts +63 -0
  354. package/dist/popup-menu-register.d.ts +9 -0
  355. package/dist/popup-menu-register.js +31 -0
  356. package/dist/popup-menu-register.js.map +1 -0
  357. package/dist/popup-menu.d.ts +99 -0
  358. package/dist/popup-menu.js +3 -0
  359. package/dist/popup-menu.js.map +1 -0
  360. package/dist/resizable-region.d.ts +32 -3
  361. package/dist/resizable-region.js +1 -1
  362. package/dist/row.d.ts +48 -0
  363. package/dist/row.js +6 -0
  364. package/dist/row.js.map +1 -0
  365. package/dist/segmented-control.d.ts +13 -8
  366. package/dist/segmented-control.js +1 -1
  367. package/dist/select-register.d.ts +5 -1
  368. package/dist/select-register.js +197 -2
  369. package/dist/select-register.js.map +1 -1
  370. package/dist/select.d.ts +87 -8
  371. package/dist/select.js +4 -1
  372. package/dist/semantic-content-BbzjvSu9.d.ts +14 -0
  373. package/dist/sides-BPSWde0A.d.ts +4 -0
  374. package/dist/skeleton.d.ts +31 -0
  375. package/dist/skeleton.js +4 -0
  376. package/dist/skeleton.js.map +1 -0
  377. package/dist/spacer.d.ts +18 -0
  378. package/dist/spacer.js +4 -0
  379. package/dist/spacer.js.map +1 -0
  380. package/dist/split-view.d.ts +39 -7
  381. package/dist/split-view.js +120 -10
  382. package/dist/split-view.js.map +1 -1
  383. package/dist/state-banner.d.ts +19 -5
  384. package/dist/state-banner.js +4 -1
  385. package/dist/styles/app-tab.css +69 -0
  386. package/dist/styles/badge.css +118 -0
  387. package/dist/styles/catalog/components/catalog-example-stack.css +9 -0
  388. package/dist/styles/catalog/components/catalog-example.css +164 -0
  389. package/dist/styles/catalog/components/catalog-stage.css +55 -0
  390. package/dist/styles/catalog/components/catalog.css +12 -0
  391. package/dist/styles/catalog.css +5 -0
  392. package/dist/styles/collapsible-panel.css +575 -0
  393. package/dist/styles/content-item.css +30 -0
  394. package/dist/styles/document.css +23 -0
  395. package/dist/styles/floating-toolbar.css +119 -0
  396. package/dist/styles/foundation.css +178 -40
  397. package/dist/styles/grid.css +21 -0
  398. package/dist/styles/layout.css +3 -41
  399. package/dist/styles/list-action-row.css +257 -0
  400. package/dist/styles/list-header.css +228 -0
  401. package/dist/styles/list-inset-control.css +30 -0
  402. package/dist/styles/list-inset-text.css +29 -0
  403. package/dist/styles/list-item.css +240 -0
  404. package/dist/styles/list.css +133 -0
  405. package/dist/styles/nav-stack.css +158 -50
  406. package/dist/styles/pane.css +229 -0
  407. package/dist/styles/popup-menu.css +270 -0
  408. package/dist/styles/resizable-region.css +429 -4
  409. package/dist/styles/row.css +111 -0
  410. package/dist/styles/segmented-control.css +31 -8
  411. package/dist/styles/select.css +232 -9
  412. package/dist/styles/skeleton.css +92 -0
  413. package/dist/styles/spacer.css +11 -0
  414. package/dist/styles/split-view.css +108 -3
  415. package/dist/styles/state-banner.css +94 -19
  416. package/dist/styles/styles.css +13 -4
  417. package/dist/styles/sunken-panel.css +22 -0
  418. package/dist/styles/surface-scaffold.css +56 -0
  419. package/dist/styles/tab-bar.css +132 -9
  420. package/dist/styles/tab-scaffold.css +113 -3
  421. package/dist/styles/text.css +65 -0
  422. package/dist/styles/token-search-field.css +49 -43
  423. package/dist/styles/toolbar-control-group.css +465 -28
  424. package/dist/styles/toolbar-text.css +88 -4
  425. package/dist/styles/toolbar.css +319 -11
  426. package/dist/styles/value-table.css +34 -4
  427. package/dist/styles/webawesome.css +348 -10
  428. package/dist/styles/workbench.css +828 -7
  429. package/dist/sunken-panel.d.ts +22 -0
  430. package/dist/sunken-panel.js +3 -0
  431. package/dist/sunken-panel.js.map +1 -0
  432. package/dist/surface-scaffold.d.ts +30 -0
  433. package/dist/surface-scaffold.js +3 -0
  434. package/dist/surface-scaffold.js.map +1 -0
  435. package/dist/tab-bar.d.ts +31 -6
  436. package/dist/tab-bar.js +1 -1
  437. package/dist/tab-scaffold.d.ts +54 -7
  438. package/dist/tab-scaffold.js +82 -9
  439. package/dist/tab-scaffold.js.map +1 -1
  440. package/dist/text.d.ts +38 -0
  441. package/dist/text.js +3 -0
  442. package/dist/text.js.map +1 -0
  443. package/dist/token-search-field-CCke1yvQ.d.ts +126 -0
  444. package/dist/token-search-field.d.ts +3 -43
  445. package/dist/token-search-field.js +1 -1
  446. package/dist/token-search-model.d.ts +3 -0
  447. package/dist/token-search-model.js +3 -0
  448. package/dist/token-search-model.js.map +1 -0
  449. package/dist/toolbar-control-group.d.ts +65 -7
  450. package/dist/toolbar-control-group.js +1 -1
  451. package/dist/toolbar-text.d.ts +37 -4
  452. package/dist/toolbar-text.js +3 -1
  453. package/dist/toolbar.d.ts +56 -7
  454. package/dist/toolbar.js +1 -1
  455. package/dist/types-BuHELdXR.d.ts +117 -0
  456. package/dist/value-table.d.ts +13 -3
  457. package/dist/value-table.js +3 -1
  458. package/dist/webawesome.d.ts +8 -1
  459. package/dist/wire-catalog.d.ts +82 -0
  460. package/dist/wire-catalog.js +327 -0
  461. package/dist/wire-catalog.js.map +1 -0
  462. package/dist/wire-nav-stack.d.ts +4 -1
  463. package/dist/wire-nav-stack.js +147 -7
  464. package/dist/wire-nav-stack.js.map +1 -1
  465. package/dist/wire-resizable-regions.d.ts +2 -1
  466. package/dist/wire-resizable-regions.js +2 -1
  467. package/dist/wire-scroll-dividers.d.ts +69 -0
  468. package/dist/wire-scroll-dividers.js +3 -0
  469. package/dist/wire-scroll-dividers.js.map +1 -0
  470. package/dist/wire-sidebar.d.ts +63 -0
  471. package/dist/wire-sidebar.js +231 -0
  472. package/dist/wire-sidebar.js.map +1 -0
  473. package/dist/wire-tab-bars.d.ts +19 -2
  474. package/dist/wire-tab-bars.js +1 -1
  475. package/dist/wire-tab-scaffold.js +9 -4
  476. package/dist/wire-tab-scaffold.js.map +1 -1
  477. package/dist/wire-token-search-fields.d.ts +65 -3
  478. package/dist/wire-token-search-fields.js +1 -1
  479. package/dist/wire-workbench.d.ts +109 -0
  480. package/dist/wire-workbench.js +6 -0
  481. package/dist/wire-workbench.js.map +1 -0
  482. package/dist/workbench.d.ts +218 -7
  483. package/dist/workbench.js +13 -15
  484. package/dist/workbench.js.map +1 -1
  485. package/docs/accessibility.md +386 -22
  486. package/docs/app-layouts.md +106 -8
  487. package/docs/catalog.md +440 -0
  488. package/docs/collapsible-panel.md +363 -0
  489. package/docs/component-contract.md +555 -52
  490. package/docs/component-integration.md +75 -0
  491. package/docs/component-selection.md +359 -89
  492. package/docs/design/templates/empty-state/filtered-dark.svg +1 -0
  493. package/docs/design/templates/empty-state/filtered.svg +1 -0
  494. package/docs/design/templates/empty-state/with-action-dark.svg +1 -0
  495. package/docs/design/templates/empty-state/with-action.svg +1 -0
  496. package/docs/design/templates/empty-state-dark.svg +1 -0
  497. package/docs/design/templates/empty-state.svg +1 -0
  498. package/docs/design/templates/list/compact-dark.svg +1 -0
  499. package/docs/design/templates/list/compact.svg +1 -0
  500. package/docs/design/templates/list/stack-dark.svg +1 -0
  501. package/docs/design/templates/list/stack.svg +1 -0
  502. package/docs/design/templates/list-action-row/default-dark.svg +1 -0
  503. package/docs/design/templates/list-action-row/default.svg +1 -0
  504. package/docs/design/templates/list-action-row/selected-dark.svg +1 -0
  505. package/docs/design/templates/list-action-row/selected.svg +1 -0
  506. package/docs/design/templates/list-action-row-dark.svg +1 -0
  507. package/docs/design/templates/list-action-row.svg +1 -0
  508. package/docs/design/templates/list-dark.svg +1 -0
  509. package/docs/design/templates/list-header/action-dark.svg +1 -0
  510. package/docs/design/templates/list-header/action.svg +1 -0
  511. package/docs/design/templates/list-header/count-dark.svg +1 -0
  512. package/docs/design/templates/list-header/count.svg +1 -0
  513. package/docs/design/templates/list-header/inline-action-dark.svg +1 -0
  514. package/docs/design/templates/list-header/inline-action.svg +1 -0
  515. package/docs/design/templates/list-header/toggle-collapsed-dark.svg +1 -0
  516. package/docs/design/templates/list-header/toggle-collapsed.svg +1 -0
  517. package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -0
  518. package/docs/design/templates/list-header/toggle-expanded.svg +1 -0
  519. package/docs/design/templates/list-header-dark.svg +1 -0
  520. package/docs/design/templates/list-header.svg +1 -0
  521. package/docs/design/templates/list-item/default-dark.svg +1 -0
  522. package/docs/design/templates/list-item/default.svg +1 -0
  523. package/docs/design/templates/list-item/multiline-dark.svg +1 -0
  524. package/docs/design/templates/list-item/multiline.svg +1 -0
  525. package/docs/design/templates/list-item/selected-dark.svg +1 -0
  526. package/docs/design/templates/list-item/selected.svg +1 -0
  527. package/docs/design/templates/list-item/trailing-dark.svg +1 -0
  528. package/docs/design/templates/list-item/trailing.svg +1 -0
  529. package/docs/design/templates/list-item-dark.svg +1 -0
  530. package/docs/design/templates/list-item.svg +1 -0
  531. package/docs/design/templates/list.svg +1 -0
  532. package/docs/design/templates/segmented-control/equal-dark.svg +1 -0
  533. package/docs/design/templates/segmented-control/equal.svg +1 -0
  534. package/docs/design/templates/segmented-control/pill-small-dark.svg +1 -0
  535. package/docs/design/templates/segmented-control/pill-small.svg +1 -0
  536. package/docs/design/templates/segmented-control-dark.svg +1 -0
  537. package/docs/design/templates/segmented-control.svg +1 -0
  538. package/docs/design/templates/skeleton/avatar-dark.svg +1 -0
  539. package/docs/design/templates/skeleton/avatar.svg +1 -0
  540. package/docs/design/templates/skeleton/block-dark.svg +1 -0
  541. package/docs/design/templates/skeleton/block.svg +1 -0
  542. package/docs/design/templates/skeleton/lines-dark.svg +1 -0
  543. package/docs/design/templates/skeleton/lines.svg +1 -0
  544. package/docs/design/templates/skeleton-dark.svg +1 -0
  545. package/docs/design/templates/skeleton.svg +1 -0
  546. package/docs/design/templates/state-banner/danger-dark.svg +1 -0
  547. package/docs/design/templates/state-banner/danger.svg +1 -0
  548. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -0
  549. package/docs/design/templates/state-banner/info-badge.svg +1 -0
  550. package/docs/design/templates/state-banner/info-dark.svg +1 -0
  551. package/docs/design/templates/state-banner/info.svg +1 -0
  552. package/docs/design/templates/state-banner/success-dark.svg +1 -0
  553. package/docs/design/templates/state-banner/success.svg +1 -0
  554. package/docs/design/templates/state-banner/warning-dark.svg +1 -0
  555. package/docs/design/templates/state-banner/warning.svg +1 -0
  556. package/docs/design/templates/state-banner-dark.svg +1 -0
  557. package/docs/design/templates/state-banner.svg +1 -0
  558. package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -0
  559. package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -0
  560. package/docs/design/templates/tab-bar-dark.svg +1 -0
  561. package/docs/design/templates/tab-bar.svg +1 -0
  562. package/docs/design/templates/token-search-field/empty-dark.svg +1 -0
  563. package/docs/design/templates/token-search-field/empty.svg +1 -0
  564. package/docs/design/templates/token-search-field/tokens-dark.svg +1 -0
  565. package/docs/design/templates/token-search-field/tokens.svg +1 -0
  566. package/docs/design/templates/token-search-field-dark.svg +1 -0
  567. package/docs/design/templates/token-search-field.svg +1 -0
  568. package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -0
  569. package/docs/design/templates/toolbar/title-and-actions.svg +1 -0
  570. package/docs/design/templates/toolbar-control-group/borderless-single-dark.svg +1 -0
  571. package/docs/design/templates/toolbar-control-group/borderless-single.svg +1 -0
  572. package/docs/design/templates/toolbar-control-group/icon-buttons-dark.svg +1 -0
  573. package/docs/design/templates/toolbar-control-group/icon-buttons.svg +1 -0
  574. package/docs/design/templates/toolbar-control-group/push-buttons-dark.svg +1 -0
  575. package/docs/design/templates/toolbar-control-group/push-buttons.svg +1 -0
  576. package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -0
  577. package/docs/design/templates/toolbar-control-group/with-text.svg +1 -0
  578. package/docs/design/templates/toolbar-control-group-dark.svg +1 -0
  579. package/docs/design/templates/toolbar-control-group.svg +1 -0
  580. package/docs/design/templates/toolbar-dark.svg +1 -0
  581. package/docs/design/templates/toolbar-text/default-dark.svg +1 -0
  582. package/docs/design/templates/toolbar-text/default.svg +1 -0
  583. package/docs/design/templates/toolbar-text/large-dark.svg +1 -0
  584. package/docs/design/templates/toolbar-text/large.svg +1 -0
  585. package/docs/design/templates/toolbar-text/small-dark.svg +1 -0
  586. package/docs/design/templates/toolbar-text/small.svg +1 -0
  587. package/docs/design/templates/toolbar-text-dark.svg +1 -0
  588. package/docs/design/templates/toolbar-text.svg +1 -0
  589. package/docs/design/templates/toolbar.svg +1 -0
  590. package/docs/design/templates/value-table/details-dark.svg +1 -0
  591. package/docs/design/templates/value-table/details.svg +1 -0
  592. package/docs/design/templates/value-table-dark.svg +1 -0
  593. package/docs/design/templates/value-table.svg +1 -0
  594. package/docs/design/templates.md +138 -0
  595. package/docs/design-philosophy.md +48 -20
  596. package/docs/device-class.md +10 -9
  597. package/docs/document-baseline.md +38 -0
  598. package/docs/examples/application-ui-profile.json +60 -0
  599. package/docs/examples/command-palette-adapter.tsx +69 -17
  600. package/docs/examples/component-catalog-extension.json +45 -0
  601. package/docs/examples/component-composition-extension.json +80 -0
  602. package/docs/layout.md +398 -59
  603. package/docs/nav-stack.md +126 -14
  604. package/docs/recipes.md +137 -54
  605. package/docs/split-view.md +69 -6
  606. package/docs/sunken-panel.md +53 -0
  607. package/docs/surface-scaffold.md +25 -0
  608. package/docs/tab-scaffold.md +94 -10
  609. package/docs/type-contracts.md +134 -0
  610. package/docs/ui-analyzer.md +306 -0
  611. package/docs/ui-doctor.md +107 -0
  612. package/docs/ui-evaluator.md +139 -0
  613. package/docs/ux-demo.md +40 -16
  614. package/docs/webawesome-theme.md +143 -16
  615. package/docs/workbench.md +534 -12
  616. package/doctor/cli.mjs +115 -0
  617. package/doctor/config.schema.json +68 -0
  618. package/doctor/eslint-diagnostics.d.mts +24 -0
  619. package/doctor/eslint-diagnostics.mjs +24 -0
  620. package/doctor/index.d.mts +116 -0
  621. package/doctor/index.mjs +1277 -0
  622. package/doctor/report.schema.json +118 -0
  623. package/evaluator/cli.mjs +89 -0
  624. package/evaluator/index.d.mts +90 -0
  625. package/evaluator/index.mjs +1203 -0
  626. package/evaluator/report.schema.json +152 -0
  627. package/llms.txt +395 -42
  628. package/package.json +235 -37
  629. package/traversal-exclusions.mjs +27 -0
  630. package/ux-demo/recipes/app-shell.tsx +205 -17
  631. package/ux-demo/recipes/collapsible-sidebar.tsx +260 -0
  632. package/ux-demo/recipes/compact-toolbar.tsx +135 -14
  633. package/ux-demo/recipes/composer-form.tsx +133 -21
  634. package/ux-demo/recipes/list-detail-dialog.tsx +282 -0
  635. package/ux-demo/recipes/list-workspace-states.tsx +183 -11
  636. package/ux-demo/recipes/loaders.ts +15 -5
  637. package/ux-demo/recipes/loading-inspector.tsx +204 -0
  638. package/ux-demo/recipes/mount-recipe.ts +28 -10
  639. package/ux-demo/recipes/navigation-sidebar.tsx +139 -13
  640. package/ux-demo/recipes/navigation-stack.tsx +79 -24
  641. package/ux-demo/recipes/types.ts +23 -2
  642. package/ux-demo/recipes/workspace-header.tsx +86 -5
  643. package/dist/browser/menu-action-row.js +0 -3
  644. package/dist/browser/menu-header.js +0 -5
  645. package/dist/browser/menu-item.js +0 -3
  646. package/dist/chunk-24Z2XE6C.js +0 -10
  647. package/dist/chunk-24Z2XE6C.js.map +0 -1
  648. package/dist/chunk-2RJBFNB6.js +0 -172
  649. package/dist/chunk-2RJBFNB6.js.map +0 -1
  650. package/dist/chunk-55DATV3A.js +0 -10
  651. package/dist/chunk-55DATV3A.js.map +0 -1
  652. package/dist/chunk-56RJXPHG.js.map +0 -1
  653. package/dist/chunk-7BR3DO2A.js.map +0 -1
  654. package/dist/chunk-7LDCTU7D.js +0 -134
  655. package/dist/chunk-7LDCTU7D.js.map +0 -1
  656. package/dist/chunk-AQNKJRFH.js +0 -79
  657. package/dist/chunk-AQNKJRFH.js.map +0 -1
  658. package/dist/chunk-CTQKI2XL.js +0 -28
  659. package/dist/chunk-CTQKI2XL.js.map +0 -1
  660. package/dist/chunk-DAFFDO33.js +0 -14
  661. package/dist/chunk-DAFFDO33.js.map +0 -1
  662. package/dist/chunk-EGHL5S4P.js +0 -33
  663. package/dist/chunk-EGHL5S4P.js.map +0 -1
  664. package/dist/chunk-KZKSBUKC.js +0 -19
  665. package/dist/chunk-KZKSBUKC.js.map +0 -1
  666. package/dist/chunk-M5JRI6MN.js +0 -27
  667. package/dist/chunk-M5JRI6MN.js.map +0 -1
  668. package/dist/chunk-MBR3TYNL.js +0 -14
  669. package/dist/chunk-MBR3TYNL.js.map +0 -1
  670. package/dist/chunk-MFKMHK5W.js +0 -10
  671. package/dist/chunk-MFKMHK5W.js.map +0 -1
  672. package/dist/chunk-MQIZAD4A.js.map +0 -1
  673. package/dist/chunk-NPPD2A6O.js +0 -40
  674. package/dist/chunk-NPPD2A6O.js.map +0 -1
  675. package/dist/chunk-R6JHHBKQ.js +0 -19
  676. package/dist/chunk-R6JHHBKQ.js.map +0 -1
  677. package/dist/chunk-RBTVBGRD.js +0 -23
  678. package/dist/chunk-RBTVBGRD.js.map +0 -1
  679. package/dist/chunk-S3TPM2LP.js +0 -23
  680. package/dist/chunk-S3TPM2LP.js.map +0 -1
  681. package/dist/chunk-TRNBHPNW.js.map +0 -1
  682. package/dist/chunk-VHW5YNIB.js +0 -17
  683. package/dist/chunk-VHW5YNIB.js.map +0 -1
  684. package/dist/chunk-W2FK7ZNY.js.map +0 -1
  685. package/dist/chunk-WVPYVDXY.js +0 -15
  686. package/dist/chunk-WVPYVDXY.js.map +0 -1
  687. package/dist/chunk-XZXRLY5Q.js +0 -33
  688. package/dist/chunk-XZXRLY5Q.js.map +0 -1
  689. package/dist/menu-action-row.d.ts +0 -50
  690. package/dist/menu-action-row.js +0 -4
  691. package/dist/menu-action-row.js.map +0 -1
  692. package/dist/menu-header.d.ts +0 -41
  693. package/dist/menu-header.js +0 -6
  694. package/dist/menu-header.js.map +0 -1
  695. package/dist/menu-item.d.ts +0 -31
  696. package/dist/menu-item.js +0 -4
  697. package/dist/menu-item.js.map +0 -1
  698. package/dist/panel-header.d.ts +0 -26
  699. package/dist/panel-header.js +0 -6
  700. package/dist/panel-header.js.map +0 -1
  701. package/dist/styles/menu-action-row.css +0 -160
  702. package/dist/styles/menu-header.css +0 -160
  703. package/dist/styles/menu-item.css +0 -123
  704. package/dist/styles/panel-header.css +0 -59
  705. package/ux-demo/recipes/master-detail-dialog.tsx +0 -45
  706. package/ux-demo/recipes/recipes.css +0 -355
package/README.md CHANGED
@@ -4,11 +4,27 @@ Accessible, composable UI primitives for [kerf](https://github.com/brianwestphal
4
4
 
5
5
  Start interface work with the [need-first component selection matrix](./docs/component-selection.md). It distinguishes direct reuse, composition, thin application adapters, and genuinely custom semantics, with imports, required wiring, application ownership, alternatives, and recipes for every public primitive.
6
6
 
7
- For connective application patterns, use the seven [production composition
7
+ When adding a first-party public component, follow the
8
+ [component integration workflow](./docs/component-integration.md). The catalog
9
+ entry drives one validator across package, build, barrel, CSS, demo, route, and
10
+ AI signature projections, with a non-mutating dry-run report.
11
+
12
+ Browser verification always builds current source: both `npm run test:e2e`
13
+ and direct focused Playwright commands run the catalog/conformance preflights
14
+ and production build before preview. See the [UX catalog contract](./docs/ux-demo.md).
15
+
16
+ When authoring a component gallery, follow the single
17
+ [Catalog demo authoring contract](./docs/catalog.md#catalog-demo-authoring-contract)
18
+ for focused-versus-composition modes, helper nesting, specimen selection,
19
+ geometry inspection, and metadata ownership. AI tools can discover that
20
+ contract and its public imports through the shipped
21
+ [`catalog-authoring.json`](./ai/catalog-authoring.json) artifact.
22
+
23
+ For connective application patterns, use the ten [production composition
8
24
  recipes](./docs/recipes.md). Each has a stable catalog route, runnable state,
9
25
  public-subpath source, semantic layout ownership, and explicit application
10
26
  customization boundaries. The composer recipe demonstrates one coherent form
11
- surface with `PanelHeader` hierarchy and field/action controls aligned to the
27
+ surface with a `Toolbar`/`ToolbarText` heading and field/action controls aligned to the
12
28
  shared 8px gutter; only persistent feedback adds a nested semantic
13
29
  `StateBanner` surface.
14
30
 
@@ -23,60 +39,93 @@ npm install kerfjs @kerfjs/ui
23
39
  ```
24
40
 
25
41
  ```tsx
26
- import { MenuItem } from '@kerfjs/ui/menu-item';
27
- import { MenuHeader } from '@kerfjs/ui/menu-header';
28
- import { MenuActionRow } from '@kerfjs/ui/menu-action-row';
29
- import { Toolbar } from '@kerfjs/ui/toolbar';
30
- import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
31
- import { ToolbarText } from '@kerfjs/ui/toolbar-text';
32
-
33
- mount(root, () => <>
34
- <Toolbar label="Document" leading={<ToolbarControlGroup appearance="borderless" single><ToolbarText text="Notes" /></ToolbarControlGroup>} />
35
- <section>
36
- <MenuHeader
37
- label="Workspace"
38
- action="show-workspace-actions"
39
- actionLabel="Workspace actions"
40
- rootAttributes={{ 'data-section-id': 'workspace' }}
41
- triggerAttributes={{
42
- popoverTarget: 'workspace-actions',
43
- popoverTargetAction: 'toggle',
44
- 'aria-controls': 'workspace-actions',
45
- 'aria-haspopup': 'dialog',
46
- }}
47
- />
48
- <MenuItem
49
- action="open-notes"
50
- label="Notes"
51
- selected
52
- rootAttributes={{ 'data-command-color': 'blue', 'data-drop-status': 'ready' }}
42
+ import { mount } from "kerfjs";
43
+ import { ListItem } from "@kerfjs/ui/list-item";
44
+ import { ListHeader } from "@kerfjs/ui/list-header";
45
+ import { ListActionRow } from "@kerfjs/ui/list-action-row";
46
+ import { Toolbar } from "@kerfjs/ui/toolbar";
47
+ import { ToolbarText } from "@kerfjs/ui/toolbar-text";
48
+
49
+ const root = document.getElementById("app")!;
50
+
51
+ mount(root, () => (
52
+ <>
53
+ <Toolbar
54
+ label="Document"
55
+ leading={<ToolbarText text="Notes" />}
53
56
  />
54
- <MenuActionRow
55
- action="open-file"
56
- itemId="src/main.ts"
57
- label="src/main.ts"
58
- trailingAction="open-file-actions"
59
- trailingActionLabel="Actions for src/main.ts"
60
- trailingActionIcon={moreIcon}
61
- />
62
- <div id="workspace-actions" popover="auto">Application-owned actions</div>
63
- </section>
64
- </>);
57
+ <section>
58
+ <ListHeader
59
+ label="Workspace"
60
+ action="show-workspace-actions"
61
+ actionLabel="Workspace actions"
62
+ rootAttributes={{ "data-section-id": "workspace" }}
63
+ triggerAttributes={{
64
+ popoverTarget: "workspace-actions",
65
+ popoverTargetAction: "toggle",
66
+ "aria-controls": "workspace-actions",
67
+ "aria-haspopup": "dialog",
68
+ }}
69
+ />
70
+ <ListItem
71
+ action="open-notes"
72
+ label="Notes"
73
+ selected
74
+ rootAttributes={{
75
+ "data-command-color": "blue",
76
+ "data-drop-status": "ready",
77
+ }}
78
+ />
79
+ <ListActionRow
80
+ action="open-file"
81
+ itemId="src/main.ts"
82
+ label="src/main.ts"
83
+ trailingAction="open-file-actions"
84
+ trailingActionLabel="Actions for src/main.ts"
85
+ trailingActionIcon={<span aria-hidden="true">⋯</span>}
86
+ />
87
+ <div id="workspace-actions" popover="auto">
88
+ Application-owned actions
89
+ </div>
90
+ </section>
91
+ </>
92
+ ));
65
93
  ```
66
94
 
67
95
  Components return Kerf `SafeHtml`. They do not own application state or attach transient listeners. Actions are stable `data-action` hooks; the application wires them once with `delegate()` or `delegateActions()` and retains the disposer.
68
96
 
69
- `MenuItem.rootAttributes`, `MenuHeader.rootAttributes`,
70
- `MenuActionRow.rootAttributes`, and `AppTab.rootAttributes` carry typed
97
+ Component content positions use one convention: `children` is the homogeneous
98
+ primary region, while semantic positions and replacement content use explicit
99
+ named `SafeHtml` props such as `header`, `footer`, `leading`, `trailing`,
100
+ `icon`, and `action`. These named `SafeHtml` prop slots are ordinary typed
101
+ function-component props—not native `<slot>` elements, wrapper slot
102
+ components, or a generic `slots` object. The composition catalog publishes
103
+ sound prop bindings as `zone.jsx.prop`, allowing ESLint to validate statically
104
+ visible content and cardinality without guessing from zone names.
105
+
106
+ Stable single-root visual components also accept the explicit native
107
+ `slot?: string` prop, so their returned root can participate directly in a web
108
+ component's named slot and keep that assignment through Kerf rerenders. This is
109
+ a narrow interop attribute, not general native-attribute spreading. The
110
+ multi-root `ResizableRegion` and `CollapsiblePanel` intentionally omit it
111
+ because neither has one unambiguous returned root; `CollapsiblePanelToggle`
112
+ supports it as a normal single-root control.
113
+
114
+ `ListItem.rootAttributes`, `ListHeader.rootAttributes`,
115
+ `ListActionRow.rootAttributes`, `AppTab.rootAttributes`,
116
+ `Catalog.stageRootAttributes`, `CatalogExample.rootAttributes`, and `CatalogExampleStack.rootAttributes` carry typed
71
117
  application `data-*` metadata without
72
- teaching the package domain fields. `MenuHeader.triggerAttributes` and
73
- `MenuActionRow.trailingActionAttributes` additionally support native popover
118
+ teaching the package domain fields. `ListHeader.triggerAttributes` and
119
+ `ListActionRow.trailingActionAttributes` additionally support native popover
74
120
  target and relationship attributes. Roles and component-owned action, selection,
75
- disclosure, naming, disabled, and icon semantics remain protected props; an
121
+ disclosure, naming, disabled, icon, and catalog-structure semantics remain protected props; an
76
122
  isolated `role="menuitem"` is not an extension shortcut.
123
+ `CatalogExample.viewport` owns the finite layout constraints needed by focused
124
+ specimens, so catalog authors do not need route-local stylesheets, inline
125
+ styles, or styling-only demo classes.
77
126
  The slots are also filtered at runtime, so structurally widened objects and
78
127
  JavaScript callers cannot bypass those protections with case-variant names.
79
- `MenuItem.trailing` is dormant metadata. Use `MenuActionRow` when a row needs
128
+ `ListItem.trailing` is dormant metadata. Use `ListActionRow` when a row needs
80
129
  sibling primary and trailing native-button actions with independent names,
81
130
  disabled states, focus, and click ownership. Its `label`, `icon`, and
82
131
  `trailingActionIcon` slots are dormant content and must not contain controls.
@@ -90,69 +139,296 @@ Do not concatenate a count into `label` or pass a numeric `badge`; the mutually
90
139
  exclusive legacy `badge` slot remains available for non-count `SafeHtml` such
91
140
  as a `New` marker.
92
141
 
142
+ `Row.gap`, `Grid.gap`, `List.gap`, and `Spacer` dimensions accept a direct spacing name such as
143
+ `gap="xs"` or `gap="m"`, or a branded `CssLength`. Import `space`, `rem`, `em`,
144
+ `px`, `pct`, `lengthVar`, `plus`, and `calc` from the CSS-free
145
+ `@kerfjs/ui/css-values` subpath when a named step is not enough. `plus` returns
146
+ an incomplete expression, so wrap it with `calc` before passing it to a prop.
147
+ Raw CSS strings are deliberately rejected; the opaque brands catch authoring
148
+ mistakes but are not sanitizers.
149
+
150
+ Use `Row` for horizontal flex composition and `List` for vertical composition.
151
+ Both accept `hAlign` (`left`, `center`, `right`, `full`) and `vAlign` (`top`,
152
+ `middle`, `bottom`, `full`), plus their documented short/CSS aliases. `Row`
153
+ also accepts `vAlign="baseline"` for cross-axis text alignment; baseline is not
154
+ available on `List`, whose vertical axis uses `justify-content`. `Row`
155
+ defaults to left/full alignment, the `xs` gap, and `wrap={false}`; List keeps
156
+ its existing full/top alignment and zero-gap defaults. Set `textInsets` or
157
+ `controlInsets` with canonical physical sides in `t`/`r`/`b`/`l` order (for
158
+ example, `textInsets="tbl"` or `controlInsets="r"`). Text geometry takes
159
+ precedence where both select the same side. `ListInsetText` and
160
+ `ListInsetControl` inset all four sides by default and accept the same `sides`
161
+ grammar for selective insets. Nested Rows and Lists resolve their inset sides
162
+ independently, so an unselected inner side does not inherit its parent's inset.
163
+
164
+ Use `Grid` for a fixed positive number of evenly distributed columns. Its
165
+ `minmax(0, 1fr)` tracks stay equal when children have different intrinsic
166
+ widths; the application owns responsive count changes. Use application CSS grid
167
+ for asymmetric or intrinsic tracks and `ResizableRegion` for adjustable ones.
168
+
169
+ The same property-specific boundary applies beyond spacing: use `flex()` (or a
170
+ finite keyword) for `Row.flex`, `Grid.flex`, and `List.flex`; length builders and intrinsic-size keywords for
171
+ `Skeleton.width`/`height`; length builders for `Skeleton.radius`; and
172
+ a foreground color for `SelectChoice.color` — `uiColor()` with a foreground
173
+ token such as `success-on-quiet`, or `foregroundColorVar()` (fill tokens such
174
+ as `uiColor('success-fill-quiet')` are rejected). These grammars are not
175
+ interchangeable. `ListItem` and `ListActionRow` deliberately expose no raw
176
+ `style` declarations; use `className`, public tokens, and component props.
177
+
93
178
  ## Component subpaths
94
179
 
95
- | Component | Browser import (includes reachable CSS) | Manual CSS export |
96
- | --- | --- | --- |
97
- | `LucideIcon` | `@kerfjs/ui/lucide-icon` | `@kerfjs/ui/lucide-icon.css` |
98
- | `DisclosureArrow` | `@kerfjs/ui/disclosure-arrow` | `@kerfjs/ui/disclosure-arrow.css` |
99
- | `Toolbar` | `@kerfjs/ui/toolbar` | `@kerfjs/ui/toolbar.css` |
100
- | `ToolbarControlGroup` | `@kerfjs/ui/toolbar-control-group` | `@kerfjs/ui/toolbar-control-group.css` |
101
- | `ToolbarText` | `@kerfjs/ui/toolbar-text` | `@kerfjs/ui/toolbar-text.css` |
102
- | `MenuActionRow` | `@kerfjs/ui/menu-action-row` | `@kerfjs/ui/menu-action-row.css` |
103
- | `MenuItem` | `@kerfjs/ui/menu-item` | `@kerfjs/ui/menu-item.css` |
104
- | `MenuHeader` | `@kerfjs/ui/menu-header` | `@kerfjs/ui/menu-header.css` |
105
- | Pane, content, and navigation composition | — | `@kerfjs/ui/layout.css` |
106
- | `ResizableRegion` | `@kerfjs/ui/resizable-region` | `@kerfjs/ui/resizable-region.css` |
107
- | `wireResizableRegions` | `@kerfjs/ui/wire-resizable-regions` | — |
108
- | `AppTab` | `@kerfjs/ui/app-tab` | `@kerfjs/ui/app-tab.css` |
109
- | `TabBar` | `@kerfjs/ui/tab-bar` | `@kerfjs/ui/tab-bar.css` |
110
- | `wireTabBars`, `reorderTabs` | `@kerfjs/ui/wire-tab-bars` | — |
111
- | `LoadingSpinner` | `@kerfjs/ui/loading-spinner` | `@kerfjs/ui/loading-spinner.css` |
112
- | `Select` | `@kerfjs/ui/select` | `@kerfjs/ui/select.css` |
113
- | `SegmentedControl` | `@kerfjs/ui/segmented-control` | `@kerfjs/ui/segmented-control.css` |
114
- | `TokenSearchField`, `readTokenSearchField`, `placeTokenSearchCaret` | `@kerfjs/ui/token-search-field` | `@kerfjs/ui/token-search-field.css` |
115
- | `wireTokenSearchFields` | `@kerfjs/ui/wire-token-search-fields` | — |
116
- | `StateBanner` | `@kerfjs/ui/state-banner` | `@kerfjs/ui/state-banner.css` |
117
- | `EmptyState` | `@kerfjs/ui/empty-state` | `@kerfjs/ui/empty-state.css` |
118
- | `PanelHeader` | `@kerfjs/ui/panel-header` | `@kerfjs/ui/panel-header.css` |
119
- | `ValueTable`, `ValueTableRow` | `@kerfjs/ui/value-table` | `@kerfjs/ui/value-table.css` |
120
-
121
- `PanelHeader` is a plain `Toolbar` used as a panel, dialog, or page heading: an
122
- optional icon control group (given a brand fill with a matching border), the
123
- title as extra-large `ToolbarText`, the app's trailing action controls, and an
124
- optional subtitle on a separate row below the title. It overrides no toolbar
125
- styles — the app passes its own trailing controls (typically a
126
- `ToolbarControlGroup`).
127
-
128
- `DisclosureArrow` defaults to an 18px root-scaled decorative visual. Override
129
- `--kui-disclosure-arrow-size` at the narrowest useful scope when a consumer
130
- needs another size; the owning control still supplies interaction, naming, and
180
+ | Component | Browser import (includes reachable CSS) | Manual CSS export |
181
+ | ------------------------------------------------------------------- | --------------------------------------- | -------------------------------------- |
182
+ | `LucideIcon` | `@kerfjs/ui/lucide-icon` | `@kerfjs/ui/lucide-icon.css` |
183
+ | `Badge` | `@kerfjs/ui/badge` | `@kerfjs/ui/badge.css` |
184
+ | `DisclosureArrow` | `@kerfjs/ui/disclosure-arrow` | `@kerfjs/ui/disclosure-arrow.css` |
185
+ | `Toolbar` | `@kerfjs/ui/toolbar` | `@kerfjs/ui/toolbar.css` |
186
+ | `ToolbarControlGroup`, `ToolbarActionLink` | `@kerfjs/ui/toolbar-control-group` | `@kerfjs/ui/toolbar-control-group.css` |
187
+ | `DialogSurface`, `PopupSurface` | `@kerfjs/ui/surface-scaffold` | `@kerfjs/ui/surface-scaffold.css` |
188
+ | `FloatingToolbar` | `@kerfjs/ui/floating-toolbar` | `@kerfjs/ui/floating-toolbar.css` |
189
+ | `PopupMenu` (register with `@kerfjs/ui/popup-menu/register`) | `@kerfjs/ui/popup-menu` | `@kerfjs/ui/popup-menu.css` |
190
+ | `ToolbarText` | `@kerfjs/ui/toolbar-text` | `@kerfjs/ui/toolbar-text.css` |
191
+ | `Text` | `@kerfjs/ui/text` | `@kerfjs/ui/text.css` |
192
+ | `List` | `@kerfjs/ui/list` | `@kerfjs/ui/list.css` |
193
+ | `Row` | `@kerfjs/ui/row` | `@kerfjs/ui/row.css` |
194
+ | `Grid` | `@kerfjs/ui/grid` | `@kerfjs/ui/grid.css` |
195
+ | `Spacer` | `@kerfjs/ui/spacer` | `@kerfjs/ui/spacer.css` |
196
+ | Typed CSS dimension builders | `@kerfjs/ui/css-values` | — |
197
+ | `ListActionRow` | `@kerfjs/ui/list-action-row` | `@kerfjs/ui/list-action-row.css` |
198
+ | `ListItem` | `@kerfjs/ui/list-item` | `@kerfjs/ui/list-item.css` |
199
+ | `ListHeader` | `@kerfjs/ui/list-header` | `@kerfjs/ui/list-header.css` |
200
+ | `ListInsetControl` | `@kerfjs/ui/list-inset-control` | `@kerfjs/ui/list-inset-control.css` |
201
+ | `ListInsetText` | `@kerfjs/ui/list-inset-text` | `@kerfjs/ui/list-inset-text.css` |
202
+ | `ContentItem` | `@kerfjs/ui/content-item` | `@kerfjs/ui/content-item.css` |
203
+ | `Pane` | `@kerfjs/ui/pane` | `@kerfjs/ui/pane.css` |
204
+ | `NavStack` | `@kerfjs/ui/nav-stack` | `@kerfjs/ui/nav-stack.css` |
205
+ | `wireNavStack` | `@kerfjs/ui/wire-nav-stack` | — |
206
+ | `SplitView` | `@kerfjs/ui/split-view` | `@kerfjs/ui/split-view.css` |
207
+ | `TabScaffold` | `@kerfjs/ui/tab-scaffold` | `@kerfjs/ui/tab-scaffold.css` |
208
+ | `wireTabScaffold` | `@kerfjs/ui/wire-tab-scaffold` | — |
209
+ | `Workbench` | `@kerfjs/ui/workbench` | `@kerfjs/ui/workbench.css` |
210
+ | `wireWorkbench` | `@kerfjs/ui/wire-workbench` | — |
211
+ | `CollapsiblePanel`, `CollapsiblePanelToggle` | `@kerfjs/ui/collapsible-panel` | `@kerfjs/ui/collapsible-panel.css` |
212
+ | `wireSidebar` | `@kerfjs/ui/wire-sidebar` | — |
213
+ | Content and navigation composition | — | `@kerfjs/ui/layout.css` |
214
+ | `ResizableRegion` | `@kerfjs/ui/resizable-region` | `@kerfjs/ui/resizable-region.css` |
215
+ | `wireResizableRegions` | `@kerfjs/ui/wire-resizable-regions` | — |
216
+ | `AppTab` | `@kerfjs/ui/app-tab` | `@kerfjs/ui/app-tab.css` |
217
+ | `TabBar` | `@kerfjs/ui/tab-bar` | `@kerfjs/ui/tab-bar.css` |
218
+ | `wireTabBars`, `reorderTabs` | `@kerfjs/ui/wire-tab-bars` | — |
219
+ | `wireScrollDividers` | `@kerfjs/ui/wire-scroll-dividers` | — |
220
+ | `LoadingSpinner` | `@kerfjs/ui/loading-spinner` | `@kerfjs/ui/loading-spinner.css` |
221
+ | `Skeleton` | `@kerfjs/ui/skeleton` | `@kerfjs/ui/skeleton.css` |
222
+ | `SunkenPanel` | `@kerfjs/ui/sunken-panel` | `@kerfjs/ui/sunken-panel.css` |
223
+ | `Select` | `@kerfjs/ui/select` | `@kerfjs/ui/select.css` |
224
+ | `SegmentedControl` | `@kerfjs/ui/segmented-control` | `@kerfjs/ui/segmented-control.css` |
225
+ | `TokenSearchField`, `readTokenSearchField`, `placeTokenSearchCaret` | `@kerfjs/ui/token-search-field` | `@kerfjs/ui/token-search-field.css` |
226
+ | `wireTokenSearchFields` | `@kerfjs/ui/wire-token-search-fields` | — |
227
+ | `createTokenSearchModel` | `@kerfjs/ui/token-search-model` | — |
228
+ | `StateBanner` | `@kerfjs/ui/state-banner` | `@kerfjs/ui/state-banner.css` |
229
+ | `EmptyState` | `@kerfjs/ui/empty-state` | `@kerfjs/ui/empty-state.css` |
230
+ | `ValueTable`, `ValueTableRow` | `@kerfjs/ui/value-table` | `@kerfjs/ui/value-table.css` |
231
+
232
+ Application layouts are separate component subpaths. Browser-condition imports
233
+ include their reachable CSS; use the matching manual CSS export when your
234
+ bundler does not select the browser condition. Add a wire subpath when the
235
+ layout has interactive behavior. The catalog
236
+ entries for `nav-stack`, `split-view`, `tab-scaffold`, `workbench`, and
237
+ `collapsible-panel` document their selection rules, ownership boundaries,
238
+ public classes, tokens, and focused demos. See
239
+ [`docs/app-layouts.md`](./docs/app-layouts.md) for the layout decision matrix.
240
+ `NavStack` and `TabScaffold` expose `chromeDividers="scroll" | "always" |
241
+ "none"` for their chrome lines; `SplitView` forwards the setting to its
242
+ compact stack. A sole `Pane` in a view or scene fills it, keeping the Pane's
243
+ header in place while its own content scrolls.
244
+
245
+ For a `Workbench` or `CollapsiblePanel`, place panel toolbar groups in its
246
+ `leading`, `center`, and `trailing` zones. Add `relocateOnCollapse` to each
247
+ `ToolbarControlGroup` that should remain available in the work-area toolbar
248
+ while the panel is closed. The panel collects marked groups in zone order;
249
+ its toggle follows them. See [Workbench panel toolbars](./docs/workbench.md#panel-toolbars).
250
+
251
+ Compose panel, dialog, and page headings directly with `Toolbar`: put an optional
252
+ icon in a `ToolbarControlGroup`, use a direct extra-large `ToolbarText` for the
253
+ title, and put actions in the trailing zone inside their own control group. Set
254
+ `headingLevel` for page or section headings. Supporting copy is app-owned content
255
+ below the toolbar and should be connected to its host with `aria-describedby`
256
+ when it adds useful context. Set `responsive="wrap"` on a heading whose title
257
+ must stay whole: it keeps one row while everything fits and otherwise moves the
258
+ trailing actions below the title instead of truncating it.
259
+
260
+ A toolbar never clips an action. Its trailing zone wraps whole control groups
261
+ onto another trailing-aligned row under every `responsive` policy, and a
262
+ `responsive="stack"` toolbar wraps its stacked center and trailing groups the
263
+ same way. Wrapping keeps every command visible at its full 44px target without
264
+ moving focus or DOM identity. When a product wants fewer visible commands at
265
+ narrow widths, it chooses them: render a lower-priority command inside an
266
+ app-owned "More" `PopupMenu` (in a `single` group with `nestedDropdown`).
267
+
268
+ `DisclosureArrow` defaults to an 18px root-scaled decorative visual. Pass a
269
+ typed `size` (for example `size={remify(24)}` from `@kerfjs/ui/css-values`)
270
+ when a consumer needs another size; the owning control still supplies interaction, naming, and
131
271
  expanded state. Kerf `Select` retains its independent Web Awesome expand-glyph
132
272
  scale of `.5` through `--kui-disclosure-icon-scale`. Author replacement
133
273
  `DisclosureArrow` icon content facing right before its configured direction
134
274
  transform is applied. Direction changes take the shortest rotation path; a
135
275
  180-degree closed-to-open tie uses counterclockwise rotation.
136
276
 
137
- `MenuHeader` supplies that production `DisclosureArrow` automatically when
277
+ `ListHeader` supplies that production `DisclosureArrow` automatically when
138
278
  `toggle` is true and `actionIcon` is omitted. Keep `expanded` synchronized with
139
279
  real controlled content and preserve the button's stable label; ordinary
140
280
  navigation must not display a disclosure arrow. A custom `actionIcon` remains
141
281
  an escape hatch and replaces the default arrow entirely. The header fills its
142
- available inline width, keeping a separate action at the logical end in a 44px
143
- target. Its visible action glyph defaults to 18px through
144
- `--kui-menu-header-action-icon-size`.
282
+ available inline width by default; set `inline` to shrink-wrap it beside other
283
+ content and remove its root margin, border, and padding. It keeps a separate
284
+ action at the logical end. Its visible action glyph defaults to 18px through
285
+ `--kui-list-header-action-icon-size`.
145
286
 
146
287
  ## Machine-readable catalog
147
288
 
148
- AI tools can retrieve the shipped [`ai/component-catalog.json`](./ai/component-catalog.json)
289
+ AI assistants should start from the generated markdown reference,
290
+ [`ai/components/README.md`](./ai/components/README.md): a one-line index of
291
+ every entry grouped like the catalog, plus one short page per entry
292
+ (`ai/components/<id>.md`) covering when to use and avoid it, imports and
293
+ CSS/registration side effects, where its exact props live, legal parents,
294
+ zones with their JSX props and child counts, app- and wiring-owned state,
295
+ geometry ownership, accessibility obligations, the styling boundary
296
+ (configure through props; never override internals), and its composition
297
+ diagnostics. The pages are projected from the two JSON catalogs by
298
+ `scripts/sync-component-docs.mjs` (`npm run catalog:sync`), and
299
+ `npm run check:catalog` fails when any page drifts.
300
+
301
+ Tools can retrieve the shipped [`ai/component-catalog.json`](./ai/component-catalog.json)
149
302
  for the exhaustive component and composition inventory. It is the canonical
150
303
  source for ids, public exports, purpose and selection guidance, relationships,
151
304
  delivery and side effects, companion wiring, application-owned policy,
152
305
  variants, accessibility obligations, public CSS hooks, routes, and current
153
306
  documentation/recipe links. The adjacent
154
307
  [`component-catalog.schema.json`](./ai/component-catalog.schema.json) describes
155
- the versioned format.
308
+ the versioned format. Every visual entry also declares who owns its margin,
309
+ border, and padding, so a generator can fit it into Kerf's alignment model
310
+ without guessing from a screenshot or private CSS.
311
+
312
+ Catalog demo authoring is deliberately separate from the entry inventory. Load
313
+ [`catalog-authoring.json`](./ai/catalog-authoring.json) to discover the
314
+ authoritative [Catalog demo authoring contract](./docs/catalog.md#catalog-demo-authoring-contract),
315
+ the exact API-signature context, public imports/helpers, sanctioned metadata
316
+ slot, three-kind taxonomy, and functional-group/importance ordering policy.
317
+ Keeping this as a companion artifact prevents per-entry selection facts from
318
+ duplicating presentation rules.
319
+
320
+ Tools that evaluate composition may additionally load
321
+ [`component-composition.json`](./ai/component-composition.json). It is a
322
+ generated composition layer beside `component-catalog.json`, not a newer
323
+ version of it: a deterministic, package-qualified projection of every
324
+ component-catalog entry with formal parent/context, zone/cardinality, child,
325
+ state ownership, wiring, responsive, layout, accessibility, public-boundary,
326
+ and stable-diagnostic fields. `component-catalog.json` remains the selection
327
+ and delivery surface. Composition defaults are
328
+ deliberately permissive; only documented objective rules receive an
329
+ authoritative override and enforceable diagnostic. The adjacent schema and
330
+ [`component-composition.d.ts`](./ai/component-composition.d.ts) types describe
331
+ the same contract.
332
+
333
+ Applications and downstream design systems should publish the same facts for
334
+ their own components. Start from the reusable
335
+ [`component-catalog-extension.schema.json`](./ai/component-catalog-extension.schema.json)
336
+ and the checked
337
+ [`component-catalog-extension.json`](./docs/examples/component-catalog-extension.json)
338
+ example. Give each app-owned component or composition a stable id, selection
339
+ guidance, public hooks, and explicit geometry ownership; then concatenate its
340
+ `entries` with Kerf's shipped `entries` in the AI context. Keep package/source
341
+ identity alongside each input when ids could collide. This makes a combined
342
+ tool reason about both sides of a composition using one vocabulary without
343
+ pretending app-local components are `@kerfjs/ui` exports.
344
+
345
+ Composition-aware consumers use
346
+ [`component-composition-extension.schema.json`](./ai/component-composition-extension.schema.json),
347
+ its shipped TypeScript types, and the checked
348
+ [`component-composition-extension.json`](./docs/examples/component-composition-extension.json)
349
+ example. Preserve each catalog's package and qualify every identity and
350
+ cross-catalog reference as `package:id`; never merge entries by bare id.
351
+
352
+ [`compile-time-contracts-v1.json`](./ai/compile-time-contracts-v1.json) is the
353
+ matching declaration contract: stable `KUI-T###` ids identify the invalid prop,
354
+ state, identity, accessibility, and protected-attribute combinations TypeScript
355
+ rejects. The package gate compiles one positive/negative consumer fixture against
356
+ both source and declarations extracted from the real packed tarball. The
357
+ [compile-time contract guide](./docs/type-contracts.md) documents migrations and
358
+ the dynamic DOM/children relationships that remain runtime or catalog checks.
359
+ Packages scaffolded by `create-kerf-component` maintain this composition input from
360
+ `kerf.components.json`: `npm run catalog:generate` emits the catalog and
361
+ `npm run catalog:check` verifies source files, named public exports, explicit
362
+ author decisions, and byte-for-byte drift. Tools index the generated consumer
363
+ entries and this catalog by full key, reject duplicate full keys, search the
364
+ consumer package first, and retain package identity across every reference.
365
+ They must not infer missing semantics or geometry from rendered appearance.
366
+
367
+ ### Application UI profile
368
+
369
+ Applications can check in `.kerf-ui-profile.json` so tools do not have to infer
370
+ project-wide UI policy. Start from the shipped
371
+ [`application-ui-profile.defaults.json`](./ai/application-ui-profile.defaults.json)
372
+ and the checked
373
+ [`application-ui-profile.json`](./docs/examples/application-ui-profile.json)
374
+ workspace example. The versioned
375
+ [`application-ui-profile.schema.json`](./ai/application-ui-profile.schema.json)
376
+ and [`application-ui-profile.d.ts`](./ai/application-ui-profile.d.ts) cover
377
+ catalog locations, concept preferences, allowed theme/density choices, semantic
378
+ token overrides, layout/responsive conventions, and narrow rule exceptions.
379
+ Profiles contain policy only—never product records, user data, or broad styling
380
+ waivers.
381
+
382
+ Catalog declarations always provide a `composition` location. Consumer
383
+ packages generated with composition-only metadata omit `selection`;
384
+ `@kerfjs/ui` continues to require its `component-catalog.json` selection catalog.
385
+
386
+ Node-based AI and static-analysis tools may import the shipped discovery API
387
+ from `@kerfjs/ui/ai/application-ui-profile.mjs`. It discovers package defaults,
388
+ then the workspace profile, then directory profiles from parent to child;
389
+ `mergeApplicationUiProfiles()` applies later scalar/map values, replaces a
390
+ catalog by package and an exception by id, and preserves source provenance.
391
+ `loadApplicationUiProfile()` resolves catalogs and returns diagnostics with the
392
+ originating file plus JSON path. Unknown/stale components, tokens, rules, and
393
+ catalog locations are errors. Every layer is checked against its then-effective
394
+ catalogs, including parent references and catalog paths later overridden by a
395
+ child profile. Synchronous integrations can require the shipped
396
+ `application-ui-profile-sync.cjs` projection and call
397
+ `loadApplicationUiProfileSync()` with already-discovered layers. Consumers that define additional stable
398
+ diagnostics pass their ids through the additive `knownRules` option; those ids
399
+ are merged with catalog diagnostics before exception validation.
400
+
401
+ ### Static CSS and layout ownership analysis
402
+
403
+ Run `kerf-ui-analyze --root . src` (or import
404
+ `@kerfjs/ui/analyzer`) to evaluate cross-file integration facts against the
405
+ composition catalogs and application profile. It catches provable private
406
+ selector reach-through, unknown tokens, competing geometry owners, nested
407
+ scroll owners, and cataloged CSS-value violations in JavaScript/TypeScript
408
+ component calls and JSX, plus component-ownership overrides: CSS that makes
409
+ another package's component its subject, touches its private variables,
410
+ overrides a token its typed prop sets, or styles it through a hook class on
411
+ its root (`KUI-L019`–`KUI-L022`; forcing a component's dimensions is one such
412
+ restyle). It reports repeated insets, exceptional spacing shorthands, and
413
+ dynamic classes separately as review findings. Text, versioned JSON,
414
+ and SARIF outputs carry stable `KUI-L###` ids, repository-relative locations,
415
+ evidence, and ownership chains. See the [analyzer guide](./docs/ui-analyzer.md).
416
+
417
+ ### Browser-backed integration evaluation
418
+
419
+ Run `kerf-ui-evaluate --url <running-app>` (or import
420
+ `@kerfjs/ui/evaluator`) after the static analyzer. Its Playwright-backed
421
+ wide/intermediate/narrow/200%-zoom, light/dark, and reduced-motion matrix checks
422
+ rendered overflow, clipping, reachability, focus/keyboard behavior, accessible
423
+ names, contrast, hit targets, scrolling, alignment, and cataloged runtime
424
+ geometry. The versioned report carries stable `KUI-B###` diagnostics, focused
425
+ DOM/computed-style evidence, hashed screenshot artifacts, explicit timeout and
426
+ retention policy, and a separate unscored human-visual rubric. See the
427
+ [browser evaluator guide](./docs/ui-evaluator.md).
428
+
429
+ ### Unified repair-loop doctor
430
+
431
+ Use `kerf-ui-doctor` for the supported application repair loop across profile/catalog validation, TypeScript, the Kerf UI ESLint preset, static layout analysis, and an optional explicitly authorized browser evaluation. Its isolated Kerf lint pass preserves each file's applicable core-rule and suppression settings without executing consumer plugin rules. It emits one portable versioned JSON report with deterministic exit codes, exact suppressions, monorepo package selection, changed/full modes, caching, and local-path redaction. See the [UI doctor guide](./docs/ui-doctor.md).
156
432
 
157
433
  For code generation, pair catalog selection guidance with the checked-in
158
434
  [`public-api-signatures-v1.md`](./ai/public-api-signatures-v1.md) declaration
@@ -182,41 +458,74 @@ roots therefore do not need a transitive stylesheet list, and removing the last
182
458
  component import also removes its reachable CSS. This is component-level CSS
183
459
  tree shaking; variants within an imported component remain together.
184
460
 
461
+ When one public subpath groups several visual components, its source is a
462
+ folder: one component per file and one owned stylesheet per visual component.
463
+ The public JavaScript/TypeScript compatibility entrypoint only re-exports those
464
+ modules, and its CSS compatibility entrypoint only imports the owner
465
+ stylesheets. Do not accumulate multiple visual owners in either compatibility
466
+ file.
467
+
468
+ `npm run check:css-ownership` keeps that boundary honest: application CSS may
469
+ style only application-owned structure, never package component classes or
470
+ Web Awesome descendants, and a package component's stylesheet styles only
471
+ itself (in a composing parent's context when needed) — never another kerf
472
+ component's root, the `wa-*` tags it renders, its variables, or a hook class on
473
+ its root. The UX catalog's `style.css` contains document-shell
474
+ mechanics only, recipes ship no stylesheets (`npm run check:recipes` rejects
475
+ route stylesheets, inline styles, and styling-only classes), and `catalog.css`
476
+ remains a
477
+ minimal compatibility entrypoint.
478
+
185
479
  The root `@kerfjs/ui` barrel stays JavaScript-only because making a side-effectful
186
480
  CSS barrel tree-shakable is not portable across bundlers. If an application uses
187
481
  that convenience import, also import `@kerfjs/ui/styles.css`, which deliberately
188
482
  contains the complete layer. Non-browser/SSR tools resolve the pure `import`
189
483
  condition automatically; `@kerfjs/ui/unstyled` is the explicit CSS-free root
190
484
  entry for a browser build with a custom styling pipeline. The exported
191
- `foundation.css` and component CSS paths remain available for fully manual
192
- delivery. Load application overrides after package styles, or scope `--kui-*`
193
- variables directly on a component instance.
485
+ `@kerfjs/ui/foundation.css` and component CSS paths remain available for fully
486
+ manual delivery. Its complete supported `--kui-*` token surface is cataloged
487
+ under the `foundation` entry. Load application overrides after package styles,
488
+ or scope variables directly on a component instance.
489
+
490
+ Applications can separately opt into `@kerfjs/ui/document.css` for border-box
491
+ sizing, token-backed body typography/colors, zero body margin, plain-link color,
492
+ and a definite full-height chain. Add `class="kui-app-root"` to the one direct
493
+ mount container when a percentage-height application shell must fill the
494
+ viewport. This global baseline is deliberately absent from `styles.css` and
495
+ component browser imports. See [Document baseline](./docs/document-baseline.md).
194
496
 
195
497
  ## Pane and content geometry
196
498
 
197
- Import `@kerfjs/ui/layout.css` and use the same structural vocabulary for a
198
- sidebar, main area, inspector, or dialog. `.kui-pane` is unpadded and contains
199
- an optional toolbar, one scrolling `.kui-pane__content`, and an optional footer.
200
- Add `.kui-content` to make its major children a vertical stack with 24px gaps.
499
+ Render `Pane` (`@kerfjs/ui/pane`) for a sidebar, main area, inspector, or
500
+ dialog: the same structural vocabulary everywhere. Its `.kui-pane` root is
501
+ unpadded and contains an optional header, one scrolling `.kui-pane__content`,
502
+ and an optional footer; the content slot already carries `.kui-content`, which
503
+ makes its major children a vertical stack with 24px gaps. Choose landmark
504
+ semantics with `element` / `contentElement` rather than writing the pane
505
+ classes onto your own elements — `eslint-plugin-kerfjs` reports a component's
506
+ anatomy class on an application-owned element as `KUI-L103`.
201
507
 
202
508
  ```tsx
203
- <aside class="kui-pane">
204
- <div class="kui-pane__toolbar"><Toolbar label="Workspace" ... /></div>
205
- <nav class="kui-pane__content kui-content">
206
- <section>
207
- <MenuHeader label="Workspace" count={3} countLabel="3 workspaces" />
208
- <MenuItem action="open" label="Inbox" icon={inboxIcon} />
209
- <MenuItem action="open" label="Drafts" />
210
- </section>
211
- <div class="kui-content-item">Workspace details</div>
212
- </nav>
213
- </aside>
509
+ <Pane
510
+ element="aside"
511
+ label="Workspace"
512
+ contentElement="nav"
513
+ header={<Toolbar label="Workspace" ... />}
514
+ >
515
+ <section>
516
+ <ListHeader label="Workspace" count={3} countLabel="3 workspaces" />
517
+ <ListItem action="open" label="Inbox" icon={inboxIcon} />
518
+ <ListItem action="open" label="Drafts" />
519
+ </section>
520
+ <ContentItem>Workspace details</ContentItem>
521
+ </Pane>
214
522
  ```
215
523
 
216
- Ordinary children use `.kui-content-item`: 8px inline margin, a real 1px border
217
- (transparent by default), 8px padding, and 12px rounded corners. The pill
218
- modifier uses a 22px radius. A component can expose a transparent border or
219
- background without changing layout. `MenuHeader` follows the same rule while
524
+ Ordinary children use `ContentItem` (`@kerfjs/ui/content-item`): 8px inline
525
+ margin, a real 1px border (transparent by default), 8px padding, and 12px
526
+ rounded corners. `shape="pill"` uses a 22px radius, and `frame="framed"` paints
527
+ the neutral border only when the item marks a real distinction. A component can expose a transparent border or
528
+ background without changing layout. `ListHeader` follows the same rule while
220
529
  keeping its dormant title and count-or-badge cluster separate from its optional
221
530
  44px action.
222
531
 
@@ -236,10 +545,10 @@ Apps using Web Awesome's free components can opt into the same visual universe
236
545
  with one CSS import:
237
546
 
238
547
  ```ts
239
- import type {} from '@kerfjs/ui/webawesome';
240
- import '@kerfjs/ui/webawesome.css';
241
- import '@awesome.me/webawesome/dist/components/button/button.js';
242
- import '@awesome.me/webawesome/dist/components/input/input.js';
548
+ import type {} from "@kerfjs/ui/webawesome";
549
+ import "@kerfjs/ui/webawesome.css";
550
+ import "@awesome.me/webawesome/dist/components/button/button.js";
551
+ import "@awesome.me/webawesome/dist/components/input/input.js";
243
552
  ```
244
553
 
245
554
  The type-only `@kerfjs/ui/webawesome` import adds Kerf JSX intrinsic-element
@@ -250,6 +559,9 @@ Awesome modules the application renders.
250
559
  `webawesome.css` includes Web Awesome's native/base theme and then applies the
251
560
  Hot Sheet 2 palette, surfaces, status colors, focus treatment, form geometry,
252
561
  radii, tooltips, and shadows through Web Awesome's public `--wa-*` contract.
562
+ On `wa-dialog`, the optional `hide-actions` class hides the exported
563
+ `header-actions` shadow part for compositions that provide another dismissal
564
+ affordance.
253
565
  Those tokens flow into all free component families. Every free Web Awesome 3.12
254
566
  component has an individual UX-catalog route under the collapsible ecosystem
255
567
  section, but the theme entry does not import or register component JavaScript,
@@ -258,30 +570,37 @@ Tooltip and Popover surfaces omit pointer arrows by default. Override
258
570
  `--wa-tooltip-arrow-size` and `--kui-wa-popover-arrow-size`, or a single
259
571
  popover's public `--arrow-size`, when an arrow communicates useful context.
260
572
 
261
- Load application CSS afterward to override semantic values globally, or scope
262
- them to a subtree. Use Web Awesome's `.wa-light`, `.wa-dark`, and `.wa-invert`
573
+ Configure semantic values globally at the application root, or scope variables
574
+ to a self-owned subtree. Use Web Awesome's `.wa-light`, `.wa-dark`, and `.wa-invert`
263
575
  classes for explicit appearance boundaries:
264
576
 
265
577
  ```css
266
578
  :root {
267
579
  --wa-color-brand-fill-loud: #7540a8;
268
- --wa-form-control-border-radius: .5rem;
580
+ --wa-form-control-border-radius: 0.5rem;
269
581
  }
270
582
  ```
271
583
 
272
584
  `foundation.css` follows Hot Sheet 2's Web Awesome-compatible semantic palette.
273
- Brand, neutral, success, warning, and danger each expose fill, border, and
274
- foreground roles through `--kui-color-*`; stateful components also expose
585
+ Brand, pop, neutral, success, warning, and danger each expose fill, border, and
586
+ foreground roles through `--kui-color-*`. Pop is attractive, non-status emphasis
587
+ for featured, novel, or celebratory content; it never substitutes for success,
588
+ warning, or danger. Stateful components also expose
275
589
  component variables such as `--kui-state-banner-background`. Override the
276
590
  foundation for an application theme, a tone variable for one semantic state, or
277
591
  a component variable on one instance without replacing component selectors.
278
- Prefer an equivalent prop or token. When composition-specific layout still
279
- needs a selector, the component catalog's `publicClasses` arrays define the
280
- exact stable anatomy: public-class-to-public-class selectors are supported;
281
- descendant tag, id, attribute-only, and unlisted-class selectors are not.
282
-
283
- `StateBanner` has opinionated `neutral`, `info`, `success`, `warning`, and
284
- `danger` palettes. Override an individual banner with
592
+ Prefer an equivalent prop or token. The component catalog's `publicClasses`
593
+ arrays support diagnostics, tooling, browser assertions, and package-owned
594
+ composition; they are not an application styling API. Application-owned CSS may
595
+ style new structure rendered by its own component, but it must not select a
596
+ nested Kerf or Web Awesome component. Add missing configuration to the owner.
597
+ Markup follows the same rule: write only an entry's `placeableClasses` (layout
598
+ utilities, `kui-app-root`, `kui-content-item` on a non-div carrier) onto your
599
+ own elements; any other public class recreates a component by class, which
600
+ `eslint-plugin-kerfjs` reports as `KUI-L103` with the component to render.
601
+
602
+ `StateBanner` has opinionated `neutral`, `info`, `pop`, `success`, `warning`,
603
+ and `danger` palettes. Override an individual banner with
285
604
  `--kui-state-banner-background`, `--kui-state-banner-border`,
286
605
  `--kui-state-banner-foreground`, `--kui-state-banner-detail`,
287
606
  `--kui-state-banner-action-background`, and
@@ -305,8 +624,8 @@ standalone `filled`/`outlined` appearance with `shape="rounded"` or
305
624
  appearance="toolbar"
306
625
  shape="pill"
307
626
  choices={[
308
- { value: 'list', label: 'List' },
309
- { value: 'columns', label: 'Columns' },
627
+ { value: "list", label: "List" },
628
+ { value: "columns", label: "Columns" },
310
629
  ]}
311
630
  />
312
631
  ```
@@ -320,14 +639,27 @@ value through `data-segment-value`. Override an instance through
320
639
  free text and ordered filter chips in one field. Its editable text stays
321
640
  DOM-owned between token changes so typing does not replace the caret. Tokens
322
641
  expose stable edit/remove actions and remain atomic during editing; the app owns
323
- parsing, suggestions, query execution, and state. Use `readTokenSearchField()`
642
+ parsing, suggestions, query execution, and state in manual mode. For automatic
643
+ handling, create a model with `createTokenSearchModel({ rules, evaluate })`,
644
+ pass it as the field's `model`, and register it under the field id in
645
+ `wireTokenSearchFields(root, { models })`. Rules parse `name:value` expressions;
646
+ their optional `suggest` function supplies selectable completions. The model
647
+ commits valid expressions on whitespace or Enter, owns chips and clear/edit/
648
+ remove actions, and exposes `state`, `suggestions`, and the latest `result` as
649
+ signals. Omit the model to retain full manual control. Use `readTokenSearchField()`
324
650
  after browser input to recover text plus token offsets, and
325
651
  `placeTokenSearchCaret()` when restoring focus after a controlled update.
326
652
  Call `wireTokenSearchFields()` once at a stable root to make Enter submit through
327
653
  `onSubmit` without inserting a contenteditable line break and to preserve focus
328
654
  plus the text-relative caret when keyboard deletion of a chip causes controlled
329
- rendering to replace the editor. Text still wraps visually when it reaches the
330
- field edge.
655
+ rendering to replace the editor. A select-all deletion is normalized to a truly
656
+ empty editor even when the browser leaves an atomic chip or line break behind;
657
+ replacement typing consumes that intent so a later Backspace/Delete remains an
658
+ ordinary character edit.
659
+ Managed deletion keeps a collapsible replacement editor open and focused before
660
+ the next keystroke; applications must persist both query and tokens from the DOM
661
+ read. Genuine outside focus and Escape still collapse an empty field.
662
+ Text still wraps visually when it reaches the field edge.
331
663
  Clear actions should empty the editor's `textContent` before clearing app state.
332
664
  The leading icon, first text line, clear action, and trailing slot share one
333
665
  fixed alignment row; when text wraps, those controls stay pinned to that first
@@ -350,6 +682,11 @@ drag, the scroll strip automatically moves toward either edge with speed based
350
682
  on pointer proximity, exposing earlier or later drop targets. Apply the reported
351
683
  change with `reorderTabs()` or application-specific state logic. The application
352
684
  still owns selection, closing, routing, and persistence.
685
+ For a tab-local action immediately after the final tab plus a workspace action
686
+ at the opposite edge, set `trailingPlacement="adjacent"`, pass the local action
687
+ through `trailing`, and pass the workspace action through `end`. TabBar owns the
688
+ flex geometry: the tab strip shrinks and scrolls while both action regions stay
689
+ visible. Do not recreate that split with descendant CSS overrides.
353
690
  Use `AppTab.rootAttributes` for domain `data-*` metadata and `closeIcon` for a
354
691
  decorative replacement glyph. The runtime rejects roles and case variants of
355
692
  the component- or wiring-owned action, tab identity, selection, drag, drop, and
@@ -359,15 +696,27 @@ close button retains all close interaction.
359
696
  `Select` uses Web Awesome but does not register anything by itself. Install the optional peer, import the shared theme if desired, and explicitly import the registration entry in the application:
360
697
 
361
698
  ```ts
362
- import '@kerfjs/ui/webawesome.css';
363
- import '@kerfjs/ui/select/register';
699
+ import "@kerfjs/ui/webawesome.css";
700
+ import "@kerfjs/ui/select/register";
364
701
  ```
365
702
 
366
- That boundary keeps Web Awesome and its custom-element side effects out of bundles that use unrelated components. Automated consumer-bundle tests enforce it.
703
+ That boundary keeps Web Awesome and its custom-element side effects out of bundles that use unrelated components. Automated consumer-bundle tests enforce it. `PopupMenu` follows the same rule: import `@kerfjs/ui/popup-menu/register` once to register the dropdown, item, button, and divider elements it renders. Either registration also installs help tags: an icon-only Select, PopupMenu, or `aria-label`-named `<button>` in a `ToolbarControlGroup` shows its name in an `aria-hidden` tooltip on hover and keyboard focus. A toolbar with icon-only buttons but neither control imports `@kerfjs/ui/help-tags/register`, which registers only the tooltip.
704
+
705
+ `PopupMenu` items may include `submenu` children, `checked` choices, a leading `icon`, trailing `details`, `disabledReason`, and a `danger` tone. The app owns choice state and dispatches each item's `action`. For a right-click menu, set `context: true` and a `label`, then call `openPopupMenuAt(menu, event.clientX, event.clientY)` from the app's `contextmenu` handler; `closePopupMenu(menu)` closes it programmatically. See [component selection](docs/component-selection.md#popup-menu-migration) for examples.
706
+ Use `label` for a visible label or `ariaLabel` for a visually hidden name. A
707
+ nonempty visible label takes precedence when both are supplied. Kerf names the
708
+ actual shadow combobox without adding visible label spacing; this also works
709
+ with `renderSelected`, and needs no application shadow-DOM patch. Use `hint`
710
+ for persistent supporting text below the control and `placeholderText` for the
711
+ empty value inside the closed control. Loading placeholders preserve the hint.
712
+
367
713
  `Select` also owns the Kerf/Web Awesome reconciliation boundary: option icons
368
714
  keep stable slotted elements across rerenders, and `renderSelected` content is
369
715
  replaced when the controlled value changes. Consumers do not need to add
370
- `data-key` or `data-morph-skip` workarounds around choice icons.
716
+ `data-key` or `data-morph-skip` workarounds around choice icons. Icon-bearing
717
+ options retain the standard icon-to-label gap. When a compact Select is wrapped
718
+ in a `ToolbarControlGroup`, use `focusRingOwner="group"`; the group paints the
719
+ focus ring with its configured pill or rounded geometry.
371
720
 
372
721
  For application choices and panes, prefer Kerf's purpose-built primitives:
373
722
  `Select` over direct Web Awesome selection/dropdown composition,
@@ -376,7 +725,12 @@ Awesome Tabs, `LucideIcon` over Web Awesome Icon, and `ResizableRegion` over
376
725
  Split Panel. `ResizableRegion` includes Hot Sheet 2's 1px separator and
377
726
  hover/focus grip. Its optional `handleIcon` replaces only the decorative glyph;
378
727
  the component and `wireResizableRegions()` retain separator semantics and
379
- pointer/keyboard behavior. Consider Web Awesome Popup when its anchored-positioning
728
+ pointer/keyboard behavior. Typed policies cover separator visibility,
729
+ instant-track/composited-content collapse, popup-safe overflow,
730
+ inline/overlay/hidden responsive presentation, `responsiveFillAt` single-track
731
+ replacement, and safe-area restore controls;
732
+ the same policies are available on `Workbench` and `CollapsiblePanel`. Consider
733
+ Web Awesome Popup when its anchored-positioning
380
734
  engine removes custom placement code; treat Tree, Animated Image, Comparison,
381
735
  Zoomable Frame, and the displaced alternatives above as exceptional rather
382
736
  than default patterns. The detailed rationale lives in the theme contract.
@@ -395,8 +749,9 @@ than default patterns. The detailed rationale lives in the theme contract.
395
749
 
396
750
  Run `npm run dev` from this directory for the category-grouped master/detail catalog. Every public visual component has a focused route; all 70 free Web Awesome 3.12 components have focused routes under the collapsible ecosystem section. Every detail visibly links its first-party demo source and existing guidance while showing the repository-relative paths; first-party components also link their implementation source, and Web Awesome entries label local guidance as Kerf integration guidance. One grouped `Related components` selector contains derived `Uses` / `Used by` navigation across both sets. Run `npm run check` for static/unit/bundle gates and `npm run test:e2e` for the real-browser suite.
397
751
 
398
- Run `npm run format:css` after editing styles. The normal `npm run check` gate
399
- uses Prettier to reject unformatted CSS in `src/` and `ux-demo/`.
752
+ Run `npm run format` after editing source or structured content. The narrower
753
+ `npm run format:css` command remains available for style-only work. The normal
754
+ `npm run lint` and `npm run check` gates use Prettier to reject formatting drift.
400
755
 
401
756
  For dimensions that should scale with the root font size, author pixels with
402
757
  `remify()`: `gap: remify(17px)` builds to `gap: 1.0625rem` using a fixed 16px