@kerfjs/ui 5.0.0-beta.8 → 5.0.0-beta.81

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 (807) hide show
  1. package/README.md +546 -139
  2. package/ai/application-ui-diagnostic-ids-v1.json +113 -0
  3. package/ai/application-ui-profile-sync.cjs +548 -0
  4. package/ai/application-ui-profile.d.mts +1 -0
  5. package/ai/application-ui-profile.d.ts +106 -0
  6. package/ai/application-ui-profile.defaults.json +96 -0
  7. package/ai/application-ui-profile.mjs +653 -0
  8. package/ai/application-ui-profile.schema.json +140 -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 +104 -0
  14. package/ai/component-catalog.json +4280 -457
  15. package/ai/component-catalog.schema.json +94 -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 +520 -0
  20. package/ai/component-composition.d.ts +129 -0
  21. package/ai/component-composition.json +7401 -0
  22. package/ai/component-composition.schema.json +408 -0
  23. package/ai/components/README.md +171 -0
  24. package/ai/components/application-tabs.md +65 -0
  25. package/ai/components/badge.md +72 -0
  26. package/ai/components/chip.md +72 -0
  27. package/ai/components/collapsible-panel.md +102 -0
  28. package/ai/components/content-item.md +96 -0
  29. package/ai/components/disclosure-arrow.md +77 -0
  30. package/ai/components/document-baseline.md +75 -0
  31. package/ai/components/empty-state.md +80 -0
  32. package/ai/components/feedback.md +71 -0
  33. package/ai/components/floating-toolbar.md +82 -0
  34. package/ai/components/foundation.md +65 -0
  35. package/ai/components/grid.md +100 -0
  36. package/ai/components/headers.md +63 -0
  37. package/ai/components/layout.md +75 -0
  38. package/ai/components/list-action-row.md +91 -0
  39. package/ai/components/list-header.md +91 -0
  40. package/ai/components/list-inset-control.md +74 -0
  41. package/ai/components/list-inset-text.md +72 -0
  42. package/ai/components/list-item.md +94 -0
  43. package/ai/components/list.md +106 -0
  44. package/ai/components/loading-spinner.md +73 -0
  45. package/ai/components/lucide-icon.md +97 -0
  46. package/ai/components/nav-stack.md +105 -0
  47. package/ai/components/pane.md +104 -0
  48. package/ai/components/popup-menu.md +171 -0
  49. package/ai/components/recipe-app-shell.md +57 -0
  50. package/ai/components/recipe-collapsible-sidebar.md +57 -0
  51. package/ai/components/recipe-compact-toolbar.md +57 -0
  52. package/ai/components/recipe-composer-form.md +57 -0
  53. package/ai/components/recipe-list-detail-dialog.md +57 -0
  54. package/ai/components/recipe-list-workspace-states.md +57 -0
  55. package/ai/components/recipe-loading-inspector.md +57 -0
  56. package/ai/components/recipe-navigation-sidebar.md +57 -0
  57. package/ai/components/recipe-navigation-stack.md +57 -0
  58. package/ai/components/recipe-workspace-header.md +57 -0
  59. package/ai/components/resize.md +106 -0
  60. package/ai/components/row.md +96 -0
  61. package/ai/components/segmented-control.md +82 -0
  62. package/ai/components/select.md +115 -0
  63. package/ai/components/skeleton.md +84 -0
  64. package/ai/components/spacer.md +86 -0
  65. package/ai/components/split-view.md +103 -0
  66. package/ai/components/state-banner.md +94 -0
  67. package/ai/components/sunken-panel.md +79 -0
  68. package/ai/components/surface-scaffold.md +87 -0
  69. package/ai/components/tab-bar.md +113 -0
  70. package/ai/components/tab-navigator.md +95 -0
  71. package/ai/components/tabs.md +95 -0
  72. package/ai/components/text.md +87 -0
  73. package/ai/components/token-search-field.md +107 -0
  74. package/ai/components/toolbar-control-group.md +121 -0
  75. package/ai/components/toolbar-text.md +98 -0
  76. package/ai/components/toolbar.md +101 -0
  77. package/ai/components/value-table.md +73 -0
  78. package/ai/components/wa-accordion-item.md +55 -0
  79. package/ai/components/wa-accordion.md +65 -0
  80. package/ai/components/wa-animated-image.md +55 -0
  81. package/ai/components/wa-animation.md +55 -0
  82. package/ai/components/wa-avatar.md +55 -0
  83. package/ai/components/wa-badge.md +55 -0
  84. package/ai/components/wa-breadcrumb-item.md +53 -0
  85. package/ai/components/wa-breadcrumb.md +55 -0
  86. package/ai/components/wa-button-group.md +59 -0
  87. package/ai/components/wa-button.md +55 -0
  88. package/ai/components/wa-callout.md +58 -0
  89. package/ai/components/wa-card.md +59 -0
  90. package/ai/components/wa-carousel-item.md +53 -0
  91. package/ai/components/wa-carousel.md +55 -0
  92. package/ai/components/wa-checkbox-group.md +55 -0
  93. package/ai/components/wa-checkbox.md +55 -0
  94. package/ai/components/wa-color-picker.md +55 -0
  95. package/ai/components/wa-comparison.md +55 -0
  96. package/ai/components/wa-copy-button.md +55 -0
  97. package/ai/components/wa-details.md +61 -0
  98. package/ai/components/wa-dialog.md +59 -0
  99. package/ai/components/wa-divider.md +53 -0
  100. package/ai/components/wa-drawer.md +55 -0
  101. package/ai/components/wa-dropdown-item.md +60 -0
  102. package/ai/components/wa-dropdown.md +60 -0
  103. package/ai/components/wa-format-bytes.md +53 -0
  104. package/ai/components/wa-format-date.md +53 -0
  105. package/ai/components/wa-format-number.md +53 -0
  106. package/ai/components/wa-icon.md +58 -0
  107. package/ai/components/wa-include.md +53 -0
  108. package/ai/components/wa-input.md +59 -0
  109. package/ai/components/wa-intersection-observer.md +53 -0
  110. package/ai/components/wa-known-date.md +53 -0
  111. package/ai/components/wa-markdown.md +53 -0
  112. package/ai/components/wa-mutation-observer.md +53 -0
  113. package/ai/components/wa-number-input.md +55 -0
  114. package/ai/components/wa-option.md +59 -0
  115. package/ai/components/wa-otp-input.md +53 -0
  116. package/ai/components/wa-page.md +53 -0
  117. package/ai/components/wa-pagination.md +55 -0
  118. package/ai/components/wa-popover.md +55 -0
  119. package/ai/components/wa-popup.md +53 -0
  120. package/ai/components/wa-progress-bar.md +53 -0
  121. package/ai/components/wa-progress-ring.md +53 -0
  122. package/ai/components/wa-qr-code.md +53 -0
  123. package/ai/components/wa-radio-group.md +59 -0
  124. package/ai/components/wa-radio.md +55 -0
  125. package/ai/components/wa-random-content.md +53 -0
  126. package/ai/components/wa-rating.md +55 -0
  127. package/ai/components/wa-relative-time.md +53 -0
  128. package/ai/components/wa-resize-observer.md +53 -0
  129. package/ai/components/wa-scroller.md +53 -0
  130. package/ai/components/wa-select.md +63 -0
  131. package/ai/components/wa-skeleton.md +53 -0
  132. package/ai/components/wa-slider.md +55 -0
  133. package/ai/components/wa-spinner.md +58 -0
  134. package/ai/components/wa-split-panel.md +58 -0
  135. package/ai/components/wa-switch.md +53 -0
  136. package/ai/components/wa-tab-group.md +69 -0
  137. package/ai/components/wa-tab-panel.md +60 -0
  138. package/ai/components/wa-tab.md +59 -0
  139. package/ai/components/wa-tag.md +59 -0
  140. package/ai/components/wa-textarea.md +53 -0
  141. package/ai/components/wa-time-input.md +55 -0
  142. package/ai/components/wa-toast-item.md +60 -0
  143. package/ai/components/wa-toast.md +60 -0
  144. package/ai/components/wa-tooltip.md +55 -0
  145. package/ai/components/wa-tree-item.md +55 -0
  146. package/ai/components/wa-tree.md +55 -0
  147. package/ai/components/wa-zoomable-frame.md +55 -0
  148. package/ai/components/workbench.md +119 -0
  149. package/ai/public-api-signatures-v1.md +2821 -250
  150. package/ai/skill.md +354 -66
  151. package/ai/webawesome-jsx-signatures-v1.md +9 -2
  152. package/analyzer/cli.mjs +49 -0
  153. package/analyzer/component-ownership.d.mts +72 -0
  154. package/analyzer/component-ownership.mjs +429 -0
  155. package/analyzer/index.d.mts +53 -0
  156. package/analyzer/index.mjs +2346 -0
  157. package/analyzer/loud-pairs.d.mts +49 -0
  158. package/analyzer/loud-pairs.mjs +357 -0
  159. package/analyzer/report.schema.json +66 -0
  160. package/analyzer/selectors.d.mts +21 -0
  161. package/analyzer/selectors.mjs +212 -0
  162. package/catalog-projection-cli.mjs +96 -0
  163. package/catalog-projection.d.mts +55 -0
  164. package/catalog-projection.mjs +62 -0
  165. package/dist/app-tab.d.ts +39 -4
  166. package/dist/app-tab.js +2 -1
  167. package/dist/badge.d.ts +54 -0
  168. package/dist/badge.js +3 -0
  169. package/dist/badge.js.map +1 -0
  170. package/dist/browser/badge.js +3 -0
  171. package/dist/browser/catalog.js +26 -0
  172. package/dist/browser/chip.js +3 -0
  173. package/dist/browser/collapsible-panel.js +9 -0
  174. package/dist/browser/content-item.js +3 -0
  175. package/dist/browser/floating-toolbar.js +3 -0
  176. package/dist/browser/grid.js +3 -0
  177. package/dist/browser/list-action-row.js +5 -0
  178. package/dist/browser/{menu-header.js → list-header.js} +5 -3
  179. package/dist/browser/list-inset-control.js +3 -0
  180. package/dist/browser/list-inset-text.js +3 -0
  181. package/dist/browser/list-item.js +5 -0
  182. package/dist/browser/list.js +3 -0
  183. package/dist/browser/nav-stack.js +11 -0
  184. package/dist/browser/pane.js +3 -0
  185. package/dist/browser/popup-menu.js +3 -0
  186. package/dist/browser/row.js +3 -0
  187. package/dist/browser/segmented-control.js +0 -1
  188. package/dist/browser/select.js +2 -1
  189. package/dist/browser/spacer.js +3 -0
  190. package/dist/browser/split-view.js +13 -0
  191. package/dist/browser/state-banner.js +1 -0
  192. package/dist/browser/sunken-panel.js +3 -0
  193. package/dist/browser/surface-scaffold.js +3 -0
  194. package/dist/browser/tab-navigator.js +4 -0
  195. package/dist/browser/text.js +3 -0
  196. package/dist/browser/toolbar-control-group.js +1 -0
  197. package/dist/browser/workbench.js +14 -0
  198. package/dist/catalog-resources.d.ts +48 -0
  199. package/dist/catalog-resources.js +22 -0
  200. package/dist/catalog-resources.js.map +1 -0
  201. package/dist/catalog.d.ts +92 -0
  202. package/dist/catalog.js +541 -0
  203. package/dist/catalog.js.map +1 -0
  204. package/dist/chip.d.ts +36 -0
  205. package/dist/chip.js +3 -0
  206. package/dist/chip.js.map +1 -0
  207. package/dist/chunk-2GOCOLQL.js +270 -0
  208. package/dist/chunk-2GOCOLQL.js.map +1 -0
  209. package/dist/chunk-3CXRQAYT.js +288 -0
  210. package/dist/chunk-3CXRQAYT.js.map +1 -0
  211. package/dist/chunk-3RE2JMZU.js +48 -0
  212. package/dist/chunk-3RE2JMZU.js.map +1 -0
  213. package/dist/chunk-3SXWV2IR.js +295 -0
  214. package/dist/chunk-3SXWV2IR.js.map +1 -0
  215. package/dist/chunk-3XPGJUUQ.js +37 -0
  216. package/dist/chunk-3XPGJUUQ.js.map +1 -0
  217. package/dist/chunk-4Y4L5YEI.js +66 -0
  218. package/dist/chunk-4Y4L5YEI.js.map +1 -0
  219. package/dist/chunk-5BZBIRQG.js +452 -0
  220. package/dist/chunk-5BZBIRQG.js.map +1 -0
  221. package/dist/chunk-5D3WDMIK.js +71 -0
  222. package/dist/chunk-5D3WDMIK.js.map +1 -0
  223. package/dist/chunk-62VMNBV2.js +779 -0
  224. package/dist/chunk-62VMNBV2.js.map +1 -0
  225. package/dist/chunk-75I3SNUJ.js +44 -0
  226. package/dist/chunk-75I3SNUJ.js.map +1 -0
  227. package/dist/chunk-7QQ3HE47.js +17 -0
  228. package/dist/chunk-7QQ3HE47.js.map +1 -0
  229. package/dist/chunk-7TE6XDFI.js +91 -0
  230. package/dist/chunk-7TE6XDFI.js.map +1 -0
  231. package/dist/chunk-A7DYEERU.js +59 -0
  232. package/dist/chunk-A7DYEERU.js.map +1 -0
  233. package/dist/chunk-AN5IWMTM.js +24 -0
  234. package/dist/chunk-AN5IWMTM.js.map +1 -0
  235. package/dist/chunk-ARZ4RSQO.js +48 -0
  236. package/dist/chunk-ARZ4RSQO.js.map +1 -0
  237. package/dist/chunk-BJLXE56E.js +135 -0
  238. package/dist/chunk-BJLXE56E.js.map +1 -0
  239. package/dist/chunk-BYHGRKC3.js +44 -0
  240. package/dist/chunk-BYHGRKC3.js.map +1 -0
  241. package/dist/chunk-CEJ5FK6G.js +288 -0
  242. package/dist/chunk-CEJ5FK6G.js.map +1 -0
  243. package/dist/chunk-CVKIADIS.js +172 -0
  244. package/dist/chunk-CVKIADIS.js.map +1 -0
  245. package/dist/chunk-DQDTZE4W.js +70 -0
  246. package/dist/chunk-DQDTZE4W.js.map +1 -0
  247. package/dist/chunk-EFDCALR3.js +66 -0
  248. package/dist/chunk-EFDCALR3.js.map +1 -0
  249. package/dist/chunk-FL6J644M.js +116 -0
  250. package/dist/chunk-FL6J644M.js.map +1 -0
  251. package/dist/chunk-GS2QD3N7.js +14 -0
  252. package/dist/chunk-GS2QD3N7.js.map +1 -0
  253. package/dist/chunk-H45DAZBL.js +491 -0
  254. package/dist/chunk-H45DAZBL.js.map +1 -0
  255. package/dist/chunk-H7ZJEI3H.js +52 -0
  256. package/dist/chunk-H7ZJEI3H.js.map +1 -0
  257. package/dist/chunk-HFLGWMG3.js +138 -0
  258. package/dist/chunk-HFLGWMG3.js.map +1 -0
  259. package/dist/chunk-HFQDSSED.js +188 -0
  260. package/dist/chunk-HFQDSSED.js.map +1 -0
  261. package/dist/{chunk-56RJXPHG.js → chunk-I4SDIMFA.js} +7 -4
  262. package/dist/chunk-I4SDIMFA.js.map +1 -0
  263. package/dist/chunk-IM3GKYOG.js +202 -0
  264. package/dist/chunk-IM3GKYOG.js.map +1 -0
  265. package/dist/chunk-J3AWE5I4.js +50 -0
  266. package/dist/chunk-J3AWE5I4.js.map +1 -0
  267. package/dist/chunk-JOR5LGYE.js +55 -0
  268. package/dist/chunk-JOR5LGYE.js.map +1 -0
  269. package/dist/chunk-JZM3G6RT.js +149 -0
  270. package/dist/chunk-JZM3G6RT.js.map +1 -0
  271. package/dist/{chunk-7BR3DO2A.js → chunk-LAZLBC2Q.js} +14 -5
  272. package/dist/chunk-LAZLBC2Q.js.map +1 -0
  273. package/dist/chunk-LQKY5S4F.js +506 -0
  274. package/dist/chunk-LQKY5S4F.js.map +1 -0
  275. package/dist/chunk-LRAIS3YB.js +158 -0
  276. package/dist/chunk-LRAIS3YB.js.map +1 -0
  277. package/dist/chunk-MXNIVEVL.js +48 -0
  278. package/dist/chunk-MXNIVEVL.js.map +1 -0
  279. package/dist/chunk-NJZMR7HM.js +135 -0
  280. package/dist/chunk-NJZMR7HM.js.map +1 -0
  281. package/dist/chunk-NMWDHZVM.js +35 -0
  282. package/dist/chunk-NMWDHZVM.js.map +1 -0
  283. package/dist/{chunk-YGN7OMLT.js → chunk-NS2TBYM4.js} +8 -5
  284. package/dist/chunk-NS2TBYM4.js.map +1 -0
  285. package/dist/chunk-NVKRZ5DI.js +222 -0
  286. package/dist/chunk-NVKRZ5DI.js.map +1 -0
  287. package/dist/chunk-NVRJ7C3W.js +83 -0
  288. package/dist/chunk-NVRJ7C3W.js.map +1 -0
  289. package/dist/chunk-O27D24CA.js +250 -0
  290. package/dist/chunk-O27D24CA.js.map +1 -0
  291. package/dist/chunk-PQQQXJGV.js +58 -0
  292. package/dist/chunk-PQQQXJGV.js.map +1 -0
  293. package/dist/chunk-RRCD3A6G.js +139 -0
  294. package/dist/chunk-RRCD3A6G.js.map +1 -0
  295. package/dist/chunk-S3ECMF23.js +33 -0
  296. package/dist/chunk-S3ECMF23.js.map +1 -0
  297. package/dist/chunk-S4ZGTDSG.js +18 -0
  298. package/dist/chunk-S4ZGTDSG.js.map +1 -0
  299. package/dist/chunk-VHXHLZ6R.js +69 -0
  300. package/dist/chunk-VHXHLZ6R.js.map +1 -0
  301. package/dist/chunk-VIGVNDXZ.js +165 -0
  302. package/dist/chunk-VIGVNDXZ.js.map +1 -0
  303. package/dist/chunk-VR7MWD2X.js +91 -0
  304. package/dist/chunk-VR7MWD2X.js.map +1 -0
  305. package/dist/chunk-Y6KT7ZTR.js +109 -0
  306. package/dist/chunk-Y6KT7ZTR.js.map +1 -0
  307. package/dist/chunk-YLJ6X3AC.js +34 -0
  308. package/dist/chunk-YLJ6X3AC.js.map +1 -0
  309. package/dist/collapsible-panel.d.ts +137 -0
  310. package/dist/collapsible-panel.js +135 -0
  311. package/dist/collapsible-panel.js.map +1 -0
  312. package/dist/content-item.d.ts +99 -0
  313. package/dist/content-item.js +4 -0
  314. package/dist/content-item.js.map +1 -0
  315. package/dist/css-values.d.ts +112 -0
  316. package/dist/css-values.js +3 -0
  317. package/dist/css-values.js.map +1 -0
  318. package/dist/device-class.js +34 -6
  319. package/dist/device-class.js.map +1 -1
  320. package/dist/disclosure-arrow.d.ts +6 -1
  321. package/dist/disclosure-arrow.js +2 -1
  322. package/dist/empty-state.d.ts +5 -2
  323. package/dist/empty-state.js +2 -1
  324. package/dist/flex-alignment-4ms8ZbV8.d.ts +5 -0
  325. package/dist/floating-toolbar.d.ts +51 -0
  326. package/dist/floating-toolbar.js +3 -0
  327. package/dist/floating-toolbar.js.map +1 -0
  328. package/dist/grid.d.ts +57 -0
  329. package/dist/grid.js +5 -0
  330. package/dist/grid.js.map +1 -0
  331. package/dist/help-tags-register.d.ts +13 -0
  332. package/dist/help-tags-register.js +9 -0
  333. package/dist/help-tags-register.js.map +1 -0
  334. package/dist/index.d.ts +40 -18
  335. package/dist/index.js +44 -23
  336. package/dist/{menu-action-row.d.ts → list-action-row.d.ts} +21 -9
  337. package/dist/list-action-row.js +8 -0
  338. package/dist/list-action-row.js.map +1 -0
  339. package/dist/list-header.d.ts +98 -0
  340. package/dist/list-header.js +10 -0
  341. package/dist/list-header.js.map +1 -0
  342. package/dist/list-inset-control.d.ts +22 -0
  343. package/dist/list-inset-control.js +3 -0
  344. package/dist/list-inset-control.js.map +1 -0
  345. package/dist/list-inset-text.d.ts +30 -0
  346. package/dist/list-inset-text.js +4 -0
  347. package/dist/list-inset-text.js.map +1 -0
  348. package/dist/list-item.d.ts +62 -0
  349. package/dist/list-item.js +8 -0
  350. package/dist/list-item.js.map +1 -0
  351. package/dist/list.d.ts +63 -0
  352. package/dist/list.js +6 -0
  353. package/dist/list.js.map +1 -0
  354. package/dist/loading-spinner.d.ts +12 -2
  355. package/dist/loading-spinner.js +2 -1
  356. package/dist/lucide-icon.d.ts +14 -2
  357. package/dist/lucide-icon.js +2 -1
  358. package/dist/nav-stack-B1Qc2e5q.d.ts +101 -0
  359. package/dist/nav-stack.d.ts +13 -38
  360. package/dist/nav-stack.js +10 -1
  361. package/dist/pane.d.ts +116 -0
  362. package/dist/pane.js +4 -0
  363. package/dist/pane.js.map +1 -0
  364. package/dist/panel-toolbar-CL9tYOkh.d.ts +72 -0
  365. package/dist/popup-menu-register.d.ts +9 -0
  366. package/dist/popup-menu-register.js +244 -0
  367. package/dist/popup-menu-register.js.map +1 -0
  368. package/dist/popup-menu.d.ts +100 -0
  369. package/dist/popup-menu.js +3 -0
  370. package/dist/popup-menu.js.map +1 -0
  371. package/dist/resizable-region.d.ts +32 -3
  372. package/dist/resizable-region.js +1 -1
  373. package/dist/row.d.ts +48 -0
  374. package/dist/row.js +6 -0
  375. package/dist/row.js.map +1 -0
  376. package/dist/segmented-control.d.ts +12 -9
  377. package/dist/segmented-control.js +1 -2
  378. package/dist/select-register.d.ts +5 -1
  379. package/dist/select-register.js +247 -3
  380. package/dist/select-register.js.map +1 -1
  381. package/dist/select.d.ts +103 -8
  382. package/dist/select.js +3 -1
  383. package/dist/semantic-content-BbzjvSu9.d.ts +14 -0
  384. package/dist/semantic-tone-CdW013KF.d.ts +4 -0
  385. package/dist/sides-BPSWde0A.d.ts +4 -0
  386. package/dist/skeleton.d.ts +14 -7
  387. package/dist/skeleton.js +2 -1
  388. package/dist/spacer.d.ts +18 -0
  389. package/dist/spacer.js +4 -0
  390. package/dist/spacer.js.map +1 -0
  391. package/dist/split-view.d.ts +44 -7
  392. package/dist/split-view.js +124 -10
  393. package/dist/split-view.js.map +1 -1
  394. package/dist/state-banner.d.ts +21 -7
  395. package/dist/state-banner.js +3 -1
  396. package/dist/styles/app-tab.css +224 -0
  397. package/dist/styles/badge.css +118 -0
  398. package/dist/styles/catalog/components/catalog-example-stack.css +9 -0
  399. package/dist/styles/catalog/components/catalog-example.css +168 -0
  400. package/dist/styles/catalog/components/catalog-stage.css +55 -0
  401. package/dist/styles/catalog/components/catalog.css +50 -0
  402. package/dist/styles/catalog.css +5 -0
  403. package/dist/styles/chip.css +138 -0
  404. package/dist/styles/collapsible-panel.css +580 -0
  405. package/dist/styles/components/actions/floating-toolbar/floating-toolbar.css +119 -0
  406. package/dist/styles/components/actions/popup-menu/popup-menu.css +285 -0
  407. package/dist/styles/components/actions/toolbar/toolbar.css +417 -0
  408. package/dist/styles/components/actions/toolbar-control-group/toolbar-control-group.css +891 -0
  409. package/dist/styles/components/actions/toolbar-text/toolbar-text.css +171 -0
  410. package/dist/styles/components/collections/list/list.css +133 -0
  411. package/dist/styles/components/collections/list-action-row/list-action-row.css +258 -0
  412. package/dist/styles/components/collections/list-header/list-header.css +229 -0
  413. package/dist/styles/components/collections/list-inset-control/list-inset-control.css +30 -0
  414. package/dist/styles/components/collections/list-inset-text/list-inset-text.css +29 -0
  415. package/dist/styles/components/collections/list-item/list-item.css +255 -0
  416. package/dist/styles/components/data-display/value-table/value-table.css +105 -0
  417. package/dist/styles/components/feedback/badge/badge.css +118 -0
  418. package/dist/styles/components/feedback/chip/chip.css +138 -0
  419. package/dist/styles/components/feedback/empty-state/empty-state.css +47 -0
  420. package/dist/styles/components/feedback/loading-spinner/loading-spinner.css +25 -0
  421. package/dist/styles/components/feedback/skeleton/skeleton.css +92 -0
  422. package/dist/styles/components/feedback/state-banner/state-banner.css +248 -0
  423. package/dist/styles/components/forms/segmented-control/segmented-control.css +196 -0
  424. package/dist/styles/components/forms/select/select.css +454 -0
  425. package/dist/styles/components/forms/token-search-field/token-search-field.css +392 -0
  426. package/dist/styles/components/layout/collapsible-panel/collapsible-panel.css +580 -0
  427. package/dist/styles/components/layout/grid/grid.css +85 -0
  428. package/dist/styles/components/layout/pane/pane.css +294 -0
  429. package/dist/styles/components/layout/resizable-region/resizable-region.css +545 -0
  430. package/dist/styles/components/layout/row/row.css +111 -0
  431. package/dist/styles/components/layout/spacer/spacer.css +11 -0
  432. package/dist/styles/components/layout/split-view/split-view.css +146 -0
  433. package/dist/styles/components/layout/workbench/workbench.css +1075 -0
  434. package/dist/styles/components/media/lucide-icon/lucide-icon.css +15 -0
  435. package/dist/styles/components/navigation/app-tab/app-tab.css +376 -0
  436. package/dist/styles/components/navigation/disclosure-arrow/disclosure-arrow.css +23 -0
  437. package/dist/styles/components/navigation/nav-stack/nav-stack.css +242 -0
  438. package/dist/styles/components/navigation/tab-bar/tab-bar.css +183 -0
  439. package/dist/styles/components/navigation/tab-navigator/tab-navigator.css +237 -0
  440. package/dist/styles/components/surfaces/content-item/content-item.css +120 -0
  441. package/dist/styles/components/surfaces/sunken-panel/sunken-panel.css +34 -0
  442. package/dist/styles/components/surfaces/surface-scaffold/surface-scaffold.css +111 -0
  443. package/dist/styles/components/typography/text/text.css +158 -0
  444. package/dist/styles/content-item.css +120 -0
  445. package/dist/styles/document.css +33 -0
  446. package/dist/styles/floating-toolbar.css +119 -0
  447. package/dist/styles/foundation.css +187 -45
  448. package/dist/styles/grid.css +85 -0
  449. package/dist/styles/layout.css +3 -41
  450. package/dist/styles/list-action-row.css +258 -0
  451. package/dist/styles/list-header.css +229 -0
  452. package/dist/styles/list-inset-control.css +30 -0
  453. package/dist/styles/list-inset-text.css +29 -0
  454. package/dist/styles/list-item.css +255 -0
  455. package/dist/styles/list.css +133 -0
  456. package/dist/styles/loading-spinner.css +4 -0
  457. package/dist/styles/lucide-icon.css +9 -0
  458. package/dist/styles/nav-stack.css +180 -50
  459. package/dist/styles/pane.css +294 -0
  460. package/dist/styles/popup-menu.css +285 -0
  461. package/dist/styles/resizable-region.css +438 -4
  462. package/dist/styles/row.css +111 -0
  463. package/dist/styles/segmented-control.css +36 -9
  464. package/dist/styles/select.css +337 -21
  465. package/dist/styles/skeleton.css +64 -3
  466. package/dist/styles/spacer.css +11 -0
  467. package/dist/styles/split-view.css +114 -3
  468. package/dist/styles/state-banner.css +94 -19
  469. package/dist/styles/styles.css +13 -4
  470. package/dist/styles/sunken-panel.css +34 -0
  471. package/dist/styles/surface-scaffold.css +111 -0
  472. package/dist/styles/tab-bar.css +147 -9
  473. package/dist/styles/tab-navigator.css +237 -0
  474. package/dist/styles/text.css +158 -0
  475. package/dist/styles/token-search-field.css +167 -56
  476. package/dist/styles/toolbar-control-group.css +710 -30
  477. package/dist/styles/toolbar-text.css +139 -8
  478. package/dist/styles/toolbar.css +367 -11
  479. package/dist/styles/value-table.css +34 -4
  480. package/dist/styles/webawesome.css +388 -16
  481. package/dist/styles/workbench.css +988 -7
  482. package/dist/sunken-panel.d.ts +31 -0
  483. package/dist/sunken-panel.js +3 -0
  484. package/dist/sunken-panel.js.map +1 -0
  485. package/dist/surface-scaffold-register.d.ts +4 -0
  486. package/dist/surface-scaffold-register.js +59 -0
  487. package/dist/surface-scaffold-register.js.map +1 -0
  488. package/dist/surface-scaffold.d.ts +38 -0
  489. package/dist/surface-scaffold.js +3 -0
  490. package/dist/surface-scaffold.js.map +1 -0
  491. package/dist/tab-bar.d.ts +39 -6
  492. package/dist/tab-bar.js +1 -1
  493. package/dist/tab-navigator.d.ts +86 -0
  494. package/dist/tab-navigator.js +95 -0
  495. package/dist/tab-navigator.js.map +1 -0
  496. package/dist/text.d.ts +63 -0
  497. package/dist/text.js +3 -0
  498. package/dist/text.js.map +1 -0
  499. package/dist/token-search-field.d.ts +3 -43
  500. package/dist/token-search-field.js +2 -1
  501. package/dist/token-search-model-DTcTXWMS.d.ts +154 -0
  502. package/dist/token-search-model.d.ts +3 -0
  503. package/dist/token-search-model.js +3 -0
  504. package/dist/token-search-model.js.map +1 -0
  505. package/dist/toolbar-control-group.d.ts +89 -7
  506. package/dist/toolbar-control-group.js +3 -1
  507. package/dist/toolbar-text.d.ts +45 -9
  508. package/dist/toolbar-text.js +2 -1
  509. package/dist/toolbar.d.ts +59 -7
  510. package/dist/toolbar.js +1 -1
  511. package/dist/types-C9BubXfz.d.ts +117 -0
  512. package/dist/value-table.d.ts +11 -3
  513. package/dist/value-table.js +2 -1
  514. package/dist/webawesome.d.ts +8 -1
  515. package/dist/wire-catalog.d.ts +82 -0
  516. package/dist/wire-catalog.js +407 -0
  517. package/dist/wire-catalog.js.map +1 -0
  518. package/dist/wire-content-items.d.ts +11 -0
  519. package/dist/wire-content-items.js +114 -0
  520. package/dist/wire-content-items.js.map +1 -0
  521. package/dist/wire-nav-stack.d.ts +4 -1
  522. package/dist/wire-nav-stack.js +191 -15
  523. package/dist/wire-nav-stack.js.map +1 -1
  524. package/dist/wire-resizable-regions.d.ts +2 -1
  525. package/dist/wire-resizable-regions.js +2 -1
  526. package/dist/wire-scroll-dividers.d.ts +72 -0
  527. package/dist/wire-scroll-dividers.js +3 -0
  528. package/dist/wire-scroll-dividers.js.map +1 -0
  529. package/dist/wire-sidebar.d.ts +63 -0
  530. package/dist/wire-sidebar.js +231 -0
  531. package/dist/wire-sidebar.js.map +1 -0
  532. package/dist/wire-tab-bars.d.ts +19 -2
  533. package/dist/wire-tab-bars.js +1 -1
  534. package/dist/wire-tab-navigator.d.ts +11 -0
  535. package/dist/wire-tab-navigator.js +21 -0
  536. package/dist/wire-tab-navigator.js.map +1 -0
  537. package/dist/wire-token-search-fields.d.ts +65 -3
  538. package/dist/wire-token-search-fields.js +2 -1
  539. package/dist/wire-toolbar-visibility.d.ts +13 -0
  540. package/dist/wire-toolbar-visibility.js +3 -0
  541. package/dist/wire-toolbar-visibility.js.map +1 -0
  542. package/dist/wire-workbench.d.ts +116 -0
  543. package/dist/wire-workbench.js +6 -0
  544. package/dist/wire-workbench.js.map +1 -0
  545. package/dist/workbench.d.ts +246 -9
  546. package/dist/workbench.js +17 -15
  547. package/dist/workbench.js.map +1 -1
  548. package/docs/accessibility.md +497 -26
  549. package/docs/app-layouts.md +141 -10
  550. package/docs/apple-hig.md +1 -0
  551. package/docs/catalog.md +493 -0
  552. package/docs/collapsible-panel.md +382 -0
  553. package/docs/component-contract.md +736 -61
  554. package/docs/component-integration.md +75 -0
  555. package/docs/component-selection.md +619 -97
  556. package/docs/design/templates/empty-state/filtered-dark.svg +1 -0
  557. package/docs/design/templates/empty-state/filtered.svg +1 -0
  558. package/docs/design/templates/empty-state/with-action-dark.svg +1 -0
  559. package/docs/design/templates/empty-state/with-action.svg +1 -0
  560. package/docs/design/templates/empty-state-dark.svg +1 -0
  561. package/docs/design/templates/empty-state.svg +1 -0
  562. package/docs/design/templates/list/compact-dark.svg +1 -0
  563. package/docs/design/templates/list/compact.svg +1 -0
  564. package/docs/design/templates/list/stack-dark.svg +1 -0
  565. package/docs/design/templates/list/stack.svg +1 -0
  566. package/docs/design/templates/list-action-row/default-dark.svg +1 -0
  567. package/docs/design/templates/list-action-row/default.svg +1 -0
  568. package/docs/design/templates/list-action-row/selected-dark.svg +1 -0
  569. package/docs/design/templates/list-action-row/selected.svg +1 -0
  570. package/docs/design/templates/list-action-row-dark.svg +1 -0
  571. package/docs/design/templates/list-action-row.svg +1 -0
  572. package/docs/design/templates/list-dark.svg +1 -0
  573. package/docs/design/templates/list-header/action-dark.svg +1 -0
  574. package/docs/design/templates/list-header/action.svg +1 -0
  575. package/docs/design/templates/list-header/count-dark.svg +1 -0
  576. package/docs/design/templates/list-header/count.svg +1 -0
  577. package/docs/design/templates/list-header/inline-action-dark.svg +1 -0
  578. package/docs/design/templates/list-header/inline-action.svg +1 -0
  579. package/docs/design/templates/list-header/size-l-dark.svg +1 -0
  580. package/docs/design/templates/list-header/size-l.svg +1 -0
  581. package/docs/design/templates/list-header/size-m-dark.svg +1 -0
  582. package/docs/design/templates/list-header/size-m.svg +1 -0
  583. package/docs/design/templates/list-header/size-xl-dark.svg +1 -0
  584. package/docs/design/templates/list-header/size-xl.svg +1 -0
  585. package/docs/design/templates/list-header/size-xs-dark.svg +1 -0
  586. package/docs/design/templates/list-header/size-xs.svg +1 -0
  587. package/docs/design/templates/list-header/toggle-collapsed-dark.svg +1 -0
  588. package/docs/design/templates/list-header/toggle-collapsed.svg +1 -0
  589. package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -0
  590. package/docs/design/templates/list-header/toggle-expanded.svg +1 -0
  591. package/docs/design/templates/list-header-dark.svg +1 -0
  592. package/docs/design/templates/list-header.svg +1 -0
  593. package/docs/design/templates/list-item/default-dark.svg +1 -0
  594. package/docs/design/templates/list-item/default.svg +1 -0
  595. package/docs/design/templates/list-item/multiline-dark.svg +1 -0
  596. package/docs/design/templates/list-item/multiline.svg +1 -0
  597. package/docs/design/templates/list-item/selected-dark.svg +1 -0
  598. package/docs/design/templates/list-item/selected.svg +1 -0
  599. package/docs/design/templates/list-item/trailing-dark.svg +1 -0
  600. package/docs/design/templates/list-item/trailing.svg +1 -0
  601. package/docs/design/templates/list-item-dark.svg +1 -0
  602. package/docs/design/templates/list-item.svg +1 -0
  603. package/docs/design/templates/list.svg +1 -0
  604. package/docs/design/templates/segmented-control/equal-dark.svg +1 -0
  605. package/docs/design/templates/segmented-control/equal.svg +1 -0
  606. package/docs/design/templates/segmented-control/pill-small-dark.svg +1 -0
  607. package/docs/design/templates/segmented-control/pill-small.svg +1 -0
  608. package/docs/design/templates/segmented-control-dark.svg +1 -0
  609. package/docs/design/templates/segmented-control.svg +1 -0
  610. package/docs/design/templates/skeleton/avatar-dark.svg +1 -0
  611. package/docs/design/templates/skeleton/avatar.svg +1 -0
  612. package/docs/design/templates/skeleton/block-dark.svg +1 -0
  613. package/docs/design/templates/skeleton/block.svg +1 -0
  614. package/docs/design/templates/skeleton/lines-dark.svg +1 -0
  615. package/docs/design/templates/skeleton/lines.svg +1 -0
  616. package/docs/design/templates/skeleton-dark.svg +1 -0
  617. package/docs/design/templates/skeleton.svg +1 -0
  618. package/docs/design/templates/state-banner/danger-dark.svg +1 -0
  619. package/docs/design/templates/state-banner/danger.svg +1 -0
  620. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -0
  621. package/docs/design/templates/state-banner/info-badge.svg +1 -0
  622. package/docs/design/templates/state-banner/info-dark.svg +1 -0
  623. package/docs/design/templates/state-banner/info.svg +1 -0
  624. package/docs/design/templates/state-banner/success-dark.svg +1 -0
  625. package/docs/design/templates/state-banner/success.svg +1 -0
  626. package/docs/design/templates/state-banner/warning-dark.svg +1 -0
  627. package/docs/design/templates/state-banner/warning.svg +1 -0
  628. package/docs/design/templates/state-banner-dark.svg +1 -0
  629. package/docs/design/templates/state-banner.svg +1 -0
  630. package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -0
  631. package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -0
  632. package/docs/design/templates/tab-bar-dark.svg +1 -0
  633. package/docs/design/templates/tab-bar.svg +1 -0
  634. package/docs/design/templates/token-search-field/empty-dark.svg +1 -0
  635. package/docs/design/templates/token-search-field/empty.svg +1 -0
  636. package/docs/design/templates/token-search-field/tokens-dark.svg +1 -0
  637. package/docs/design/templates/token-search-field/tokens.svg +1 -0
  638. package/docs/design/templates/token-search-field-dark.svg +1 -0
  639. package/docs/design/templates/token-search-field.svg +1 -0
  640. package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -0
  641. package/docs/design/templates/toolbar/title-and-actions.svg +1 -0
  642. package/docs/design/templates/toolbar/width-visibility-320-dark.svg +1 -0
  643. package/docs/design/templates/toolbar/width-visibility-320.svg +1 -0
  644. package/docs/design/templates/toolbar/width-visibility-600-dark.svg +1 -0
  645. package/docs/design/templates/toolbar/width-visibility-600.svg +1 -0
  646. package/docs/design/templates/toolbar-control-group/borderless-single-dark.svg +1 -0
  647. package/docs/design/templates/toolbar-control-group/borderless-single.svg +1 -0
  648. package/docs/design/templates/toolbar-control-group/icon-buttons-dark.svg +1 -0
  649. package/docs/design/templates/toolbar-control-group/icon-buttons.svg +1 -0
  650. package/docs/design/templates/toolbar-control-group/icon-tile-brand-dark.svg +1 -0
  651. package/docs/design/templates/toolbar-control-group/icon-tile-brand.svg +1 -0
  652. package/docs/design/templates/toolbar-control-group/icon-tile-danger-dark.svg +1 -0
  653. package/docs/design/templates/toolbar-control-group/icon-tile-danger.svg +1 -0
  654. package/docs/design/templates/toolbar-control-group/icon-tile-neutral-dark.svg +1 -0
  655. package/docs/design/templates/toolbar-control-group/icon-tile-neutral.svg +1 -0
  656. package/docs/design/templates/toolbar-control-group/icon-tile-success-dark.svg +1 -0
  657. package/docs/design/templates/toolbar-control-group/icon-tile-success.svg +1 -0
  658. package/docs/design/templates/toolbar-control-group/icon-tile-warning-dark.svg +1 -0
  659. package/docs/design/templates/toolbar-control-group/icon-tile-warning.svg +1 -0
  660. package/docs/design/templates/toolbar-control-group/push-buttons-dark.svg +1 -0
  661. package/docs/design/templates/toolbar-control-group/push-buttons.svg +1 -0
  662. package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -0
  663. package/docs/design/templates/toolbar-control-group/with-text.svg +1 -0
  664. package/docs/design/templates/toolbar-control-group-dark.svg +1 -0
  665. package/docs/design/templates/toolbar-control-group.svg +1 -0
  666. package/docs/design/templates/toolbar-dark.svg +1 -0
  667. package/docs/design/templates/toolbar-text/dark-tone-dark.svg +1 -0
  668. package/docs/design/templates/toolbar-text/dark-tone.svg +1 -0
  669. package/docs/design/templates/toolbar-text/default-dark.svg +1 -0
  670. package/docs/design/templates/toolbar-text/default.svg +1 -0
  671. package/docs/design/templates/toolbar-text/large-dark.svg +1 -0
  672. package/docs/design/templates/toolbar-text/large.svg +1 -0
  673. package/docs/design/templates/toolbar-text/small-dark.svg +1 -0
  674. package/docs/design/templates/toolbar-text/small.svg +1 -0
  675. package/docs/design/templates/toolbar-text-dark.svg +1 -0
  676. package/docs/design/templates/toolbar-text.svg +1 -0
  677. package/docs/design/templates/toolbar.svg +1 -0
  678. package/docs/design/templates/value-table/details-dark.svg +1 -0
  679. package/docs/design/templates/value-table/details.svg +1 -0
  680. package/docs/design/templates/value-table-dark.svg +1 -0
  681. package/docs/design/templates/value-table.svg +1 -0
  682. package/docs/design/templates.md +140 -0
  683. package/docs/design-philosophy.md +48 -20
  684. package/docs/device-class.md +10 -9
  685. package/docs/document-baseline.md +42 -0
  686. package/docs/examples/application-ui-profile.json +60 -0
  687. package/docs/examples/command-palette-adapter.tsx +69 -17
  688. package/docs/examples/component-catalog-extension.json +52 -0
  689. package/docs/examples/component-composition-extension.json +80 -0
  690. package/docs/layout.md +601 -59
  691. package/docs/nav-stack.md +154 -14
  692. package/docs/recipes.md +142 -55
  693. package/docs/split-view.md +77 -6
  694. package/docs/sunken-panel.md +93 -0
  695. package/docs/surface-scaffold.md +74 -0
  696. package/docs/tab-navigator.md +210 -0
  697. package/docs/type-contracts.md +135 -0
  698. package/docs/ui-analyzer.md +404 -0
  699. package/docs/ui-doctor.md +202 -0
  700. package/docs/ui-evaluator.md +139 -0
  701. package/docs/ux-demo.md +46 -16
  702. package/docs/webawesome-theme.md +188 -16
  703. package/docs/workbench.md +621 -12
  704. package/doctor/cli.mjs +120 -0
  705. package/doctor/component-style-checks.mjs +457 -0
  706. package/doctor/config.schema.json +94 -0
  707. package/doctor/eslint-diagnostics.d.mts +24 -0
  708. package/doctor/eslint-diagnostics.mjs +24 -0
  709. package/doctor/index.d.mts +122 -0
  710. package/doctor/index.mjs +1403 -0
  711. package/doctor/report.schema.json +118 -0
  712. package/evaluator/cli.mjs +89 -0
  713. package/evaluator/index.d.mts +90 -0
  714. package/evaluator/index.mjs +1203 -0
  715. package/evaluator/report.schema.json +152 -0
  716. package/llms.txt +510 -49
  717. package/package.json +266 -44
  718. package/scripts/component-catalog-extension-validation.mjs +28 -0
  719. package/traversal-exclusions.mjs +27 -0
  720. package/ux-demo/recipes/app-shell.tsx +205 -17
  721. package/ux-demo/recipes/collapsible-sidebar.tsx +260 -0
  722. package/ux-demo/recipes/compact-toolbar.tsx +135 -14
  723. package/ux-demo/recipes/composer-form.tsx +133 -21
  724. package/ux-demo/recipes/list-detail-dialog.tsx +286 -0
  725. package/ux-demo/recipes/list-workspace-states.tsx +183 -11
  726. package/ux-demo/recipes/loaders.ts +15 -5
  727. package/ux-demo/recipes/loading-inspector.tsx +204 -0
  728. package/ux-demo/recipes/mount-recipe.ts +28 -10
  729. package/ux-demo/recipes/navigation-sidebar.tsx +139 -13
  730. package/ux-demo/recipes/navigation-stack.tsx +81 -26
  731. package/ux-demo/recipes/types.ts +23 -2
  732. package/ux-demo/recipes/workspace-header.tsx +86 -5
  733. package/dist/browser/menu-action-row.js +0 -4
  734. package/dist/browser/menu-item.js +0 -4
  735. package/dist/browser/panel-header.js +0 -7
  736. package/dist/chunk-2RJBFNB6.js +0 -172
  737. package/dist/chunk-2RJBFNB6.js.map +0 -1
  738. package/dist/chunk-2Z5TWHKQ.js +0 -34
  739. package/dist/chunk-2Z5TWHKQ.js.map +0 -1
  740. package/dist/chunk-3YD6ZNRA.js +0 -34
  741. package/dist/chunk-3YD6ZNRA.js.map +0 -1
  742. package/dist/chunk-55DATV3A.js +0 -10
  743. package/dist/chunk-55DATV3A.js.map +0 -1
  744. package/dist/chunk-56RJXPHG.js.map +0 -1
  745. package/dist/chunk-7BR3DO2A.js.map +0 -1
  746. package/dist/chunk-7LDCTU7D.js +0 -134
  747. package/dist/chunk-7LDCTU7D.js.map +0 -1
  748. package/dist/chunk-AQNKJRFH.js +0 -79
  749. package/dist/chunk-AQNKJRFH.js.map +0 -1
  750. package/dist/chunk-B24C4A6T.js +0 -22
  751. package/dist/chunk-B24C4A6T.js.map +0 -1
  752. package/dist/chunk-BLK3UEEI.js +0 -23
  753. package/dist/chunk-BLK3UEEI.js.map +0 -1
  754. package/dist/chunk-BNQ2YDV4.js +0 -20
  755. package/dist/chunk-BNQ2YDV4.js.map +0 -1
  756. package/dist/chunk-DAFFDO33.js +0 -14
  757. package/dist/chunk-DAFFDO33.js.map +0 -1
  758. package/dist/chunk-H6URQGJI.js +0 -42
  759. package/dist/chunk-H6URQGJI.js.map +0 -1
  760. package/dist/chunk-I7INRJO4.js +0 -17
  761. package/dist/chunk-I7INRJO4.js.map +0 -1
  762. package/dist/chunk-LC3YSAZC.js +0 -39
  763. package/dist/chunk-LC3YSAZC.js.map +0 -1
  764. package/dist/chunk-M5JRI6MN.js +0 -27
  765. package/dist/chunk-M5JRI6MN.js.map +0 -1
  766. package/dist/chunk-MBR3TYNL.js +0 -14
  767. package/dist/chunk-MBR3TYNL.js.map +0 -1
  768. package/dist/chunk-MFKMHK5W.js +0 -10
  769. package/dist/chunk-MFKMHK5W.js.map +0 -1
  770. package/dist/chunk-MQIZAD4A.js +0 -227
  771. package/dist/chunk-MQIZAD4A.js.map +0 -1
  772. package/dist/chunk-PONXLV5U.js +0 -19
  773. package/dist/chunk-PONXLV5U.js.map +0 -1
  774. package/dist/chunk-RUNWEPR4.js +0 -10
  775. package/dist/chunk-RUNWEPR4.js.map +0 -1
  776. package/dist/chunk-W2FK7ZNY.js +0 -26
  777. package/dist/chunk-W2FK7ZNY.js.map +0 -1
  778. package/dist/chunk-WVPYVDXY.js +0 -15
  779. package/dist/chunk-WVPYVDXY.js.map +0 -1
  780. package/dist/chunk-YGN7OMLT.js.map +0 -1
  781. package/dist/chunk-YKUUZPED.js +0 -24
  782. package/dist/chunk-YKUUZPED.js.map +0 -1
  783. package/dist/menu-action-row.js +0 -5
  784. package/dist/menu-action-row.js.map +0 -1
  785. package/dist/menu-header.d.ts +0 -43
  786. package/dist/menu-header.js +0 -7
  787. package/dist/menu-header.js.map +0 -1
  788. package/dist/menu-item.d.ts +0 -33
  789. package/dist/menu-item.js +0 -5
  790. package/dist/menu-item.js.map +0 -1
  791. package/dist/panel-header.d.ts +0 -36
  792. package/dist/panel-header.js +0 -7
  793. package/dist/panel-header.js.map +0 -1
  794. package/dist/styles/menu-action-row.css +0 -160
  795. package/dist/styles/menu-header.css +0 -160
  796. package/dist/styles/menu-item.css +0 -123
  797. package/dist/styles/panel-header.css +0 -64
  798. package/dist/styles/tab-scaffold.css +0 -84
  799. package/dist/tab-scaffold.d.ts +0 -30
  800. package/dist/tab-scaffold.js +0 -16
  801. package/dist/tab-scaffold.js.map +0 -1
  802. package/dist/wire-tab-scaffold.d.ts +0 -11
  803. package/dist/wire-tab-scaffold.js +0 -16
  804. package/dist/wire-tab-scaffold.js.map +0 -1
  805. package/docs/tab-scaffold.md +0 -41
  806. package/ux-demo/recipes/master-detail-dialog.tsx +0 -45
  807. package/ux-demo/recipes/recipes.css +0 -355
