@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
@@ -18,25 +18,245 @@ package delivery paths, Web Awesome's installed manifest, AI guidance, and
18
18
  documentation links. Nuanced prose in this contract and the selection guide
19
19
  remains authored rather than generated.
20
20
 
21
+ ### Markdown component reference (AI entry point)
22
+
23
+ [`ai/components/README.md`](../ai/components/README.md) and one
24
+ `ai/components/<id>.md` page per catalog entry are the assistant-facing view of
25
+ both catalogs. An assistant reads the index, then only the pages it uses,
26
+ instead of loading the full JSON. Each page merges the entry's selection facts
27
+ (purpose, use/avoid, alternatives), delivery (JavaScript subpath, CSS,
28
+ registration, wiring helpers), a link into `public-api-signatures-v1.md` for
29
+ exact props, composition (parents, contexts, zones with their JSX prop and
30
+ cardinality, children), state and wiring ownership including wiring-owned
31
+ state attributes, geometry, accessibility obligations, public class and token
32
+ hooks framed as a styling boundary (components own their styles; configure
33
+ through props rather than overriding internals), and `KUI-C###` diagnostics
34
+ with their conditions. `scripts/sync-component-docs.mjs` renders them only from
35
+ `component-catalog.json` and `component-composition.json` (plus the signature
36
+ file's module headings for anchors), sorted and Prettier-formatted;
37
+ `check:catalog` rejects a stale, missing, or orphaned page. The JSON files stay
38
+ the canonical tool-facing sources.
39
+
40
+ ### Composition catalog
41
+
42
+ [`component-composition.json`](../ai/component-composition.json) adds a formal,
43
+ machine-evaluable composition layer beside `component-catalog.json` without
44
+ changing its selection and delivery contract; it is a generated companion, not
45
+ a newer version of that catalog. Every component-catalog entry projects once,
46
+ in order, under the stable qualified key `package:id`. Each composition entry
47
+ explicitly covers parents/contexts,
48
+ named zones and cardinality, optional explicit JSX prop bindings, child concepts, state ownership, required wiring,
49
+ responsive ownership, layout and geometry, accessibility obligations, public
50
+ CSS boundaries, diagnostics, and provenance. A wrapper entry may add
51
+ `rendersAs`: the cataloged roots it renders (any one of them, or nothing), so
52
+ composition checks treat its elements as each root rather than as an unknown
53
+ child. A placement with listed parent constraints produces one `KUI-L201`
54
+ diagnostic even when both the wrapper and a rendered root reject that parent.
55
+
56
+ `boundaries.placeableClasses` names the subset of `publicClasses` an
57
+ application may write onto its own elements (layout utilities, the document
58
+ root, item geometry on another carrier); absent means none, and every other
59
+ public class is the component's rendered anatomy. `boundaries.rootElement`
60
+ names the element a component renders around its own placeable classes
61
+ (`content-item`: `div`), so a plain element of that tag carrying them is still
62
+ the component recreated. `eslint-plugin-kerfjs`'s `ui-public-boundaries`
63
+ reports both as `KUI-L103` with the export to render — for `@kerfjs/ui` and for
64
+ every consumer catalog a `.kerf-ui-profile.json` declares, whatever the class
65
+ prefix. `create-kerf-component` packages declare the same fields in
66
+ `kerf.components.json`.
67
+
68
+ An entry's optional `cssValueProps` makes CSS-adjacent prop grammar equally
69
+ machine-evaluable. Each path records the property grammar, finite shorthands,
70
+ canonical versus exceptional spacing choices, standalone and expression-only
71
+ helpers, raw/unsafe policy, and serialization examples. Nested paths use the
72
+ bounded `items[].property` form. Consumer catalogs can publish the same facts;
73
+ ESLint, `kerf-ui-analyze`, and `kerf-ui-doctor` then issue the same stable
74
+ `KUI-L013`–`KUI-L017` feedback for application and third-party components.
75
+
76
+ `wiring.stateAttributes` lists the **wiring-owned state attributes**: the
77
+ `data-*` attributes a wiring helper writes at runtime, such as
78
+ `data-handle-inset` and `data-resizing`, which `wireResizableRegions` puts on a
79
+ `ResizableRegion`. Each entry names the attribute, the element that carries it
80
+ (`on`), the `helper` that writes it, and what it means. An application must not
81
+ render, remove, or treat these attributes as its own state; tools use the list
82
+ to tell them apart from app-authored attributes. They are declared once, on the
83
+ helper's wiring item in the component catalog, and the composition catalog
84
+ flattens them. `check:catalog`
85
+ reads each `wire*` helper's source and fails when its declarations differ from
86
+ the `data-*` attributes it actually writes. First-party entries always carry
87
+ the list, empty when their helpers write none; it is optional in extension
88
+ catalogs.
89
+
90
+ The generator starts with permissive defaults. An `any` mode records that the
91
+ catalog has no defensible prohibition; it does not claim every composition is
92
+ recommended. Objective rules live in
93
+ `component-composition-rules.json` and may carry stable `KUI-C###`
94
+ diagnostics. A tool reports a diagnostic only after proving its exact `when`
95
+ condition. Subjective choice, product policy, and visual taste remain prose.
96
+
97
+ Kerf UI calls component content positions **named `SafeHtml` prop slots**.
98
+ Use `children` for one homogeneous primary region; use explicit named
99
+ `SafeHtml` props for semantic positions or replacement content such as
100
+ `header`, `footer`, `leading`, `trailing`, `icon`, and `action`. These are typed
101
+ function-component props, not native web-component `<slot>` elements and not a
102
+ generic `slots={{...}}` object. A composition zone declares `jsx.prop` only when tooling
103
+ can soundly bind that zone to one public JSX prop; `children` is spelled
104
+ explicitly. Zones without that binding remain guidance and are never guessed
105
+ from their ids. Static tools inspect only visible JSX structure and leave
106
+ dynamic `SafeHtml` expressions to runtime and accessibility evaluation.
107
+
108
+ ### Native named-slot assignment
109
+
110
+ Every public visual component with one stable conceptual root accepts an
111
+ explicit `slot?: string` prop and forwards it to that root on every render
112
+ branch. Use it when a Kerf component is a light-DOM child of a custom element,
113
+ for example `StateBanner({ title: 'Ready', slot: 'status' })`. Omitting the prop
114
+ omits the attribute.
115
+
116
+ This contract does not open a generic native-attribute bag: components still
117
+ accept only their documented props and narrow extension-attribute objects.
118
+ `ResizableRegion` and `CollapsiblePanel` are deliberately excluded because each
119
+ can return a region plus a sibling restore control, leaving no single root that
120
+ can truthfully own native slot assignment. Their single-root controls and all
121
+ alternate-root branches of supported components retain the contract.
122
+
123
+ Component-catalog consumers continue unchanged. Composition-aware consumers
124
+ read `component-catalog.json` for selection/delivery and
125
+ `component-composition.json` for composition. `npm run catalog:sync` projects every new component,
126
+ recipe, and supported Web Awesome entry, and the completeness gate prevents
127
+ silent omissions. Downstream catalogs use the composition extension schema and types,
128
+ retain their own package identity, and qualify cross-catalog references. See
129
+ the checked
130
+ [`component-composition-extension.json`](./examples/component-composition-extension.json)
131
+ application-owned example.
132
+
133
+ ### Compile-time contract boundary
134
+
135
+ The versioned
136
+ [`compile-time-contracts-v1.json`](../ai/compile-time-contracts-v1.json)
137
+ artifact maps stable `KUI-T###` ids to public imports, emitted symbols, and
138
+ catalog identities. Its positive/negative fixture compiles against both source
139
+ and a freshly packed package, so source declarations and shipped declarations
140
+ cannot silently diverge. See [Compile-time contracts](./type-contracts.md) for
141
+ the full audit, migration guidance, and the relationships deliberately left to
142
+ runtime/catalog checks because TypeScript cannot prove them.
143
+
144
+ ### Application UI profile
145
+
146
+ The component catalogs describe what packages provide; an application profile
147
+ describes which supported choices a project has approved. A workspace may
148
+ check in `.kerf-ui-profile.json` conforming to
149
+ [`application-ui-profile.schema.json`](../ai/application-ui-profile.schema.json).
150
+ Keep package-qualified catalog locations and recurring-concept preferences,
151
+ allowed color schemes and density, public semantic-token overrides,
152
+ layout/responsive conventions, and narrow rule exceptions there. Product
153
+ records, copy, permissions, user preferences, and transport state do not belong
154
+ in this policy file.
155
+
156
+ Every catalog location names a composition artifact. `selection` is optional
157
+ for consumer packages whose generated metadata declares component-catalog
158
+ selection guidance not applicable; `@kerfjs/ui` retains its required
159
+ `component-catalog.json` selection artifact. This
160
+ lets a generated `component-composition.json` participate directly without a
161
+ fabricated compatibility file.
162
+
163
+ Discovery and precedence are deterministic:
164
+
165
+ 1. Load `application-ui-profile.defaults.json` from `@kerfjs/ui`.
166
+ 2. Load `.kerf-ui-profile.json` at the workspace root when present.
167
+ 3. Walk from the workspace root toward the target directory and load each
168
+ directory-local profile in parent-to-child order.
169
+
170
+ Later scalar and object-map values win. Catalogs merge by package; preferences
171
+ and token overrides merge by key; exceptions merge by stable id. Lists such as
172
+ allowed themes/densities replace the earlier list rather than accumulating.
173
+ Every resolved field retains its source file. The shipped
174
+ `application-ui-profile.mjs` API implements discovery, merge, loading, and
175
+ validation and reports actionable originating file + JSON-path diagnostics for stale
176
+ catalogs, unknown component/rule/token references, preference conflicts, and
177
+ broad exceptions. Each raw layer is validated against the catalogs effective at
178
+ that exact precedence point before merge, so a broken parent catalog, stale
179
+ parent reference, invalid value, or unknown field cannot disappear merely
180
+ because a child profile replaces it. The shipped
181
+ `application-ui-profile-sync.cjs` projects the same merge and validation contract
182
+ for synchronous hosts such as ESLint rules; it deliberately performs no async
183
+ I/O.
184
+ See the
185
+ [`application-ui-profile.json`](./examples/application-ui-profile.json) example.
186
+
187
+ The package defaults avoid every `Discouraged` Web Awesome entry — each
188
+ `webawesome` catalog entry whose `recommendation` is not `supported`, except the
189
+ encouraged `wa-popup` primitive — under a concept whose `preferred` value is the
190
+ Kerf component that wraps or replaces it (`command-menu` → `PopupMenu`,
191
+ `value-selection` → `Select`, `application-tabs` → `TabBar`, `icon` →
192
+ `LucideIcon`, `resizable-pane` → `ResizableRegion`, `exclusive-choice` →
193
+ `SegmentedControl`, `hierarchy-navigation` → `List`, `embedded-media` →
194
+ `ContentItem`). `eslint-plugin-kerfjs` `ui-preferences` (`KUI-L301`, also run by
195
+ `kerf-ui-doctor`) therefore reports a Discouraged element written directly as a
196
+ JSX tag (`<wa-dropdown>`) as well as through an imported component. A declared
197
+ component's own source file is exempt, because that wrapper is the sanctioned
198
+ owner of the element it renders. A unit test holds the avoid set and the
199
+ catalog's Discouraged set equal in both directions, so neither can drift. A
200
+ product that genuinely needs one of these elements records a narrow `KUI-L301`
201
+ profile exception for the file that renders it.
202
+
203
+ Catalog detail footers use one standard resource vocabulary and order. Build
204
+ them with `catalogResources()` from `@kerfjs/ui/catalog-resources`: `Demo source`
205
+ first, optional `Component source` and `Design template`, then `Guidance`.
206
+ Third-party entries use the typed `integrationGuidance` kind, which renders
207
+ `Integration guidance`, and omit `Component source` when the implementation is
208
+ not owned by the catalog's project. Prefer these semantic kinds over local labels
209
+ such as “View source” or “Read UI guidance”; the helper makes that convention a
210
+ compile-time choice while still returning ordinary `CatalogResource[]` values.
211
+
21
212
  ## Ownership boundaries
22
213
 
214
+ ### Geometry ownership metadata
215
+
216
+ The canonical [`component-catalog.json`](../ai/component-catalog.json) records
217
+ the margin, border, and padding owner for every component and composition under
218
+ `geometry`. Read it before adding a wrapper or local spacing rule:
219
+
220
+ - `self` means the entry's public visual contract supplies that geometry.
221
+ - `parent` means the embedding layout must supply it.
222
+ - `child` means composed descendants supply it; the entry's outer shell does not.
223
+ - `none` means that dimension is intentionally absent from the standard contract.
224
+ - `conditional` means a variant, part, or configuration changes ownership; the
225
+ accompanying `notes` explain the boundary.
226
+
227
+ The values describe public ownership, including themed shadow parts, rather
228
+ than merely asking whether a CSS declaration appears on the host element.
229
+ Recipes are exempt because they arrange entries whose individual ownership is
230
+ already cataloged.
231
+
232
+ Downstream packages and applications should publish the same contract for their
233
+ reusable visual components. Use
234
+ [`component-catalog-extension.schema.json`](../ai/component-catalog-extension.schema.json)
235
+ and copy the structure of the checked
236
+ [`component-catalog-extension.json`](./examples/component-catalog-extension.json)
237
+ example. Keep app and Kerf entries as package-qualified inputs, then let people
238
+ or AI tools search their combined entries and compare `geometry` before adding
239
+ wrappers or insets. Do not add app-owned entries to Kerf's canonical catalog or
240
+ claim Kerf delivery paths for them.
241
+
23
242
  - Components own semantic markup, stable anatomy, documented variants, ARIA projection, and package CSS hooks.
24
243
  - Applications own signals/stores, product copy, domain-state mapping, persistence, routing, permissions, and transport.
25
244
  - Actions are `data-action` strings. Wire them at a stable root with `delegate()` or `delegateActions()` and retain the disposer.
26
245
  - A reusable component never owns per-instance mutable module state.
27
- - Consumers style through `--kui-*` semantic tokens and public component classes. Foundation tokens provide opinionated neutral, brand/info, success, warning, and danger fill/border/foreground roles. Stateful components expose local override variables; prefer an equivalent prop or token before writing a selector.
246
+ - Consumers configure presentation through component props and documented `--kui-*` semantic tokens. Foundation tokens provide opinionated neutral, brand/info, non-status pop, success, warning, and danger fill/border/foreground roles. Application stylesheets must not select package component classes or descendants. If genuinely new structure needs CSS, encapsulate that structure and its stylesheet in an application-owned component; configure any nested Kerf components through their public APIs.
28
247
 
29
- `MenuItem.rootAttributes`, `MenuActionRow.rootAttributes`,
30
- `MenuHeader.rootAttributes`, and `AppTab.rootAttributes` accept
248
+ `ListItem.rootAttributes`, `ListActionRow.rootAttributes`,
249
+ `ListHeader.rootAttributes`, `AppTab.rootAttributes`,
250
+ `CatalogExample.rootAttributes`, and `CatalogExampleStack.rootAttributes` accept
31
251
  application-owned `data-*` metadata without
32
- adding product fields to the shared API. A `MenuActionRow` trailing action uses
33
- `trailingActionAttributes`, and a `MenuHeader` action/disclosure uses
252
+ adding product fields to the shared API. A `ListActionRow` trailing action uses
253
+ `trailingActionAttributes`, and a `ListHeader` action/disclosure uses
34
254
  `triggerAttributes`, for `data-*`, native popover target/action attributes, and
35
255
  the corresponding `aria-controls`/`aria-haspopup` relationship. These slots do
36
256
  not accept roles or component-owned action, selection, disclosure, accessible
37
257
  name, disabled, or icon fields. Extension objects are filtered at runtime,
38
258
  including case-insensitive rejection of protected `data-*` names, and the
39
- component writes its protected attributes after the accepted metadata. Typed,
259
+ component or helper writes its protected attributes after the accepted metadata. Typed,
40
260
  structurally widened, and JavaScript callers therefore cannot replace its
41
261
  contract.
42
262
 
@@ -46,10 +266,10 @@ component continues to own the named close button or focusable separator, and
46
266
  `wireTabBars()` / `wireResizableRegions()` continue to own transient behavior
47
267
  and disposal.
48
268
 
49
- `MenuItem.trailing`, `MenuActionRow.label`, `MenuActionRow.icon`, and
50
- `MenuActionRow.trailingActionIcon` are dormant SafeHtml slots. They must not
269
+ `ListItem.trailing`, `ListActionRow.label`, `ListActionRow.icon`, and
270
+ `ListActionRow.trailingActionIcon` are dormant SafeHtml slots. They must not
51
271
  contain controls. When a row needs an independently interactive trailing
52
- region, `MenuActionRow` owns the noninteractive root and the two sibling native
272
+ region, `ListActionRow` owns the noninteractive root and the two sibling native
53
273
  buttons; the application owns their delegated behavior and controlled state.
54
274
  Both row components align a leading icon with the first label line when
55
275
  `multiline` allows the label to wrap; additional lines extend below that fixed
@@ -58,37 +278,143 @@ visual anchor.
58
278
  ### Public CSS anatomy
59
279
 
60
280
  The `publicClasses` array on each entry in
61
- [`component-catalog.json`](../ai/component-catalog.json) is the exact supported
62
- anatomy boundary. A scoped selector may join documented public classes, such as
63
- `.workspace .kui-toolbar .kui-toolbar__trailing`, when composition-specific
64
- layout cannot be expressed by a prop or token. A class being public does not
65
- make copied component markup an invocation or transfer state and accessibility
66
- ownership to the application.
67
-
68
- Do not select a component's descendant by element name, id, attribute alone, or
69
- an unlisted implementation class. Selectors such as `.kui-state-banner span`,
70
- `.kui-menu-item [data-state]`, and `.kui-menu-item .local-label` depend on
71
- private structure. If no prop, token, or cataloged class expresses a recurring
72
- need, request a supported hook instead of inferring one from rendered markup.
73
-
74
- `DisclosureArrow` uses an 18px root-scaled visual by default. Override
75
- `--kui-disclosure-arrow-size` on the component or its containing scope when a
76
- consumer needs another size. Kerf `Select` uses a separate Web Awesome expand
281
+ [`component-catalog.json`](../ai/component-catalog.json) identifies stable
282
+ anatomy for diagnostics, tooling, browser assertions, and package-owned
283
+ composition. It is not an application customization API. Applications choose
284
+ documented props and tokens; package components may compose other components
285
+ only through those public contracts, never by styling a child's classes from a
286
+ parent stylesheet.
287
+
288
+ Inside the package, a component never styles another component or writes
289
+ another component's variables. When a child must adapt to a composing parent,
290
+ the child styles itself in that context from its own stylesheet: the parent's
291
+ class and state appear only in an ancestor compound, the styled compound is
292
+ the child's own class (or one of the child's own unclassed internals below
293
+ it), and the child reads context values the parent provides under the
294
+ parent's name. `ResizableRegion` widens its edge extent by the unsafe inset a
295
+ split `SplitView` provides, and a `Skeleton` derives its fill from a solid
296
+ `Badge`'s on-solid color, both in their own stylesheets; an `AppTab` rounds its
297
+ outer corners in a segmented `TabBar` and shares a fill-allocated strip from
298
+ `app-tab.css`. A `PopupMenu` sizes
299
+ its trigger and applies a group's `menuInset` in its own stylesheet, and an
300
+ icon-only `Select` reads the control slot a `ToolbarControlGroup` provides
301
+ (`--_kui-toolbar-control-group-slot-*`). A parent may still style its own
302
+ elements keyed on a child's state, naming the child by class inside `:has()`
303
+ (`:has(> .kui-select[open])`, or `TabBar` insetting a segmented strip that
304
+ holds compact tabs), and it keeps styling raw native and raw Web
305
+ Awesome children no kerf component owns, excluding kerf children by class
306
+ (`wa-dropdown:not(.kui-popup-menu)`). `npm run check:css-ownership` enforces
307
+ this in every component stylesheet (a `src/*.css` with a same-basename
308
+ component), deriving the component names, the Web Awesome tags each component
309
+ renders, and its composed children from `src/*.tsx`:
310
+
311
+ - **Foreign classes.** Another component's class or `[data-component]` may
312
+ appear only in an ancestor compound or inside `:has()` / `:not()`; the
313
+ styled compound is the stylesheet's own class.
314
+ - **Owned Web Awesome tags.** Kerf components are named by class, never by a
315
+ `wa-*` tag they render. A tag another component renders (`wa-dropdown`,
316
+ `wa-select`, `wa-option`, a `PopupMenu`'s trigger `wa-button`) — as the
317
+ subject, or as an ancestor whose internals the rule reaches — must be scoped
318
+ to that component by its class or excluded with `:not()`. A direct child
319
+ that cannot be the owner's internal
320
+ (`.kui-toolbar-control-group > wa-button`) needs no exclusion.
321
+ - **Variables.** A stylesheet writes only its own `--_kui-<self>-*` private
322
+ variables, and never overrides a public `--kui-<other>-*` token that another
323
+ component reads. Shared foundation tokens (`--kui-layout-*`,
324
+ `--kui-color-*`, …) are not any one component's. Context a parent provides
325
+ is named after the parent.
326
+ - **Context on any child.** Custom properties set on a subject that can be any
327
+ element (`.kui-x > *`, `> :not(…)`) also land on composed components' roots.
328
+ - **Hook classes.** A class the component places on a composed kerf child's
329
+ root (`<ToolbarText className="kui-nav-stack__title">`, a class NavStack once styled) may not be styled;
330
+ the child styles itself in that context instead.
331
+
332
+ The documented exceptions live with their reasons in
333
+ `scripts/lib/css-ownership.mjs`, and an exception that stops matching fails the
334
+ check, so the list only shrinks. The layout regions' inherited edge-inset
335
+ context (`--kui-edge-inset-*` handed to a sole Pane or layout child and cleared
336
+ for any other content, and a Toolbar clearing it for its zones) is the one
337
+ design exception; the others name the open fix ticket.
338
+
339
+ Applications and component packages built on the package follow the same
340
+ rules, and the downstream tools enforce them against the composition catalog
341
+ instead of package source: `kerf-ui-analyze` / `kerf-ui-doctor` report a rule
342
+ whose subject is another package's component (`KUI-L019`), another
343
+ component's private `--_*` variable (`KUI-L020`), an override of a token a
344
+ typed prop sets (`KUI-L021`), and a hook class on a component's root
345
+ (`KUI-L022`); `eslint-plugin-kerfjs`'s `ui-component-ownership` reports
346
+ `KUI-L020` / `KUI-L021` in script. Both share the selector parsing in
347
+ `analyzer/selectors.mjs` with `check:css-ownership`, and
348
+ `check:css-ownership` fails when a component renders a Web Awesome tag the
349
+ catalog does not list, so `KUI-L019` keeps covering every tag a kerf component
350
+ renders. Each finding names the configuration to use and routes a missing
351
+ prop to a component-gap report (see [the analyzer guide](./ui-analyzer.md#component-ownership-kui-l019kui-l022)).
352
+
353
+ The composition catalog additionally requires `boundaries.rootClass` to be
354
+ either one exact member of `publicClasses` or `null` when the entry has no
355
+ rendered class root. Runtime geometry tooling uses this explicit field; array
356
+ order never implies root ownership.
357
+
358
+ Do not select a component root or descendant by class, element name, id, or
359
+ attribute. Selectors such as `.workspace .kui-toolbar`,
360
+ `.kui-state-banner span`, and `.kui-list-item [data-state]` cross the ownership
361
+ boundary. If no prop or token expresses a recurring need, add the configuration
362
+ to the owning component instead of inferring it from rendered markup.
363
+
364
+ `Badge` owns the complete visual treatment for compact status, count, category,
365
+ and metadata labels. Configure its semantic `tone`, `appearance`, `shape`, and
366
+ `size`; do not recreate or override badge anatomy in an application or consuming
367
+ component. Use `label` when visible content is abbreviated and `ariaHidden` only
368
+ when a surrounding component already includes the same value in its accessible name.
369
+ Every tone's text and solid fill use that tone's `--kui-color-{tone}-on-fill`
370
+ token (`neutral` uses the text colors), the foreground tuned to clear WCAG AA
371
+ (4.5:1) on the tone's fills in light and dark mode.
372
+
373
+ `ListItem` renders its leading icon and nested SVG at a root-scaled 18px by
374
+ default while retaining the row's 44px minimum interactive target. Multiline
375
+ rows align that 18px visual with the first inherited text line. The row clips
376
+ descendant painting to its rounded root so labels, status, and dormant trailing
377
+ content cannot escape its visible boundary. Rows with descriptions grow enough
378
+ to keep their owned two-line label stack readable; use `multiline` when the
379
+ primary label should wrap rather than truncate. A single-line row ends its
380
+ primary label and description with an ellipsis before the trailing status
381
+ slot, even when the label is one long word; a `multiline` row wraps instead,
382
+ breaking a word wider than the label column (a long component or file name)
383
+ rather than letting it run under the trailing slot. A string label in a
384
+ `multiline` row gets line-break opportunities at its camelCase and acronym
385
+ boundaries, so `QuickTicketComposer` wraps as `QuickTicket` / `Composer`
386
+ rather than mid-word; breaking anywhere is only the last resort for a single
387
+ word that is still too wide. The text and accessible name are unchanged. `ListActionRow` labels
388
+ follow the same single-line and `multiline` rules before the trailing action.
389
+
390
+ `DisclosureArrow` uses an 18px root-scaled visual by default. Pass its typed
391
+ `size` prop when a consumer needs another size. Kerf `Select` uses a separate Web Awesome expand
77
392
  glyph contract, `--kui-disclosure-icon-scale: .5`; changing one contract does
78
393
  not implicitly change the other. Direction changes take the shortest rotation
79
394
  path; a 180-degree closed-to-open tie uses counterclockwise rotation.
80
395
 
81
- In `MenuHeader` toggle mode, omitting `actionIcon` composes the production
396
+ In `ListHeader` toggle mode, omitting `actionIcon` composes the production
82
397
  `DisclosureArrow` and derives its visual direction from `expanded`. The app
83
398
  must update that controlled state and reveal or hide real content. Passing a
84
399
  custom `actionIcon` replaces the default rather than layering or rotating both.
85
- The root fills the available inline width after its standard margins. A
86
- separate action stays at the logical end in its 44px target while the visible
87
- glyph defaults to 18px through `--kui-menu-header-action-icon-size`.
400
+ The root fills the available inline width after its standard margins by
401
+ default. Set `inline` when it must shrink-wrap beside surrounding content; that
402
+ presentation removes the root margin, border, and padding while retaining the
403
+ title and optional action's own control geometry. A separate action stays at
404
+ the logical end while the visible glyph defaults to 18px through
405
+ `--kui-list-header-action-icon-size`.
88
406
 
89
407
  `StateBanner` exposes instance-level `--kui-state-banner-background`,
90
408
  `--kui-state-banner-border`, `--kui-state-banner-foreground`,
91
- `--kui-state-banner-detail`, and action background variables. Its five built-in
409
+ `--kui-state-banner-detail` and action background variables. Its optional
410
+ badge composes `Badge` beside the title and follows the banner tone by default. The
411
+ title, badge, and detail flow as inline text: a wrapping title keeps the badge one item
412
+ gap after its last word, and a detail that does not fit whole beside them moves to its
413
+ own line and truncates at the full copy width (below 576px it always takes its own
414
+ line). The title and detail both use the tone's `--kui-color-{tone}-on-fill`
415
+ foreground (`info` uses `brand`) at full strength, clearing WCAG AA over the tone's fill in light and dark
416
+ mode; the detail reads as secondary through its smaller, regular-weight type, and
417
+ only the neutral tone quiets it, to `--kui-color-neutral-on-quiet`. Its five built-in
92
418
  tones can be rethemed globally with
93
419
  `--kui-state-banner-{tone}-{background|border|foreground}`. Toolbar control,
94
420
  segmented-control, app-tab, and tab-bar colors likewise use their public
@@ -96,39 +422,117 @@ segmented-control, app-tab, and tab-bar colors likewise use their public
96
422
  hover, and selected-state variables, so rounded, pill, and toolbar presentations
97
423
  remain opinionated but locally overridable.
98
424
 
425
+ Inset hover and selection surfaces follow the outer control shape instead of
426
+ choosing an independent radius. `--kui-layout-highlight-inset` is the full
427
+ distance between those edges; the inner radius is the outer radius minus that
428
+ inset. `ToolbarControlGroup` publishes its derived radius to nested toolbar
429
+ `SegmentedControl` choices, keeping both direct buttons and exclusive-choice
430
+ highlights concentric when the group switches between pill and rounded shapes.
431
+
99
432
  `ResizableRegion` owns the Hot Sheet 2 split treatment: a persistent 1px
100
- separator with a compact grip that appears on hover or keyboard focus. Override
433
+ separator with a compact grip that appears on hover or keyboard focus. The grip
434
+ is drawn centered on the separator line even though the pointer target is wider
435
+ than the line, so the handle never reads as offset into a pane. Override
101
436
  `--kui-resizable-region-separator-color`,
102
437
  `--kui-resizable-region-handle-color`, or
103
438
  `--kui-resizable-region-handle-active-color` on a region when its containing
104
439
  surface needs a different contrast level.
105
440
 
106
- `@kerfjs/ui/layout.css` defines one structural model for sidebars, main areas,
107
- inspectors, and dialogs. `.kui-pane` is unpadded and contains an optional
108
- toolbar, one scrolling `.kui-pane__content`, and an optional footer.
441
+ `Pane` defines one structural model for sidebars, main areas, inspectors, and
442
+ dialogs. Its `.kui-pane` root is unpadded and contains an optional vertical
443
+ header, one scrolling vertical `.kui-pane__content`, and an optional footer.
444
+ Logical-edge separator lines are independently opt-in and default off.
445
+ `@kerfjs/ui/layout.css` retains the pane roles and supplies the related content
446
+ geometry classes.
447
+ `List` is the corresponding layout-only vertical stack: its children stretch by
448
+ default, while `gap`, `flex`, and `scrollable` opt into typed spacing,
449
+ flex growth, and vertical scroll ownership. `Row.flex` uses the same typed flex
450
+ participation contract on the horizontal counterpart. `dividerSides` accepts canonical
451
+ physical top/right/bottom/left combinations such as `tr` and `trbl`; the stack
452
+ adds no list semantics, margin, or padding of its own. Use a direct finite
453
+ spacing shorthand such as `gap="2xs"`, or pass a `CssLength` created by the
454
+ CSS-free `@kerfjs/ui/css-values` helpers: `space('m')`, `rem(0.25)`,
455
+ `lengthVar('--app-gap')`, or `calc(plus(rem(0.25), pct(10)))`. `plus` returns a
456
+ non-standalone `CssLengthExpression`; only `calc` turns it into a complete
457
+ length. `remify(18)` is the runtime twin of source CSS's `remify(18px)`: it
458
+ takes a pixel count and returns a `CssLength` in rem (`1.125rem`) against the
459
+ same fixed 16px baseline. Raw CSS strings, and the source-only `remify(4px)`
460
+ string form, are not valid runtime props. The `CssLength` name intentionally includes percentages for UI dimension
461
+ props. Its opaque string brand improves authoring correctness; it is not a CSS
462
+ sanitizer or security boundary.
463
+ `Row.flex` and `List.flex` likewise accept their boolean default, finite keywords, or `CssFlex`
464
+ from `flex(grow, shrink, basis)`. `Skeleton` width/height use `CssSize`, radius
465
+ uses `CssLength`, and `SelectChoice.color` uses `CssForegroundColor` from
466
+ `uiColor()` with a foreground token such as `success-on-quiet`, or from
467
+ `foregroundColorVar()`. Fill tokens such as `success` are pale background tints
468
+ and do not type-check there. Never exchange these property grammars. List rows expose
469
+ `className`, public tokens, and semantic props instead of unrestricted `style`
470
+ declarations.
109
471
  `.kui-content` gives major children 24px vertical separation.
110
- `.kui-content-item` gives one child 8px inline margin, a real 1px border,
111
- 8px padding, and 12px corners; border and background may be transparent without
112
- changing geometry. `.kui-content-item--pill` selects the 22px radius.
472
+ `ContentItem` (`@kerfjs/ui/content-item`, rendering `.kui-content-item`) gives
473
+ one child 8px inline margin, a real 1px border, 8px padding, and 12px corners;
474
+ the border stays transparent unless `frame="framed"`, so framing never changes
475
+ geometry. `shape="pill"` selects the 22px radius.
113
476
 
114
477
  `ToolbarControlGroup` is the unit of toolbar organization, even for dormant
115
478
  text. Each group reserves `calc(2px + remify(42px))`, or 44px, with 8px between
116
- groups and inside items. `MenuHeader` similarly separates its dormant title and
479
+ groups and inside items. For an ordinary icon/action control inside a group, use
480
+ a plain `<button>` — the group styles `> button` fully, and it keeps the group
481
+ free of a Web Awesome dependency and shadow DOM. Use `ToolbarActionLink` when
482
+ the action must retain native anchor navigation; the group owns its geometry,
483
+ hover, and focus treatment. Set `overflow="scroll"` when a row of controls must
484
+ stay inside the available toolbar width. Set `visibility="compact-only"` for a
485
+ group that replaces wider toolbar controls below the Toolbar's compact container
486
+ breakpoint; do not hide the group with an application class. Reach for
487
+ `wa-button` only when you need
488
+ a Web Awesome feature; a popup menu is a `PopupMenu`, which renders its own
489
+ trigger. Nothing wraps inside a group: an icon sits beside its label on one
490
+ row, and a group's controls never break onto a second line — the group sizes
491
+ to its content and the enclosing `Toolbar`'s responsive policy relocates whole
492
+ groups. For a compact mixed-content group, set `nestedDropdown`; a
493
+ text-and-caret trigger grows to its intrinsic width while an icon-only trigger
494
+ can remain square. A compact icon `<button>` is a 32px circle, so a selected
495
+ compact segment never becomes an oval. An icon-only `Select` joins a group as
496
+ one more segment with its siblings' inset, radius, hover, and focus ring; only a
497
+ lone Select grows the group to its icon-and-caret pill. Set `menuInset` to configure the dropdown menu surface
498
+ without application `::part(menu)` CSS; the default `standard` keeps each menu's
499
+ own inset (8px for a raw `wa-dropdown`, the Select listbox's 4px for a
500
+ `PopupMenu`), while `compact` and `list-zero` apply to every nested menu. A
501
+ `PopupMenu` and a `Select` draw one popup: the same caret that turns to face the
502
+ open popup, fade-in surface, surface inset, row height and padding, reserved
503
+ check column, current-row fill, and group titles, all read from one private
504
+ popup-choice contract in `foundation.css`. Compact mixed controls retain the standard
505
+ item padding, omit an internal separator, and let the raised selected item paint
506
+ over the outer border instead of shrinking to an inset highlight. The Web
507
+ Awesome trigger's shadow base owns max-content sizing, so icons, localized text,
508
+ and the shadow caret determine the width without a fixed host measurement.
509
+ The enclosing `Toolbar` owns zone alignment and responsive topology: use
510
+ `centerAlign="stretch"` when the center group should consume its track, and
511
+ choose `responsive="stack"` with `responsiveAt="compact" | "narrow"`,
512
+ `responsive="wrap"` for a heading whose title must stay whole, or
513
+ `responsive="center-priority"` instead of selecting its zone classes from a
514
+ parent stylesheet. No policy clips an action: the trailing zone, and a stacked
515
+ center zone, wrap whole groups onto another row. The center zone never
516
+ compresses below its content width, so when the leading identity, center, and
517
+ trailing zones share a row that is too narrow, the leading title is what gives
518
+ way: it truncates with an ellipsis (as a platform toolbar's title does) instead
519
+ of the center group painting over it. When everything fits, the center group
520
+ keeps its place, centered in the track between the leading and trailing zones.
521
+ `ListHeader` similarly separates its dormant title and
117
522
  optional count or badge from its optional 44px action. Use the mutually
118
523
  exclusive `count`/`countLabel` pair for non-negative safe-integer section
119
524
  quantities; reserve `badge` for non-count `SafeHtml`. Do not concatenate counts
120
- into the section label. Do not add padding to pane shells,
525
+ into the section label. Set `width="content"` to shrink-wrap while retaining
526
+ normal header geometry; `inline` is the separate zero-outer-geometry mode. Do
527
+ not add padding to pane shells,
121
528
  double child-owned geometry with wrapper insets, or create competing scroll
122
529
  owners. The [layout contract](./layout.md) lists the public roles and tokens.
123
530
 
124
- `PanelHeader` is a plain top `Toolbar` used as a panel, dialog, or page heading;
125
- it overrides no Toolbar styles. The leading zone holds an optional icon (a normal
126
- bordered `ToolbarControlGroup` given a brand fill with a matching border) and the
127
- title as extra-large `ToolbarText`, and the app's `actions` go straight into the
128
- trailing zone (typically as a `ToolbarControlGroup`). The icon group is omitted
129
- when no icon is passed. The optional summary is a separate row aligned below the
130
- title, so it cannot pull the icon group out of vertical alignment with the
131
- title and action row.
531
+ Panel, dialog, and page headings are direct `Toolbar` compositions. The leading
532
+ zone holds an optional icon `ToolbarControlGroup` and a direct extra-large
533
+ `ToolbarText`; app actions belong in a trailing `ToolbarControlGroup`. Omit the
534
+ icon group when it has no content. Supporting copy is app-owned content below
535
+ the toolbar so it cannot pull the icon or actions out of alignment.
132
536
 
133
537
  `ValueTable` composes typed `ValueTableRow` entries. A row owns its `dt`/`dd`
134
538
  semantics and may receive a leading `SafeHtml` icon. Every row keeps 8px of
@@ -139,6 +543,16 @@ padding + 24px icon + 8px gap) and 8px from the right edge for an icon-bearing
139
543
  row. Applications own the values, formatting, and whether an icon is decorative
140
544
  or meaningfully labeled.
141
545
 
546
+ A row follows the settings-style key/value priority: the value keeps its
547
+ content and the label gives way. The label and value are two content-sized
548
+ columns that share the row's free space equally, each stopping once its content
549
+ fits. A short value therefore stays whole on one line beside any label, and a
550
+ long label takes the remaining width, wrapping at its spaces and ending a word
551
+ wider than its column (a long component or file name) in an ellipsis before the
552
+ value rather than running under it. A short label keeps its width beside a
553
+ long value, which wraps; when both are long they split the row, so neither is
554
+ starved.
555
+
142
556
  ## Imports and side effects
143
557
 
144
558
  Every component has an explicit JS and CSS subpath. In CSS-aware browser builds,
@@ -161,27 +575,98 @@ render, hands in its own via `collapsible.signals`, drives it through
161
575
  `handle.open`/`handle.close`, or disables any individual behavior — so transient
162
576
  UI is consistent by default without every app reinventing it.
163
577
 
578
+ A public subpath that exposes several visual components is a folder-backed
579
+ surface. Put each component in its own source file and give each visual
580
+ component exactly one owned stylesheet alongside it. Keep the public
581
+ compatibility entrypoints implementation-free: the JavaScript/TypeScript
582
+ entrypoint only re-exports the folder modules, and the CSS entrypoint only
583
+ imports their owner stylesheets. A shared public name is not permission to put
584
+ several component implementations or visual contracts back into one file.
585
+
164
586
  `wireTokenSearchFields` is a deliberate exception, not the rule for `wire…`
165
- helpers. Its collapse behavior was *rich and error-prone* — reveal, focus
587
+ helpers. Its collapse behavior was _rich and error-prone_ — reveal, focus
166
588
  transfer, Escape, empty-blur collapse, focus return — the kind of transient chrome
167
589
  apps kept reimplementing inconsistently, so the helper owns it. Everywhere else the
168
590
  app's state is **domain or persisted, not transient chrome, and stays app-owned**: a
169
591
  `NavStack`'s view stack is navigation history, a `TabBar`/`TabScaffold`'s selection
170
592
  and tab order are data, a `ResizableRegion`'s committed size and a
171
593
  `Workbench`/`SplitView` rail's `collapsed` flag are persisted layout preferences.
172
- Each helper already owns only the *ephemeral mechanics* around that state —
594
+ Each helper already owns only the _ephemeral mechanics_ around that state —
173
595
  `wireNavStack` the push/pop animation, `wireTabBars` the overflow autoscroll and
174
596
  drag preview, `wireResizableRegions` the live drag preview — and reports committed
175
- changes through callbacks. A `MenuHeader` `toggle` disclosure's `expanded` is
597
+ changes through callbacks. A `ListHeader` `toggle` disclosure's `expanded` is
176
598
  likewise app-owned: it is a one-line boolean the app already tracks and must read to
177
599
  render the section body, so a managed helper would remove no real complexity. Reach
178
600
  for a managed default only when the transient behavior is substantial enough that
179
601
  hand-rolling it produces genuine, inconsistent variation.
180
602
 
603
+ TabBar itself owns the inline geometry around those mechanics. Its tab list is
604
+ the only shrinking, horizontally scrolling region; `leading`, `trailing`, and
605
+ `end` action regions remain fixed. Set `trailingPlacement="adjacent"` when the
606
+ trailing action belongs immediately after the final tab and use `end` for a
607
+ separate action pinned to the far edge. Applications own the action content,
608
+ but must not restyle TabBar descendants to recreate that allocation.
609
+
181
610
  CSS, the generated wrappers that make it
182
611
  reachable, and the registration module are the package's only declared side
183
612
  effects.
184
613
 
614
+ A value-bearing component's `placeholder` prop is a first-class loading mode: the
615
+ component renders its own real chrome (labels, icon and action affordances,
616
+ container geometry) while replacing each **value** slot with a subtle, deliberately
617
+ unanimated `Skeleton` block and disabling its own interactive controls
618
+ (`aria-busy`, dropped `data-action`, disabled buttons). Only unknown values become
619
+ skeletons; nothing else may change. Sizes, shapes, typography, color, and opacity stay
620
+ identical to the populated component, so a parent composes a faithful loading view —
621
+ an inspector, a detail pane — from placeholder children without hand-rebuilding
622
+ markup. The application still owns the loading lifecycle (when to pass `placeholder`)
623
+ and which slots are unknown; the standalone `Skeleton` covers custom slots. A
624
+ `Skeleton` is `inline-block` so it sits in a text line; pass `block` to lay it out
625
+ as `display: block` where it stands in for a box, such as an icon, so it takes no
626
+ line of its own and centers in its slot. It is a
627
+ placeholder, not progress: use `LoadingSpinner` for known busy activity, and never
628
+ animate the skeleton.
629
+
630
+ A placeholder is loading, not unavailable, so it keeps the `disabled` attribute (its
631
+ controls stay inert and out of the keyboard order) but never shows disabled chrome.
632
+ `skeleton.css`, which every component that renders a skeleton loads, neutralizes generic
633
+ disabled styling under `[data-placeholder="true"]` — including Web Awesome's native
634
+ `button:disabled { opacity: 0.5; cursor: not-allowed }` when `webawesome.css` is
635
+ loaded — to full opacity and the non-interactive `default` cursor. That opacity reset
636
+ carries zero specificity, so a component's own opacity (a control hidden until
637
+ interaction) still wins, and each component excludes placeholders from its own
638
+ disabled tone and hover feedback — including hover reveals: a `ListActionRow` with
639
+ `trailingActionVisibility="interaction"` keeps its trailing action hidden when its
640
+ placeholder is hovered, as the resting live row does. The cursor is the one intentional difference from the
641
+ live state: a placeholder is not clickable, so it never advertises a pointer.
642
+
643
+ A control the author disabled is different: it will be unavailable once loaded, so its
644
+ placeholder keeps the live disabled tone. Each such control carries the component-owned
645
+ `data-kui-disabled="true"` marker whenever its own disabled prop is set, independent of
646
+ `placeholder` — `ListItem` and `ListActionRow` `disabled`, `trailingActionDisabled`,
647
+ a `SegmentedControl` choice's `disabled`, and `ListHeader` `actionDisabled` (on the
648
+ action or disclosure toggle). The placeholder reset skips the marker and components key
649
+ their disabled tone on it, so only the `placeholder`-only `disabled` attribute is
650
+ neutralized. That tone is each component's own, never Web Awesome's native
651
+ `button:disabled`, so an author-disabled control is dimmed with or without
652
+ `webawesome.css`. The marker is reserved: the extension-attribute channels
653
+ (`rootAttributes`, `trailingActionAttributes`, `triggerAttributes`) cannot set it. A
654
+ disabled placeholder still shows the `default` cursor, never `not-allowed`.
655
+ Chrome a component draws itself from a known prop stays live, even inside a slot that
656
+ also holds values. `ListItem`'s trailing slot has three inputs: the `busy` spinner is
657
+ component-owned chrome and stays live, while `status` text and author-supplied
658
+ `trailing` content are values and each become a skeleton (the component cannot tell an
659
+ author's chevron from a count, so all `trailing` content is treated as a value).
660
+ `ListActionRow`'s status line follows the same split: its `busy` spinner stays live and
661
+ only the `status` text becomes a skeleton.
662
+ `SegmentedControl` is the one placeholder without a skeleton: its choices are known
663
+ chrome and only the selection is unknown, so it renders every choice's live label or
664
+ icon at its live geometry, selects none, and neutralizes its own disabled chrome.
665
+ `tests/browser/placeholder-fixture.spec.ts` enforces the rule: it renders every
666
+ placeholder component live and as a placeholder from identical props and diffs each
667
+ element's geometry and computed chrome, excluding only the value slots, and checks that
668
+ every author-disabled control is dimmed in both renders.
669
+
185
670
  Package source styles express root-scaled geometry with `remify(<px>)`; the
186
671
  build converts it against the 16px authoring baseline and exposes only ordinary
187
672
  `rem` CSS. Literal pixels remain for intentional hairlines, and `em` remains
@@ -197,7 +682,25 @@ Kerf JSX declaration boundary for every catalog-supported `wa-*` tag.
197
682
  Consumers register only the individual Web Awesome modules they render and can
198
683
  override `--wa-*` values after the theme import. The shared `--wa-*` values feed
199
684
  both Web Awesome controls and Kerf's `--kui-*` foundation aliases, preventing a
200
- second application palette.
685
+ second application palette. Without the theme, every foundation color token,
686
+ every elevation token (`--kui-shadow-*`), and the focus-ring color fall back to
687
+ the same value the theme assigns, including its `light-dark()` pair, so
688
+ surfaces (including the dark `surface-raised`), links (`text-link` is the brand
689
+ on-quiet text color, not the brand fill), tone text, fills, and raised-surface
690
+ shadows keep their light and dark appearance and contrast either way. The
691
+ theme's elevation shadows are scheme-aware: light keeps the soft Hot Sheet 2
692
+ alphas, and dark raises them (`--wa-shadow-s` 14% to 50% black, `-m` 11% to
693
+ 40%, `-l` 9% to 32%) so a raised surface still separates from a near-black
694
+ page.
695
+ Kerf owns the light `brand`, `success`, and `warning` `on-quiet` values in that
696
+ theme layer: each keeps its hue but is dark enough to clear WCAG AA (4.5:1) on
697
+ the lowered page background (`--kui-color-surface-lowered`, `#f2f2f7`), not
698
+ only on the white surface, so toned text reads on every background a page
699
+ paints. It likewise owns every tone's loud pair: each `on-loud` text color
700
+ clears AA on its `fill-loud` in both schemes. Light brand and danger keep white
701
+ text on a slightly deeper fill of the same hue (`#0075db`, `#eb0005`); success
702
+ keeps its bright green with dark text, as warning does; the dark-mode brand and
703
+ danger fills keep their color with dark text.
201
704
 
202
705
  `Select` owns its custom-element reconciliation seam. It gives each slotted
203
706
  option icon a stable key and leaves the upgraded Web Awesome-owned slot subtree
@@ -216,4 +719,4 @@ Keep product adapters outside the package: connection-state maps, ticket empty-s
216
719
 
217
720
  ## Testing contract
218
721
 
219
- Each behavior has focused unit coverage and a real-browser flow through the production-backed catalog. Consumer bundle tests enforce subpath CSS reachability, transitive component styles, root/SSR isolation, optional registration boundaries, and the CSS-only Web Awesome theme boundary. Visual evidence supplements—never replaces—keyboard, focus, state, and event assertions.
722
+ Each behavior has focused unit coverage and a real-browser flow through the production-backed catalog. Consumer bundle tests enforce subpath CSS reachability, transitive component styles, root/SSR isolation, optional registration boundaries, and the CSS-only Web Awesome theme boundary. `npm run check:css-ownership` rejects application selectors into Kerf or Web Awesome components, a non-minimal catalog compatibility stylesheet, or a return of the shared recipe stylesheet. Visual evidence supplements—never replaces—keyboard, focus, state, and event assertions.