@kerfjs/ui 5.0.0-beta.9 → 5.0.0-beta.90

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