@@ -2,6 +2,16 @@
2
2
 
3
3
  `@kerfjs/ui` components are plain functions that return Kerf `SafeHtml`. They have no component instance or lifecycle.
4
4
 
5
+ ### Shared semantic tones
6
+
7
+ `SemanticTone` is the shared color-role type for `Badge`, `Chip`, `StateBanner`,
8
+ and semantic `ContentItem` appearances: `neutral`, `info`, `pop`, `success`,
9
+ `warning`, and `danger`. Import it as a type from `@kerfjs/ui`,
10
+ `@kerfjs/ui/badge`, `@kerfjs/ui/state-banner`, or `@kerfjs/ui/content-item`.
11
+ Use `info` for the role backed by the existing `--kui-color-brand-*` tokens.
12
+ Migrate Badge/Chip `tone="brand"` to `tone="info"`; `BadgeTone` and
13
+ `StateBannerTone` remain deprecated aliases of `SemanticTone`.
14
+
5
15
  ## Selection boundary
6
16
 
7
17
  Begin with the [need-first component matrix](./component-selection.md). Reuse a
@@ -18,25 +28,277 @@ package delivery paths, Web Awesome's installed manifest, AI guidance, and
18
28
  documentation links. Nuanced prose in this contract and the selection guide
19
29
  remains authored rather than generated.
20
30
 
31
+ ### Markdown component reference (AI entry point)
32
+
33
+ [`ai/components/README.md`](../ai/components/README.md) and one
34
+ `ai/components/<id>.md` page per catalog entry are the assistant-facing view of
35
+ both catalogs. An assistant reads the index, then only the pages it uses,
36
+ instead of loading the full JSON. Each page merges the entry's selection facts
37
+ (purpose, use/avoid, alternatives), delivery (JavaScript subpath, CSS,
38
+ registration, wiring helpers), a link into `public-api-signatures-v1.md` for
39
+ exact props, composition (parents, contexts, zones with their JSX prop and
40
+ cardinality, children), state and wiring ownership including wiring-owned
41
+ state attributes, geometry, accessibility obligations, public class and token
42
+ hooks framed as a styling boundary (components own their styles; configure
43
+ through props rather than overriding internals), and `KUI-C###` diagnostics
44
+ with their conditions. `scripts/sync-component-docs.mjs` renders them only from
45
+ `component-catalog.json` and `component-composition.json` (plus the signature
46
+ file's module headings for anchors), sorted and Prettier-formatted;
47
+ `check:catalog` rejects a stale, missing, or orphaned page. The JSON files stay
48
+ the canonical tool-facing sources.
49
+
50
+ ### Composition catalog
51
+
52
+ [`component-composition.json`](../ai/component-composition.json) adds a formal,
53
+ machine-evaluable composition layer beside `component-catalog.json` without
54
+ changing its selection and delivery contract; it is a generated companion, not
55
+ a newer version of that catalog. Every component-catalog entry projects once,
56
+ in order, under the stable qualified key `package:id`. Each composition entry
57
+ explicitly covers parents/contexts,
58
+ named zones and cardinality, optional explicit JSX prop bindings, child concepts, state ownership, required wiring,
59
+ responsive ownership, layout and geometry, accessibility obligations, public
60
+ CSS boundaries, diagnostics, and provenance. A wrapper entry may add
61
+ `rendersAs`: the cataloged roots it renders (any one of them, or nothing), so
62
+ composition checks treat its elements as each root rather than as an unknown
63
+ child. A placement with listed parent constraints produces one `KUI-L201`
64
+ diagnostic even when both the wrapper and a rendered root reject that parent.
65
+ When one catalog entry exports another JSX component with different placement,
66
+ `jsxExports` gives that export its own parent contract. The extra export does
67
+ not stand for the entry's root when a parent zone is checked.
68
+ Generated `boundaries.rootClass` prefers the public `kui-<entry-id>` class when
69
+ present, so a sibling export's class cannot become the entry's root class.
70
+
71
+ `boundaries.placeableClasses` names the subset of `publicClasses` an
72
+ application may write onto its own elements (layout utilities, the document
73
+ root, item geometry on another carrier); absent means none, and every other
74
+ public class is the component's rendered anatomy. `boundaries.rootElement`
75
+ names the element a component renders around its own placeable classes
76
+ (`content-item`: `div`), so a plain element of that tag carrying them is still
77
+ the component recreated. `eslint-plugin-kerfjs`'s `ui-public-boundaries`
78
+ reports both as `KUI-L103` with the export to render — for `@kerfjs/ui` and for
79
+ every consumer catalog a `.kerf-ui-profile.json` declares, whatever the class
80
+ prefix. `create-kerf-component` packages declare the same fields in
81
+ `kerf.components.json`.
82
+
83
+ `descendantRootAttribute` optionally names a `data-*` attribute on a
84
+ cataloged `rootElement`. It anchors ownership of arbitrary unclassed child
85
+ element selectors below that exact root, as `LucideIcon` does with
86
+ `svg[data-lucide]`. Without the attribute in a selector, the analyzer uses
87
+ only cataloged `descendantElements` and composed JSX evidence.
88
+
89
+ An entry's optional `cssValueProps` makes CSS-adjacent prop grammar equally
90
+ machine-evaluable. Each path records the property grammar, finite shorthands,
91
+ canonical versus exceptional spacing choices, standalone and expression-only
92
+ helpers, raw/unsafe policy, and serialization examples. Nested paths use the
93
+ bounded `items[].property` form. Consumer catalogs can publish the same facts;
94
+ ESLint, `kerf-ui-analyze`, and `kerf-ui-doctor` then issue the same stable
95
+ `KUI-L013`–`KUI-L017` feedback for application and third-party components.
96
+
97
+ `wiring.stateAttributes` lists the **wiring-owned state attributes**: the
98
+ `data-*` attributes a wiring helper writes at runtime, such as
99
+ `data-handle-inset` and `data-resizing`, which `wireResizableRegions` puts on a
100
+ `ResizableRegion`. Each entry names the attribute, the element that carries it
101
+ (`on`), the `helper` that writes it, and what it means. An application must not
102
+ render, remove, or treat these attributes as its own state; tools use the list
103
+ to tell them apart from app-authored attributes. They are declared once, on the
104
+ helper's wiring item in the component catalog, and the composition catalog
105
+ flattens them. `check:catalog`
106
+ reads each `wire*` helper's source and fails when its declarations differ from
107
+ the `data-*` attributes it actually writes. First-party entries always carry
108
+ the list, empty when their helpers write none; it is optional in extension
109
+ catalogs.
110
+
111
+ An extension catalog may add `wiring.sources` entries with `export` and
112
+ `source` for each application-owned helper. The source path is relative to its
113
+ package root; `ui-wiring` resolves helper imports through this file, including
114
+ relative re-export barrels. Every named export must also appear in
115
+ `wiring.helpers`.
116
+
117
+ The selection catalog's `wiringProviders` lists public helpers that install
118
+ other wiring helpers. The `ui-wiring` rule accepts a provider call for each
119
+ helper it declares; `wireCatalog` provides `wireScrollDividers`.
120
+
121
+ The generator starts with permissive defaults. An `any` mode records that the
122
+ catalog has no defensible prohibition; it does not claim every composition is
123
+ recommended. Objective rules live in
124
+ `component-composition-rules.json` and may carry stable `KUI-C###`
125
+ diagnostics. A tool reports a diagnostic only after proving its exact `when`
126
+ condition. Subjective choice, product policy, and visual taste remain prose.
127
+
128
+ Kerf UI calls component content positions **named `SafeHtml` prop slots**.
129
+ Use `children` for one homogeneous primary region; use explicit named
130
+ `SafeHtml` props for semantic positions or replacement content such as
131
+ `header`, `footer`, `leading`, `trailing`, `icon`, and `action`. These are typed
132
+ function-component props, not native web-component `<slot>` elements and not a
133
+ generic `slots={{...}}` object. A composition zone declares `jsx.prop` only when tooling
134
+ can soundly bind that zone to one public JSX prop; `children` is spelled
135
+ explicitly. Zones without that binding remain guidance and are never guessed
136
+ from their ids. Static tools inspect only visible JSX structure and leave
137
+ dynamic `SafeHtml` expressions to runtime and accessibility evaluation.
138
+
139
+ ### Native named-slot assignment
140
+
141
+ Every public visual component with one stable conceptual root accepts an
142
+ explicit `slot?: string` prop and forwards it to that root on every render
143
+ branch. Use it when a Kerf component is a light-DOM child of a custom element,
144
+ for example `StateBanner({ title: 'Ready', slot: 'status' })`. Omitting the prop
145
+ omits the attribute.
146
+
147
+ This contract does not open a generic native-attribute bag: components still
148
+ accept only their documented props and narrow extension-attribute objects.
149
+ `ResizableRegion` and `CollapsiblePanel` are deliberately excluded because each
150
+ can return a region plus a sibling restore control, leaving no single root that
151
+ can truthfully own native slot assignment. Their single-root controls and all
152
+ alternate-root branches of supported components retain the contract.
153
+
154
+ Component-catalog consumers continue unchanged. Composition-aware consumers
155
+ read `component-catalog.json` for selection/delivery and
156
+ `component-composition.json` for composition. `npm run catalog:sync` projects every new component,
157
+ recipe, and supported Web Awesome entry, and the completeness gate prevents
158
+ silent omissions. Downstream catalogs use the composition extension schema and types,
159
+ retain their own package identity, and qualify cross-catalog references. See
160
+ the checked
161
+ [`component-composition-extension.json`](./examples/component-composition-extension.json)
162
+ application-owned example.
163
+
164
+ ### Compile-time contract boundary
165
+
166
+ The versioned
167
+ [`compile-time-contracts-v1.json`](../ai/compile-time-contracts-v1.json)
168
+ artifact maps stable `KUI-T###` ids to public imports, emitted symbols, and
169
+ catalog identities. Its positive/negative fixture compiles against both source
170
+ and a freshly packed package, so source declarations and shipped declarations
171
+ cannot silently diverge. See [Compile-time contracts](./type-contracts.md) for
172
+ the full audit, migration guidance, and the relationships deliberately left to
173
+ runtime/catalog checks because TypeScript cannot prove them.
174
+
175
+ ### Application UI profile
176
+
177
+ The component catalogs describe what packages provide; an application profile
178
+ describes which supported choices a project has approved. A workspace may
179
+ check in `.kerf-ui-profile.json` conforming to
180
+ [`application-ui-profile.schema.json`](../ai/application-ui-profile.schema.json).
181
+ Keep package-qualified catalog locations and recurring-concept preferences,
182
+ allowed color schemes and density, public semantic-token overrides,
183
+ layout/responsive conventions, application wiring entry paths, and narrow rule exceptions there. Product
184
+ records, copy, permissions, user preferences, and transport state do not belong
185
+ in this policy file.
186
+
187
+ Every catalog location names a composition artifact. `selection` is optional
188
+ for consumer packages whose generated metadata declares component-catalog
189
+ selection guidance not applicable; `@kerfjs/ui` retains its required
190
+ `component-catalog.json` selection artifact. This
191
+ lets a generated `component-composition.json` participate directly without a
192
+ fabricated compatibility file.
193
+
194
+ Discovery and precedence are deterministic:
195
+
196
+ 1. Load `application-ui-profile.defaults.json` from `@kerfjs/ui`.
197
+ 2. Load `.kerf-ui-profile.json` at the workspace root when present.
198
+ 3. Walk from the workspace root toward the target directory and load each
199
+ directory-local profile in parent-to-child order.
200
+
201
+ Later scalar and object-map values win. Catalogs merge by package; preferences
202
+ and token overrides merge by key; exceptions merge by stable id. Lists such as
203
+ allowed themes/densities replace the earlier list rather than accumulating.
204
+ `wiring.entries` similarly names workspace-relative application entry modules;
205
+ later profile layers replace the entry list. The `ui-wiring` ESLint rule checks
206
+ application-scoped helper calls and registration imports once at each entry
207
+ that reaches a rendering module, while a composition entry with
208
+ `wiring.scope: "module"` keeps a local obligation. See the
209
+ [`ui-wiring` rule](../../eslint-plugin/docs/rules/ui-wiring.md).
210
+ Every resolved field retains its source file. The shipped
211
+ `application-ui-profile.mjs` API implements discovery, merge, loading, and
212
+ validation and reports actionable originating file + JSON-path diagnostics for stale
213
+ catalogs, unknown component/rule/token references, preference conflicts, and
214
+ broad exceptions. Each raw layer is validated against the catalogs effective at
215
+ that exact precedence point before merge, so a broken parent catalog, stale
216
+ parent reference, invalid value, or unknown field cannot disappear merely
217
+ because a child profile replaces it. The shipped
218
+ `application-ui-profile-sync.cjs` projects the same merge and validation contract
219
+ for synchronous hosts such as ESLint rules; it deliberately performs no async
220
+ I/O.
221
+ See the
222
+ [`application-ui-profile.json`](./examples/application-ui-profile.json) example.
223
+
224
+ The package defaults avoid every `Discouraged` Web Awesome entry — each
225
+ `webawesome` catalog entry whose `recommendation` is not `supported`, except the
226
+ encouraged `wa-popup` primitive — under a concept whose `preferred` value is the
227
+ Kerf component that wraps or replaces it (`command-menu` → `PopupMenu`,
228
+ `value-selection` → `Select`, `application-tabs` → `TabBar`, `icon` →
229
+ `LucideIcon`, `resizable-pane` → `ResizableRegion`, `exclusive-choice` →
230
+ `SegmentedControl`, `hierarchy-navigation` → `List`, `embedded-media` →
231
+ `ContentItem`). `eslint-plugin-kerfjs` `ui-preferences` (`KUI-L301`, also run by
232
+ `kerf-ui-doctor`) therefore reports a Discouraged element written directly as a
233
+ JSX tag (`<wa-dropdown>`) as well as through an imported component. A declared
234
+ component's own source file is exempt, because that wrapper is the sanctioned
235
+ owner of the element it renders. A unit test holds the avoid set and the
236
+ catalog's Discouraged set equal in both directions, so neither can drift. A
237
+ product that genuinely needs one of these elements records a narrow `KUI-L301`
238
+ profile exception for the file that renders it.
239
+
240
+ Catalog detail footers use one standard resource vocabulary and order. Build
241
+ them with `catalogResources()` from `@kerfjs/ui/catalog-resources`: `Demo source`
242
+ first, optional `Component source` and `Design template`, then `Guidance`.
243
+ Third-party entries use the typed `integrationGuidance` kind, which renders
244
+ `Integration guidance`, and omit `Component source` when the implementation is
245
+ not owned by the catalog's project. Prefer these semantic kinds over local labels
246
+ such as “View source” or “Read UI guidance”; the helper makes that convention a
247
+ compile-time choice while still returning ordinary `CatalogResource[]` values.
248
+
21
249
  ## Ownership boundaries
22
250
 
23
- - Components own semantic markup, stable anatomy, documented variants, ARIA projection, and package CSS hooks.
251
+ ### Geometry ownership metadata
252
+
253
+ The canonical [`component-catalog.json`](../ai/component-catalog.json) records
254
+ the margin, border, and padding owner for every component and composition under
255
+ `geometry`. Read it before adding a wrapper or local spacing rule:
256
+
257
+ - `self` means the entry's public visual contract supplies that geometry.
258
+ - `parent` means the embedding layout must supply it.
259
+ - `child` means composed descendants supply it; the entry's outer shell does not.
260
+ - `none` means that dimension is intentionally absent from the standard contract.
261
+ - `conditional` means a variant, part, or configuration changes ownership; the
262
+ accompanying `notes` explain the boundary.
263
+
264
+ The values describe public ownership, including themed shadow parts, rather
265
+ than merely asking whether a CSS declaration appears on the host element.
266
+ Recipes are exempt because they arrange entries whose individual ownership is
267
+ already cataloged.
268
+
269
+ Downstream packages and applications should publish the same contract for their
270
+ reusable visual components. Use
271
+ [`component-catalog-extension.schema.json`](../ai/component-catalog-extension.schema.json)
272
+ and copy the structure of the checked
273
+ [`component-catalog-extension.json`](./examples/component-catalog-extension.json)
274
+ example. Keep app and Kerf entries as package-qualified inputs, then let people
275
+ or AI tools search their combined entries and compare `geometry` before adding
276
+ wrappers or insets. Do not add app-owned entries to Kerf's canonical catalog or
277
+ claim Kerf delivery paths for them.
278
+ Extension entries may add `uses` for direct composition dependencies and
279
+ repository-relative `source` and `demoSource` files. Resolve each dependency
280
+ against the combined Kerf and consumer catalogs; do not duplicate a Kerf id.
281
+ For Doctor's opt-in component ownership mode, add `styleSources` with the CSS
282
+ paths each entry owns, relative to the consumer package root.
283
+
284
+ - Components own semantic markup, stable anatomy, documented variants, ARIA projection, and package CSS hooks. They may render and style raw HTML or Web Awesome implementation elements they create and control. A nested Kerf or application component remains its own owner even when the parent renders it.
24
285
  - Applications own signals/stores, product copy, domain-state mapping, persistence, routing, permissions, and transport.
25
286
  - Actions are `data-action` strings. Wire them at a stable root with `delegate()` or `delegateActions()` and retain the disposer.
26
287
  - 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.
288
+ - 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. A thin composition that only connects other components should normally have no stylesheet. It may style only raw elements or layout it owns, never its component children.
28
289
 
29
- `MenuItem.rootAttributes`, `MenuActionRow.rootAttributes`,
30
- `MenuHeader.rootAttributes`, and `AppTab.rootAttributes` accept
290
+ `ListItem.rootAttributes`, `ListActionRow.rootAttributes`,
291
+ `ListHeader.rootAttributes`, `AppTab.rootAttributes`,
292
+ `CatalogExample.rootAttributes`, and `CatalogExampleStack.rootAttributes` accept
31
293
  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
294
+ adding product fields to the shared API. A `ListActionRow` trailing action uses
295
+ `trailingActionAttributes`, and a `ListHeader` action/disclosure uses
34
296
  `triggerAttributes`, for `data-*`, native popover target/action attributes, and
35
297
  the corresponding `aria-controls`/`aria-haspopup` relationship. These slots do
36
298
  not accept roles or component-owned action, selection, disclosure, accessible
37
299
  name, disabled, or icon fields. Extension objects are filtered at runtime,
38
300
  including case-insensitive rejection of protected `data-*` names, and the
39
- component writes its protected attributes after the accepted metadata. Typed,
301
+ component or helper writes its protected attributes after the accepted metadata. Typed,
40
302
  structurally widened, and JavaScript callers therefore cannot replace its
41
303
  contract.
42
304
 
@@ -46,89 +308,347 @@ component continues to own the named close button or focusable separator, and
46
308
  `wireTabBars()` / `wireResizableRegions()` continue to own transient behavior
47
309
  and disposal.
48
310
 
49
- `MenuItem.trailing`, `MenuActionRow.label`, `MenuActionRow.icon`, and
50
- `MenuActionRow.trailingActionIcon` are dormant SafeHtml slots. They must not
311
+ `ListItem.trailing`, `ListActionRow.label`, `ListActionRow.icon`, and
312
+ `ListActionRow.trailingActionIcon` are dormant SafeHtml slots. They must not
51
313
  contain controls. When a row needs an independently interactive trailing
52
- region, `MenuActionRow` owns the noninteractive root and the two sibling native
314
+ region, `ListActionRow` owns the noninteractive root and the two sibling native
53
315
  buttons; the application owns their delegated behavior and controlled state.
54
316
  Both row components align a leading icon with the first label line when
55
317
  `multiline` allows the label to wrap; additional lines extend below that fixed
56
318
  visual anchor.
57
319
 
320
+ `ToolbarControlGroup.tileTone` selects `neutral`, `brand`, `success`, `warning`, or `danger` quiet fill, matching quiet border, and on-quiet foreground for a non-interactive icon tile. Compose a contained `single` group whose only child is a direct decorative LucideIcon (`aria-hidden="true"`). Omission preserves the normal group palette. The prop does not recolor interactive, mixed, multi-control, or borderless groups; keep real actions in controls with their existing focus/hover/pressed treatments.
321
+
58
322
  ### Public CSS anatomy
59
323
 
60
324
  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
325
+ [`component-catalog.json`](../ai/component-catalog.json) identifies stable
326
+ anatomy for diagnostics, tooling, browser assertions, and package-owned
327
+ composition. It is not an application customization API. Applications choose
328
+ documented props and tokens; package components may compose other components
329
+ only through those public contracts, never by styling a child's classes from a
330
+ parent stylesheet.
331
+
332
+ Inside the package, a component never styles another component or writes
333
+ another component's variables. When a child must adapt to a composing parent,
334
+ the child styles itself in that context from its own stylesheet: the parent's
335
+ class and state appear only in an ancestor compound, the styled compound is
336
+ the child's own class (or one of the child's own unclassed internals below
337
+ it), and the child reads context values the parent provides under the
338
+ parent's name. `ResizableRegion` widens its edge extent by the unsafe inset a
339
+ split `SplitView` provides, and a `Skeleton` derives its fill from a solid
340
+ `Badge`'s on-solid color, both in their own stylesheets; an `AppTab` rounds its
341
+ outer corners in a segmented `TabBar` and shares a fill-allocated strip from
342
+ `app-tab.css`. A `PopupMenu` sizes
343
+ its trigger and applies a group's `menuInset` in its own stylesheet, and an
344
+ icon-only `Select` reads the control slot a `ToolbarControlGroup` provides
345
+ (`--_kui-toolbar-control-group-slot-*`). A parent may still style its own
346
+ elements keyed on a child's state, naming the child by class inside `:has()`
347
+ (`:has(> .kui-select[open])`, or `TabBar` insetting a segmented strip that
348
+ holds compact tabs), and it keeps styling raw native and raw Web
349
+ Awesome children no kerf component owns, excluding kerf children by class
350
+ (`wa-dropdown:not(.kui-popup-menu)`). `npm run check:css-ownership` enforces
351
+ this in every component stylesheet (a same-basename `.css` and `.tsx` pair
352
+ under `src/components/<family>/<component>/`), deriving the component names,
353
+ the Web Awesome tags each component renders, and its composed children from the
354
+ colocated component source:
355
+
356
+ - **Foreign classes.** Another component's class or `[data-component]` may
357
+ appear only in an ancestor compound or inside `:has()` / `:not()`; the
358
+ styled compound is the stylesheet's own class.
359
+ - **Owned Web Awesome tags.** Kerf components are named by class, never by a
360
+ `wa-*` tag they render. A tag another component renders (`wa-dropdown`,
361
+ `wa-select`, `wa-option`, a `PopupMenu`'s trigger `wa-button`) — as the
362
+ subject, or as an ancestor whose internals the rule reaches — must be scoped
363
+ to that component by its class or excluded with `:not()`. A direct child
364
+ that cannot be the owner's internal
365
+ (`.kui-toolbar-control-group > wa-button`) needs no exclusion.
366
+ - **Variables.** A stylesheet writes only its own `--_kui-<self>-*` private
367
+ variables, and never overrides a public `--kui-<other>-*` token that another
368
+ component reads. Shared foundation tokens (`--kui-layout-*`,
369
+ `--kui-color-*`, …) are not any one component's. Context a parent provides
370
+ is named after the parent.
371
+ - **Context on any child.** Custom properties set on a subject that can be any
372
+ element (`.kui-x > *`, `> :not(…)`) also land on composed components' roots.
373
+ - **Hook classes.** A class the component places on a composed kerf child's
374
+ root (`<ToolbarText className="kui-nav-stack__title">`, a class NavStack once styled) may not be styled;
375
+ the child styles itself in that context instead.
376
+
377
+ The documented exceptions live with their reasons in
378
+ `scripts/lib/css-ownership.mjs`, and an exception that stops matching fails the
379
+ check, so the list only shrinks. The layout regions' inherited edge-inset
380
+ context (`--kui-edge-inset-*` handed to a sole Pane or layout child and cleared
381
+ for any other content, and a Toolbar clearing it for its zones) is the one
382
+ design exception; the others name the open fix ticket.
383
+
384
+ Applications and component packages built on the package follow the same
385
+ rules, and the downstream tools enforce them against the composition catalog
386
+ instead of package source: `kerf-ui-analyze` / `kerf-ui-doctor` report a rule
387
+ whose subject is another package's component (`KUI-L019`), another
388
+ component's private `--_*` variable (`KUI-L020`), an override of a token a
389
+ typed prop sets (`KUI-L021`), and a hook class on a component's root
390
+ (`KUI-L022`), plus borrowed public classes in source markup (`KUI-L023`);
391
+ `eslint-plugin-kerfjs`'s `ui-component-ownership` reports
392
+ `KUI-L020` / `KUI-L021` in script. Both share the selector parsing in
393
+ `analyzer/selectors.mjs` with `check:css-ownership`, and
394
+ `check:css-ownership` fails when a component renders a Web Awesome tag the
395
+ catalog does not list, so `KUI-L019` keeps covering every tag a kerf component
396
+ renders. Each finding names the configuration to use and routes a missing
397
+ prop to a component-gap report (see [the analyzer guide](./ui-analyzer.md#component-ownership-kui-l019kui-l023)).
398
+
399
+ The composition catalog additionally requires `boundaries.rootClass` to be
400
+ either one exact member of `publicClasses` or `null` when the entry has no
401
+ rendered class root. Runtime geometry tooling uses this explicit field; array
402
+ order never implies root ownership.
403
+
404
+ Do not select a component root or descendant by class, element name, id, or
405
+ attribute. Selectors such as `.workspace .kui-toolbar`,
406
+ `.kui-state-banner span`, and `.kui-list-item [data-state]` cross the ownership
407
+ boundary. If no prop or token expresses a recurring need, add the configuration
408
+ to the owning component instead of inferring it from rendered markup.
409
+
410
+ `Badge` owns the complete visual treatment for compact status, count, category,
411
+ and metadata labels. Configure its semantic `tone`, `appearance`, `shape`, and
412
+ `size`; do not recreate or override badge anatomy in an application or consuming
413
+ component. Use `label` when visible content is abbreviated and `ariaHidden` only
414
+ when a surrounding component already includes the same value in its accessible name.
415
+ Every tone's text and solid fill use that tone's `--kui-color-{tone}-on-fill`
416
+ token (`neutral` uses the text colors), the foreground tuned to clear WCAG AA
417
+ (4.5:1) on the tone's fills in light and dark mode.
418
+
419
+ `ListItem` renders its leading icon and nested SVG at a root-scaled 18px by
420
+ default while retaining the row's 44px minimum interactive target. Multiline
421
+ rows align that 18px visual with the first inherited text line. The row clips
422
+ descendant painting to its rounded root so labels, status, and dormant trailing
423
+ content cannot escape its visible boundary. Rows with descriptions grow enough
424
+ to keep their owned two-line label stack readable; use `multiline` when the
425
+ primary label should wrap rather than truncate. A single-line row ends its
426
+ primary label and description with an ellipsis before the trailing status
427
+ slot, even when the label is one long word; a `multiline` row wraps instead,
428
+ breaking a word wider than the label column (a long component or file name)
429
+ rather than letting it run under the trailing slot. A string label in a
430
+ `multiline` row gets line-break opportunities at its camelCase and acronym
431
+ boundaries, so `QuickTicketComposer` wraps as `QuickTicket` / `Composer`
432
+ rather than mid-word; breaking anywhere is only the last resort for a single
433
+ word that is still too wide. The text and accessible name are unchanged. `ListActionRow` labels
434
+ follow the same single-line and `multiline` rules before the trailing action.
435
+
436
+ `DisclosureArrow` uses an 18px root-scaled visual by default. Pass its typed
437
+ `size` prop when a consumer needs another size. Kerf `Select` uses a separate Web Awesome expand
77
438
  glyph contract, `--kui-disclosure-icon-scale: .5`; changing one contract does
78
439
  not implicitly change the other. Direction changes take the shortest rotation
79
440
  path; a 180-degree closed-to-open tie uses counterclockwise rotation.
80
441
 
81
- In `MenuHeader` toggle mode, omitting `actionIcon` composes the production
442
+ In `ListHeader` toggle mode, omitting `actionIcon` composes the production
82
443
  `DisclosureArrow` and derives its visual direction from `expanded`. The app
83
444
  must update that controlled state and reveal or hide real content. Passing a
84
445
  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`.
446
+ The root fills the available inline width after its standard margins by
447
+ default. Set `inline` when it must shrink-wrap beside surrounding content; that
448
+ presentation removes the root margin, border, and padding while retaining the
449
+ title and optional action's own control geometry. A separate action stays at
450
+ the logical end while the visible glyph defaults to 18px through
451
+ `--kui-list-header-action-icon-size`.
88
452
 
89
453
  `StateBanner` exposes instance-level `--kui-state-banner-background`,
90
454
  `--kui-state-banner-border`, `--kui-state-banner-foreground`,
91
- `--kui-state-banner-detail`, and action background variables. Its five built-in
455
+ `--kui-state-banner-detail` and action background variables. Its optional
456
+ badge composes `Badge` beside the title and follows the banner tone by default. The
457
+ title, badge, and detail flow as inline text: a wrapping title keeps the badge one item
458
+ gap after its last word, and a detail that does not fit whole beside them moves to its
459
+ own line and truncates at the full copy width (below 576px it always takes its own
460
+ line). The title and detail both use the tone's `--kui-color-{tone}-on-fill`
461
+ foreground (`info` uses `brand`) at full strength, clearing WCAG AA over the tone's fill in light and dark
462
+ mode; the detail reads as secondary through its smaller, regular-weight type, and
463
+ only the neutral tone quiets it, to `--kui-color-neutral-on-quiet`. Its five built-in
92
464
  tones can be rethemed globally with
93
465
  `--kui-state-banner-{tone}-{background|border|foreground}`. Toolbar control,
94
466
  segmented-control, app-tab, and tab-bar colors likewise use their public
95
467
  `--kui-*-*` variables. `SegmentedControl` exposes surface, border, foreground,
96
468
  hover, and selected-state variables, so rounded, pill, and toolbar presentations
97
- remain opinionated but locally overridable.
469
+ remain opinionated but locally overridable. Its label color switches with the
470
+ theme without Web Awesome's native button color transition, so a dark filled
471
+ track never briefly pairs with an interpolated low-contrast label.
472
+
473
+ Inset hover and selection surfaces follow the outer control shape instead of
474
+ choosing an independent radius. `--kui-layout-highlight-inset` is the full
475
+ distance between those edges; the inner radius is the outer radius minus that
476
+ inset. `ToolbarControlGroup` publishes its derived radius to nested toolbar
477
+ `SegmentedControl` choices, keeping both direct buttons and exclusive-choice
478
+ highlights concentric when the group switches between pill and rounded shapes.
98
479
 
99
480
  `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
481
+ separator with a compact grip that appears on hover or keyboard focus. The grip
482
+ is drawn centered on the separator line even though the pointer target is wider
483
+ than the line, so the handle never reads as offset into a pane. Override
101
484
  `--kui-resizable-region-separator-color`,
102
485
  `--kui-resizable-region-handle-color`, or
103
486
  `--kui-resizable-region-handle-active-color` on a region when its containing
104
487
  surface needs a different contrast level.
105
488
 
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.
489
+ `Pane` defines one structural model for sidebars, main areas, inspectors, and
490
+ dialogs. Its `.kui-pane` root is unpadded and contains an optional vertical
491
+ header, one scrolling vertical `.kui-pane__content`, and an optional footer.
492
+ Logical-edge separator lines are independently opt-in and default off.
493
+ `@kerfjs/ui/layout.css` retains the pane roles and supplies the related content
494
+ geometry classes.
495
+ `List` is the corresponding layout-only vertical stack: its children stretch by
496
+ default, while `gap`, `flex`, and `scrollable` opt into typed spacing,
497
+ flex growth, and vertical scroll ownership. `Row.flex` uses the same typed flex
498
+ participation contract on the horizontal counterpart. `dividerSides` accepts canonical
499
+ physical top/right/bottom/left combinations such as `tr` and `trbl`; the stack
500
+ adds no list semantics, margin, or padding of its own. Use a direct finite
501
+ spacing shorthand such as `gap="2xs"`, or pass a `CssLength` created by the
502
+ CSS-free `@kerfjs/ui/css-values` helpers: `space('m')`, `rem(0.25)`,
503
+ `lengthVar('--app-gap')`, or `calc(plus(rem(0.25), pct(10)))`. `plus` returns a
504
+ non-standalone `CssLengthExpression`; only `calc` turns it into a complete
505
+ length. `remify(18)` is the runtime twin of source CSS's `remify(18px)`: it
506
+ takes a pixel count and returns a `CssLength` in rem (`1.125rem`) against the
507
+ same fixed 16px baseline. Raw CSS strings, and the source-only `remify(4px)`
508
+ string form, are not valid runtime props. The `CssLength` name intentionally includes percentages for UI dimension
509
+ props. Its opaque string brand improves authoring correctness; it is not a CSS
510
+ sanitizer or security boundary.
511
+ `Row.flex` and `List.flex` likewise accept their boolean default, finite keywords, or `CssFlex`
512
+ from `flex(grow, shrink, basis)`. `Skeleton` width/height use `CssSize`, radius
513
+ uses `CssLength`, and `SelectChoice.color` uses `CssForegroundColor` from
514
+ `uiColor()` with a foreground token such as `success-on-quiet`, or from
515
+ `foregroundColorVar()`. Fill tokens such as `success` are pale background tints
516
+ and do not type-check there. Never exchange these property grammars. List rows expose
517
+ `className`, public tokens, and semantic props instead of unrestricted `style`
518
+ declarations.
109
519
  `.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.
520
+ `ContentItem` (`@kerfjs/ui/content-item`, rendering `.kui-content-item`) gives
521
+ one child 8px inline margin, a real 1px border, 8px padding, and 12px corners;
522
+ the border stays transparent unless `frame="framed"`, so framing never changes
523
+ geometry. `shape="pill"` selects the 22px radius. `appearance="surface"`
524
+ paints the base surface, while `neutral`, `info`, `pop`, `success`, `warning`,
525
+ and `danger` coordinate the same quiet background, border, and readable
526
+ foreground tokens as `StateBanner`. The default `transparent` appearance
527
+ preserves the surrounding surface.
528
+ `flush` removes block padding and borders while preserving inline geometry;
529
+ `title` passes through as the native tooltip. Interactive hover uses the normal
530
+ neutral fill so it remains visible on a lowered surface. For a card with
531
+ multiple actions, put sibling buttons in a static ContentItem (or use
532
+ `ListActionRow` for a simple two-action row).
533
+ For an interactive ContentItem, `wireContentItems` activates the card on Enter
534
+ or Space only when the key event originated from the card itself. A nested
535
+ native control, including one inside a custom element's shadow root, keeps its
536
+ own keyboard activation.
113
537
 
114
538
  `ToolbarControlGroup` is the unit of toolbar organization, even for dormant
115
539
  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
117
- optional count or badge from its optional 44px action. Use the mutually
118
- exclusive `count`/`countLabel` pair for non-negative safe-integer section
119
- quantities; reserve `badge` for non-count `SafeHtml`. Do not concatenate counts
120
- into the section label. Do not add padding to pane shells,
540
+ groups and inside items. For an ordinary icon/action control inside a group, use
541
+ a plain `<button>` — the group styles `> button` fully, and it keeps the group
542
+ free of a Web Awesome dependency and shadow DOM. Use `ToolbarActionLink` when
543
+ the action must retain native anchor navigation; the group owns its geometry,
544
+ hover, and focus treatment. Set `overflow="scroll"` when a row of controls must
545
+ stay inside the available toolbar width. A disabled native button keeps the
546
+ group's geometry, dims to half opacity, uses the `not-allowed` cursor, and
547
+ paints neither its own nor a lone group's hover surface.
548
+ Set `visibility="compact-only"` for a
549
+ group that replaces wider toolbar controls below the Toolbar's compact container
550
+ breakpoint; do not hide the group with an application class.
551
+ Use `sizing="grow"` on an expanded search group in a wrapping zone: it grows from
552
+ `growBasis` (19rem by default) into available row space, then takes a whole
553
+ row at 480px container width or less. The basis remains its intrinsic minimum
554
+ in a wider, non-stacked Toolbar, so sibling trailing groups can share the
555
+ row. The collapsed search stays icon-sized.
556
+ Use `sizing="fill"` for a group, including a non-search segmented control,
557
+ that spans its wrapping row. Set `visibility="hide-collapsed-tiny"` on a
558
+ collapsible group to omit its closed icon at 224px or less; expanded content
559
+ remains visible. These sizes use the enclosing Toolbar's container width.
560
+ In a stacked Toolbar, set `placement="end"` on a collapsed group that should
561
+ sit at the trailing edge of its flex row. An expanded search with
562
+ `sizing="fill"` takes a whole row and enters from the row above; reduced-motion
563
+ preferences remove that entrance animation.
564
+ Use `visibility="yield-to-expanded-sibling"` on trailing groups that should
565
+ leave a 480px-or-narrower toolbar while a sibling trailing group is expanded.
566
+ They return when it collapses or the toolbar widens; leading and center zones
567
+ remain visible.
568
+ Reach for `wa-button` only when you need a Web Awesome feature; a popup menu is a `PopupMenu`, which renders its own
569
+ trigger. By default a group stays on one row: each icon sits beside its label,
570
+ and the enclosing `Toolbar`'s responsive policy relocates whole groups. Set
571
+ `overflow="wrap"` only for independent links that should move as whole actions
572
+ to another row within the group; use `overflow="scroll"` for a bounded one-row
573
+ action strip. A wrapping group centers in the toolbar band on one row and
574
+ starts at its top when it grows to multiple rows. For a compact mixed-content
575
+ group, set `nestedDropdown`; a
576
+ text-and-caret trigger grows to its intrinsic width while an icon-only trigger
577
+ can remain square. A compact icon `<button>` is a 32px circle, so a selected
578
+ compact segment never becomes an oval. An icon-only `Select` joins a group as
579
+ one more segment with its siblings' inset, radius, hover, and focus ring; only a
580
+ lone Select grows the group to its icon-and-caret pill.
581
+
582
+ Select menus use native viewport shifting with 10px gutters: default menus grow to content (up to 20rem), while `fitMenu` matches trigger width and long labels wrap. Keep popup sizing and position repairs out of consumer CSS.
583
+
584
+ For a rail view heading, use `Select presentation="title"`: its intrinsic
585
+ 36px borderless trigger has a bold large label flush with its leading edge and
586
+ a caret beside that label. Set `focusRingInset` when a NavStack or panel clips
587
+ outside painting; the Select keeps its focus outline 3px inside the trigger
588
+ and drops it while the listbox is open. Both settings belong to Select, not an
589
+ application `::part()` override.
590
+
591
+ Set `menuInset` to configure the dropdown menu surface
592
+ without application `::part(menu)` CSS; the default `standard` keeps each menu's
593
+ own inset (8px for a raw `wa-dropdown`, the Select listbox's 4px for a
594
+ `PopupMenu`), while `compact` and `list-zero` apply to every nested menu. A
595
+ `PopupMenu` and a `Select` draw one popup: the same caret that turns to face the
596
+ open popup, fade-in surface, surface inset, row height and padding, current-row
597
+ fill, and group titles, all read from one private popup-choice contract in
598
+ `foundation.css`. Checkbox items reserve a check column; plain commands start
599
+ at the checkmark's leading edge, beside the group title rather than the
600
+ farther-in Select option label. Checked submenu items keep their checkmark and
601
+ label inside the submenu surface. Compact mixed controls retain the standard
602
+ item padding, omit an internal separator, and let the raised selected item paint
603
+ over the outer border instead of shrinking to an inset highlight. The Web
604
+ Awesome trigger's shadow base owns max-content sizing, so icons, localized text,
605
+ and the shadow caret determine the width without a fixed host measurement.
606
+ With `popup-menu/register` loaded, PopupMenu and a raw dropdown inside
607
+ `PopupSurface` preserve item navigation made during the Web Awesome show
608
+ animation across its final initial-focus handoff.
609
+ At viewport widths of 480px or less, `PopupMenu` places an open submenu above
610
+ or below its parent menu, choosing the side with room and constraining the
611
+ submenu to the viewport. It never paints over the parent list. The submenu
612
+ remains a native Web Awesome `menu`: the reverse horizontal arrow (ArrowLeft in
613
+ LTR, ArrowRight in RTL) returns focus to its parent item, Escape dismisses the
614
+ menu, and choosing a child dispatches the normal
615
+ `data-action` and `wa-select` events. Wider viewports retain the side cascade.
616
+ The enclosing `Toolbar` owns zone alignment and responsive topology: use
617
+ `centerAlign="stretch"` when the center group should consume its track, and
618
+ choose `responsive="stack"` with `responsiveAt="compact" | "narrow"`,
619
+ `responsive="wrap"` for a heading whose title must stay whole, or
620
+ `responsive="center-priority"` instead of selecting its zone classes from a
621
+ parent stylesheet. No policy clips an action: the trailing zone wraps whole
622
+ groups and its standalone primary `wa-button` onto another row; a stacked
623
+ center zone wraps its groups. The center zone never
624
+ compresses below its content width, so when the leading identity, center, and
625
+ trailing zones share a row that is too narrow, the leading title is what gives
626
+ way: it truncates with an ellipsis (as a platform toolbar's title does) instead
627
+ of the center group painting over it. When everything fits, the center group
628
+ keeps its place, centered in the track between the leading and trailing zones.
629
+ `ListHeader` similarly separates its dormant title and optional indicators
630
+ from its optional 44px action. Use the `count`/`countLabel` pair for a sole
631
+ non-negative safe-integer section quantity; it excludes `badge` and `status`.
632
+ `badge` and `status` may appear together, and either may be explicitly
633
+ `undefined` as app state changes. Give a contextual quantity in a badge a full
634
+ spoken phrase, such as "3 lines unpriced". Do not concatenate counts into the
635
+ section label. Set `width="content"` to shrink-wrap while retaining
636
+ normal header geometry; `inline` is the separate zero-outer-geometry mode. Do
637
+ not add padding to pane shells,
121
638
  double child-owned geometry with wrapper insets, or create competing scroll
122
639
  owners. The [layout contract](./layout.md) lists the public roles and tokens.
123
640
 
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.
641
+ Panel, dialog, and page headings are direct `Toolbar` compositions. The leading
642
+ zone holds an optional icon `ToolbarControlGroup` and a direct extra-large
643
+ `ToolbarText`; app actions belong in a trailing `ToolbarControlGroup`. Omit the
644
+ icon group when it has no content. Supporting copy is app-owned content below
645
+ the toolbar so it cannot pull the icon or actions out of alignment.
646
+ For an editable title, `ToolbarText action="edit-title"` renders a native button
647
+ directly in the leading zone. It keeps content width when there is room, shrinks
648
+ and ellipsizes beside a status chip when space is tight, and emits the delegated
649
+ action on click or keyboard activation. The application owns the editing control
650
+ and the swap between display and edit states. An actionable title is a button,
651
+ so place any required heading landmark on another element in the view.
132
652
 
133
653
  `ValueTable` composes typed `ValueTableRow` entries. A row owns its `dt`/`dd`
134
654
  semantics and may receive a leading `SafeHtml` icon. Every row keeps 8px of
@@ -139,6 +659,16 @@ padding + 24px icon + 8px gap) and 8px from the right edge for an icon-bearing
139
659
  row. Applications own the values, formatting, and whether an icon is decorative
140
660
  or meaningfully labeled.
141
661
 
662
+ A row follows the settings-style key/value priority: the value keeps its
663
+ content and the label gives way. The label and value are two content-sized
664
+ columns that share the row's free space equally, each stopping once its content
665
+ fits. A short value therefore stays whole on one line beside any label, and a
666
+ long label takes the remaining width, wrapping at its spaces and ending a word
667
+ wider than its column (a long component or file name) in an ellipsis before the
668
+ value rather than running under it. A short label keeps its width beside a
669
+ long value, which wraps; when both are long they split the row, so neither is
670
+ starved.
671
+
142
672
  ## Imports and side effects
143
673
 
144
674
  Every component has an explicit JS and CSS subpath. In CSS-aware browser builds,
@@ -159,25 +689,58 @@ by default it also owns the collapsible field's transient expand/collapse/focus
159
689
  state in a signal it exposes on the returned handle. An app reads that signal in
160
690
  render, hands in its own via `collapsible.signals`, drives it through
161
691
  `handle.open`/`handle.close`, or disables any individual behavior — so transient
162
- UI is consistent by default without every app reinventing it.
692
+ UI is consistent by default without every app reinventing it. A collapsed
693
+ field may reveal its editor after the current microtask; the helper keeps a
694
+ bounded render-frame focus handoff for that reveal and cancels it on disposal.
695
+ `TokenSearchField.trailingAction` supplies an icon, accessible `label`, delegated
696
+ `action`, and optional `id`; the field renders a 24px wide button that fills its
697
+ 34px line slot, including the hit target, disabled state, hover, and focus ring.
698
+ Use `trailing` for passive content. The two props are mutually exclusive.
699
+ For a collapsible search in a stretched Toolbar center, `fill` lets the expanded
700
+ field and its enclosing search `ToolbarControlGroup` consume the available width;
701
+ the collapsed action retains its fixed icon width.
702
+ Grammar suggestion rows align their labels to one leading edge inside the
703
+ anchored popover, including when the labels have different lengths.
704
+
705
+ A public subpath that exposes several visual components is a folder-backed
706
+ surface. Put each component in its own source file and give each visual
707
+ component exactly one owned stylesheet alongside it. Keep the public
708
+ compatibility entrypoints implementation-free: the JavaScript/TypeScript
709
+ entrypoint only re-exports the folder modules, and the CSS entrypoint only
710
+ imports their owner stylesheets. A shared public name is not permission to put
711
+ several component implementations or visual contracts back into one file.
163
712
 
164
713
  `wireTokenSearchFields` is a deliberate exception, not the rule for `wire…`
165
- helpers. Its collapse behavior was *rich and error-prone* — reveal, focus
714
+ helpers. Its collapse behavior was _rich and error-prone_ — reveal, focus
166
715
  transfer, Escape, empty-blur collapse, focus return — the kind of transient chrome
167
716
  apps kept reimplementing inconsistently, so the helper owns it. Everywhere else the
168
717
  app's state is **domain or persisted, not transient chrome, and stays app-owned**: a
169
- `NavStack`'s view stack is navigation history, a `TabBar`/`TabScaffold`'s selection
718
+ `NavStack`'s view stack is navigation history, a `TabBar`/`TabNavigator`'s selection
170
719
  and tab order are data, a `ResizableRegion`'s committed size and a
171
720
  `Workbench`/`SplitView` rail's `collapsed` flag are persisted layout preferences.
172
- Each helper already owns only the *ephemeral mechanics* around that state —
721
+ Each helper already owns only the _ephemeral mechanics_ around that state —
173
722
  `wireNavStack` the push/pop animation, `wireTabBars` the overflow autoscroll and
174
723
  drag preview, `wireResizableRegions` the live drag preview — and reports committed
175
- changes through callbacks. A `MenuHeader` `toggle` disclosure's `expanded` is
724
+ changes through callbacks. A `ListHeader` `toggle` disclosure's `expanded` is
176
725
  likewise app-owned: it is a one-line boolean the app already tracks and must read to
177
726
  render the section body, so a managed helper would remove no real complexity. Reach
178
727
  for a managed default only when the transient behavior is substantial enough that
179
728
  hand-rolling it produces genuine, inconsistent variation.
180
729
 
730
+ TabBar itself owns the inline geometry around those mechanics. Its tab list is
731
+ the only shrinking, horizontally scrolling region; `leading`, `trailing`, and
732
+ `end` action regions remain fixed. Set `trailingPlacement="adjacent"` when the
733
+ trailing action belongs immediately after the final tab and use `end` for a
734
+ separate action pinned to the far edge. Applications own the action content,
735
+ but must not restyle TabBar descendants to recreate that allocation.
736
+ When a leading AppTab is pinned, the leading scroll divider appears at that
737
+ tab's trailing edge while peer tabs scroll beneath it, including in RTL.
738
+ With `snapTabs`, `wireTabBars` measures the pinned tab and settles peers at
739
+ whole-tab starts after scroll and selection changes, reserving end room so the
740
+ last peer can align there. The application still owns selection and tab order.
741
+ ResizeObserver notifications coalesce snap measurements into the next animation
742
+ frame, so inset writes cannot resize the observed strip during observer delivery.
743
+
181
744
  CSS, the generated wrappers that make it
182
745
  reachable, and the registration module are the package's only declared side
183
746
  effects.
@@ -186,14 +749,74 @@ A value-bearing component's `placeholder` prop is a first-class loading mode: th
186
749
  component renders its own real chrome (labels, icon and action affordances,
187
750
  container geometry) while replacing each **value** slot with a subtle, deliberately
188
751
  unanimated `Skeleton` block and disabling its own interactive controls
189
- (`aria-busy`, dropped `data-action`, disabled buttons). Sizes and shapes stay
752
+ (`aria-busy`, dropped `data-action`, disabled buttons). Only unknown values become
753
+ skeletons; nothing else may change. Sizes, shapes, typography, color, and opacity stay
190
754
  identical to the populated component, so a parent composes a faithful loading view —
191
755
  an inspector, a detail pane — from placeholder children without hand-rebuilding
192
756
  markup. The application still owns the loading lifecycle (when to pass `placeholder`)
193
- and which slots are unknown; the standalone `Skeleton` covers custom slots. It is a
757
+ and which slots are unknown; the standalone `Skeleton` covers custom slots. A
758
+ `Skeleton` is `inline-block` so it sits in a text line; pass `block` to lay it out
759
+ as `display: block` where it stands in for a box, such as an icon, so it takes no
760
+ line of its own and centers in its slot. It is a
194
761
  placeholder, not progress: use `LoadingSpinner` for known busy activity, and never
195
762
  animate the skeleton.
196
763
 
764
+ `LucideIcon` defaults to `appearance="outline"`. Pass
765
+ `appearance="solid"` for a filled state glyph such as a selected star or
766
+ triangle. The SVG uses `fill="currentColor"`, so fill follows the icon's text
767
+ color without styling its internal SVG from the application. Choose a Lucide
768
+ node whose geometry supports a solid fill; the prop does not replace an icon
769
+ node's own fill attributes.
770
+ The SVG is block-level by default. Pass `inline` when it belongs inside a
771
+ sentence or `Text`: the SVG becomes `inline-block`, keeps its inherited 1em
772
+ size unless `size` is supplied, and stays decorative unless `label` is set.
773
+
774
+ `LoadingSpinner` accepts the same `size` steps as `LucideIcon`: `xs`, `s`, `m`,
775
+ `l`, `xl` (12/16/20/24/32px at a 16px root) or a positive finite pixel
776
+ number converted to rem. Omit `size` to keep its inherited 1em box. A supplied
777
+ size is exposed as `data-size`; callers configure the spinner through this prop
778
+ instead of sizing its SVG from outside.
779
+
780
+ A placeholder is loading, not unavailable, so it keeps the `disabled` attribute (its
781
+ controls stay inert and out of the keyboard order) but never shows disabled chrome.
782
+ `skeleton.css`, which every component that renders a skeleton loads, neutralizes generic
783
+ disabled styling under `[data-placeholder="true"]` — including Web Awesome's native
784
+ `button:disabled { opacity: 0.5; cursor: not-allowed }` when `webawesome.css` is
785
+ loaded — to full opacity and the non-interactive `default` cursor. That opacity reset
786
+ carries zero specificity, so a component's own opacity (a control hidden until
787
+ interaction) still wins, and each component excludes placeholders from its own
788
+ disabled tone and hover feedback — including hover reveals: a `ListActionRow` with
789
+ `trailingActionVisibility="interaction"` keeps its trailing action hidden when its
790
+ placeholder is hovered, as the resting live row does. The cursor is the one intentional difference from the
791
+ live state: a placeholder is not clickable, so it never advertises a pointer.
792
+
793
+ A control the author disabled is different: it will be unavailable once loaded, so its
794
+ placeholder keeps the live disabled tone. Each such control carries the component-owned
795
+ `data-kui-disabled="true"` marker whenever its own disabled prop is set, independent of
796
+ `placeholder` — `ListItem` and `ListActionRow` `disabled`, `trailingActionDisabled`,
797
+ a `SegmentedControl` choice's `disabled`, and `ListHeader` `actionDisabled` (on the
798
+ action or disclosure toggle). The placeholder reset skips the marker and components key
799
+ their disabled tone on it, so only the `placeholder`-only `disabled` attribute is
800
+ neutralized. That tone is each component's own, never Web Awesome's native
801
+ `button:disabled`, so an author-disabled control is dimmed with or without
802
+ `webawesome.css`. The marker is reserved: the extension-attribute channels
803
+ (`rootAttributes`, `trailingActionAttributes`, `triggerAttributes`) cannot set it. A
804
+ disabled placeholder still shows the `default` cursor, never `not-allowed`.
805
+ Chrome a component draws itself from a known prop stays live, even inside a slot that
806
+ also holds values. `ListItem`'s trailing slot has three inputs: the `busy` spinner is
807
+ component-owned chrome and stays live, while `status` text and author-supplied
808
+ `trailing` content are values and each become a skeleton (the component cannot tell an
809
+ author's chevron from a count, so all `trailing` content is treated as a value).
810
+ `ListActionRow`'s status line follows the same split: its `busy` spinner stays live and
811
+ only the `status` text becomes a skeleton.
812
+ `SegmentedControl` is the one placeholder without a skeleton: its choices are known
813
+ chrome and only the selection is unknown, so it renders every choice's live label or
814
+ icon at its live geometry, selects none, and neutralizes its own disabled chrome.
815
+ `tests/browser/placeholder-fixture.spec.ts` enforces the rule: it renders every
816
+ placeholder component live and as a placeholder from identical props and diffs each
817
+ element's geometry and computed chrome, excluding only the value slots, and checks that
818
+ every author-disabled control is dimmed in both renders.
819
+
197
820
  Package source styles express root-scaled geometry with `remify(<px>)`; the
198
821
  build converts it against the 16px authoring baseline and exposes only ordinary
199
822
  `rem` CSS. Literal pixels remain for intentional hairlines, and `em` remains
@@ -209,7 +832,25 @@ Kerf JSX declaration boundary for every catalog-supported `wa-*` tag.
209
832
  Consumers register only the individual Web Awesome modules they render and can
210
833
  override `--wa-*` values after the theme import. The shared `--wa-*` values feed
211
834
  both Web Awesome controls and Kerf's `--kui-*` foundation aliases, preventing a
212
- second application palette.
835
+ second application palette. Without the theme, every foundation color token,
836
+ every elevation token (`--kui-shadow-*`), and the focus-ring color fall back to
837
+ the same value the theme assigns, including its `light-dark()` pair, so
838
+ surfaces (including the dark `surface-raised`), links (`text-link` is the brand
839
+ on-quiet text color, not the brand fill), tone text, fills, and raised-surface
840
+ shadows keep their light and dark appearance and contrast either way. The
841
+ theme's elevation shadows are scheme-aware: light keeps the soft Hot Sheet 2
842
+ alphas, and dark raises them (`--wa-shadow-s` 14% to 50% black, `-m` 11% to
843
+ 40%, `-l` 9% to 32%) so a raised surface still separates from a near-black
844
+ page.
845
+ Kerf owns the light `brand`, `success`, and `warning` `on-quiet` values in that
846
+ theme layer: each keeps its hue but is dark enough to clear WCAG AA (4.5:1) on
847
+ the lowered page background (`--kui-color-surface-lowered`, approximately `#f2f2f7` over white), not
848
+ only on the white surface, so toned text reads on every background a page
849
+ paints. It likewise owns every tone's loud pair: each `on-loud` text color
850
+ clears AA on its `fill-loud` in both schemes. Light brand and danger keep white
851
+ text on a slightly deeper fill of the same hue (`#0075db`, `#eb0005`); success
852
+ keeps its bright green with dark text, as warning does; the dark-mode brand and
853
+ danger fills keep their color with dark text.
213
854
 
214
855
  `Select` owns its custom-element reconciliation seam. It gives each slotted
215
856
  option icon a stable key and leaves the upgraded Web Awesome-owned slot subtree
@@ -228,4 +869,38 @@ Keep product adapters outside the package: connection-state maps, ticket empty-s
228
869
 
229
870
  ## Testing contract
230
871
 
231
- 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.
872
+ 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.
873
+
874
+ ### Toolbar width visibility
875
+
876
+ `ToolbarText` and `ToolbarControlGroup` accept typed `hideBelow` and
877
+ `showBelow` CSS lengths. Call `wireToolbarVisibility(root)` from
878
+ `@kerfjs/ui/wire-toolbar-visibility` after mounting, and call its disposer when
879
+ the application unmounts. The nearest Toolbar's **content-box width**, excluding
880
+ padding, borders, and safe-area insets, determines visibility. `hideBelow={px(416)}`
881
+ hides strictly below 416px; `showBelow={px(416)}` shows strictly below 416px. At
882
+ 416px the first is visible and the second hidden. Together they define the visible
883
+ interval `[hideBelow, showBelow)`. Width rules intersect existing visibility and
884
+ expanded-state rules; they never force a CSS-hidden group visible.
885
+
886
+ Use `px`, `rem`, `em`, `pct`, `space`, `lengthVar`, or `calc`/`plus` to construct
887
+ lengths. Percentages resolve against that content box, `em` uses the child item's
888
+ font size, and custom properties use its inherited and own token context. The
889
+ helper follows resizes, theme/token/font changes, inserted items, nested toolbars,
890
+ and relocated groups. Invalid, unresolved, negative, or contradictory thresholds
891
+ leave the item visible under this width policy. Server-rendered content is visible
892
+ until wiring runs; without browser observers, initial wiring and window resize
893
+ still update it. Probe context and lengths are reconciled only when their CSSOM
894
+ values change, so unrelated DOM observers can redraw without feeding an ongoing
895
+ mutation loop. Probes are helper-owned imperative nodes preserved across Kerf
896
+ rerenders, preventing repeated probe creation and resize/DOM observer churn.
897
+ Invisible preserved state children keep actual CSS visibility stable while a render
898
+ removes transient parent markers, so post-render geometry measurements cannot
899
+ feed a show/hide render loop. These children never enter layout, focus or the
900
+ accessible tree. Toolbar replacement or deliberate internal-node removal is
901
+ still repaired. Dispose to
902
+ remove measurement probes and restore prior markers.
903
+
904
+ Hidden controls leave layout and keyboard navigation. A hidden busy group also
905
+ hides only its own adjacent busy status. Keep primary actions always available;
906
+ show a complementary overflow group for secondary actions at narrow widths.