@kerfjs/ui 5.0.0-beta.7 → 5.0.0-beta.70

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 (723) hide show
  1. package/README.md +501 -139
  2. package/ai/application-ui-diagnostic-ids-v1.json +109 -0
  3. package/ai/application-ui-profile-sync.cjs +548 -0
  4. package/ai/application-ui-profile.d.mts +1 -0
  5. package/ai/application-ui-profile.d.ts +106 -0
  6. package/ai/application-ui-profile.defaults.json +96 -0
  7. package/ai/application-ui-profile.mjs +653 -0
  8. package/ai/application-ui-profile.schema.json +140 -0
  9. package/ai/catalog-authoring.json +36 -0
  10. package/ai/catalog-authoring.schema.json +109 -0
  11. package/ai/compile-time-contracts-v1.json +149 -0
  12. package/ai/compile-time-contracts-v1.schema.json +52 -0
  13. package/ai/component-catalog-extension.schema.json +104 -0
  14. package/ai/component-catalog.json +3910 -464
  15. package/ai/component-catalog.schema.json +92 -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 +524 -0
  20. package/ai/component-composition.d.ts +127 -0
  21. package/ai/component-composition.json +7128 -0
  22. package/ai/component-composition.schema.json +399 -0
  23. package/ai/components/README.md +171 -0
  24. package/ai/components/application-tabs.md +65 -0
  25. package/ai/components/badge.md +72 -0
  26. package/ai/components/chip.md +72 -0
  27. package/ai/components/collapsible-panel.md +102 -0
  28. package/ai/components/content-item.md +93 -0
  29. package/ai/components/disclosure-arrow.md +77 -0
  30. package/ai/components/document-baseline.md +75 -0
  31. package/ai/components/empty-state.md +80 -0
  32. package/ai/components/feedback.md +71 -0
  33. package/ai/components/floating-toolbar.md +82 -0
  34. package/ai/components/foundation.md +65 -0
  35. package/ai/components/grid.md +98 -0
  36. package/ai/components/headers.md +63 -0
  37. package/ai/components/layout.md +75 -0
  38. package/ai/components/list-action-row.md +91 -0
  39. package/ai/components/list-header.md +89 -0
  40. package/ai/components/list-inset-control.md +74 -0
  41. package/ai/components/list-inset-text.md +72 -0
  42. package/ai/components/list-item.md +94 -0
  43. package/ai/components/list.md +105 -0
  44. package/ai/components/loading-spinner.md +73 -0
  45. package/ai/components/lucide-icon.md +78 -0
  46. package/ai/components/nav-stack.md +104 -0
  47. package/ai/components/pane.md +101 -0
  48. package/ai/components/popup-menu.md +171 -0
  49. package/ai/components/recipe-app-shell.md +57 -0
  50. package/ai/components/recipe-collapsible-sidebar.md +57 -0
  51. package/ai/components/recipe-compact-toolbar.md +57 -0
  52. package/ai/components/recipe-composer-form.md +57 -0
  53. package/ai/components/recipe-list-detail-dialog.md +57 -0
  54. package/ai/components/recipe-list-workspace-states.md +57 -0
  55. package/ai/components/recipe-loading-inspector.md +57 -0
  56. package/ai/components/recipe-navigation-sidebar.md +57 -0
  57. package/ai/components/recipe-navigation-stack.md +57 -0
  58. package/ai/components/recipe-workspace-header.md +57 -0
  59. package/ai/components/resize.md +106 -0
  60. package/ai/components/row.md +96 -0
  61. package/ai/components/segmented-control.md +82 -0
  62. package/ai/components/select.md +113 -0
  63. package/ai/components/skeleton.md +84 -0
  64. package/ai/components/spacer.md +86 -0
  65. package/ai/components/split-view.md +102 -0
  66. package/ai/components/state-banner.md +94 -0
  67. package/ai/components/sunken-panel.md +79 -0
  68. package/ai/components/surface-scaffold.md +78 -0
  69. package/ai/components/tab-bar.md +113 -0
  70. package/ai/components/tab-scaffold.md +94 -0
  71. package/ai/components/tabs.md +95 -0
  72. package/ai/components/text.md +85 -0
  73. package/ai/components/token-search-field.md +106 -0
  74. package/ai/components/toolbar-control-group.md +102 -0
  75. package/ai/components/toolbar-text.md +79 -0
  76. package/ai/components/toolbar.md +97 -0
  77. package/ai/components/value-table.md +73 -0
  78. package/ai/components/wa-accordion-item.md +55 -0
  79. package/ai/components/wa-accordion.md +65 -0
  80. package/ai/components/wa-animated-image.md +55 -0
  81. package/ai/components/wa-animation.md +55 -0
  82. package/ai/components/wa-avatar.md +55 -0
  83. package/ai/components/wa-badge.md +55 -0
  84. package/ai/components/wa-breadcrumb-item.md +53 -0
  85. package/ai/components/wa-breadcrumb.md +55 -0
  86. package/ai/components/wa-button-group.md +59 -0
  87. package/ai/components/wa-button.md +55 -0
  88. package/ai/components/wa-callout.md +58 -0
  89. package/ai/components/wa-card.md +59 -0
  90. package/ai/components/wa-carousel-item.md +53 -0
  91. package/ai/components/wa-carousel.md +55 -0
  92. package/ai/components/wa-checkbox-group.md +55 -0
  93. package/ai/components/wa-checkbox.md +55 -0
  94. package/ai/components/wa-color-picker.md +55 -0
  95. package/ai/components/wa-comparison.md +55 -0
  96. package/ai/components/wa-copy-button.md +55 -0
  97. package/ai/components/wa-details.md +61 -0
  98. package/ai/components/wa-dialog.md +59 -0
  99. package/ai/components/wa-divider.md +53 -0
  100. package/ai/components/wa-drawer.md +55 -0
  101. package/ai/components/wa-dropdown-item.md +60 -0
  102. package/ai/components/wa-dropdown.md +60 -0
  103. package/ai/components/wa-format-bytes.md +53 -0
  104. package/ai/components/wa-format-date.md +53 -0
  105. package/ai/components/wa-format-number.md +53 -0
  106. package/ai/components/wa-icon.md +58 -0
  107. package/ai/components/wa-include.md +53 -0
  108. package/ai/components/wa-input.md +59 -0
  109. package/ai/components/wa-intersection-observer.md +53 -0
  110. package/ai/components/wa-known-date.md +53 -0
  111. package/ai/components/wa-markdown.md +53 -0
  112. package/ai/components/wa-mutation-observer.md +53 -0
  113. package/ai/components/wa-number-input.md +55 -0
  114. package/ai/components/wa-option.md +59 -0
  115. package/ai/components/wa-otp-input.md +53 -0
  116. package/ai/components/wa-page.md +53 -0
  117. package/ai/components/wa-pagination.md +55 -0
  118. package/ai/components/wa-popover.md +55 -0
  119. package/ai/components/wa-popup.md +53 -0
  120. package/ai/components/wa-progress-bar.md +53 -0
  121. package/ai/components/wa-progress-ring.md +53 -0
  122. package/ai/components/wa-qr-code.md +53 -0
  123. package/ai/components/wa-radio-group.md +59 -0
  124. package/ai/components/wa-radio.md +55 -0
  125. package/ai/components/wa-random-content.md +53 -0
  126. package/ai/components/wa-rating.md +55 -0
  127. package/ai/components/wa-relative-time.md +53 -0
  128. package/ai/components/wa-resize-observer.md +53 -0
  129. package/ai/components/wa-scroller.md +53 -0
  130. package/ai/components/wa-select.md +63 -0
  131. package/ai/components/wa-skeleton.md +53 -0
  132. package/ai/components/wa-slider.md +55 -0
  133. package/ai/components/wa-spinner.md +58 -0
  134. package/ai/components/wa-split-panel.md +58 -0
  135. package/ai/components/wa-switch.md +53 -0
  136. package/ai/components/wa-tab-group.md +69 -0
  137. package/ai/components/wa-tab-panel.md +60 -0
  138. package/ai/components/wa-tab.md +59 -0
  139. package/ai/components/wa-tag.md +59 -0
  140. package/ai/components/wa-textarea.md +53 -0
  141. package/ai/components/wa-time-input.md +55 -0
  142. package/ai/components/wa-toast-item.md +60 -0
  143. package/ai/components/wa-toast.md +60 -0
  144. package/ai/components/wa-tooltip.md +55 -0
  145. package/ai/components/wa-tree-item.md +55 -0
  146. package/ai/components/wa-tree.md +55 -0
  147. package/ai/components/wa-zoomable-frame.md +55 -0
  148. package/ai/components/workbench.md +118 -0
  149. package/ai/public-api-signatures-v1.md +2748 -210
  150. package/ai/skill.md +286 -66
  151. package/ai/webawesome-jsx-signatures-v1.md +9 -2
  152. package/analyzer/cli.mjs +49 -0
  153. package/analyzer/component-ownership.d.mts +72 -0
  154. package/analyzer/component-ownership.mjs +286 -0
  155. package/analyzer/index.d.mts +52 -0
  156. package/analyzer/index.mjs +2038 -0
  157. package/analyzer/loud-pairs.d.mts +49 -0
  158. package/analyzer/loud-pairs.mjs +357 -0
  159. package/analyzer/report.schema.json +66 -0
  160. package/analyzer/selectors.d.mts +21 -0
  161. package/analyzer/selectors.mjs +212 -0
  162. package/catalog-projection-cli.mjs +96 -0
  163. package/catalog-projection.d.mts +55 -0
  164. package/catalog-projection.mjs +62 -0
  165. package/dist/app-tab.d.ts +39 -4
  166. package/dist/app-tab.js +2 -1
  167. package/dist/badge.d.ts +52 -0
  168. package/dist/badge.js +3 -0
  169. package/dist/badge.js.map +1 -0
  170. package/dist/browser/badge.js +3 -0
  171. package/dist/browser/catalog.js +26 -0
  172. package/dist/browser/chip.js +3 -0
  173. package/dist/browser/collapsible-panel.js +9 -0
  174. package/dist/browser/content-item.js +3 -0
  175. package/dist/browser/floating-toolbar.js +3 -0
  176. package/dist/browser/grid.js +3 -0
  177. package/dist/browser/list-action-row.js +5 -0
  178. package/dist/browser/{menu-header.js → list-header.js} +4 -2
  179. package/dist/browser/list-inset-control.js +3 -0
  180. package/dist/browser/list-inset-text.js +3 -0
  181. package/dist/browser/list-item.js +5 -0
  182. package/dist/browser/list.js +3 -0
  183. package/dist/browser/{panel-header.js → nav-stack.js} +5 -3
  184. package/dist/browser/pane.js +3 -0
  185. package/dist/browser/popup-menu.js +3 -0
  186. package/dist/browser/row.js +3 -0
  187. package/dist/browser/segmented-control.js +0 -1
  188. package/dist/browser/select.js +1 -0
  189. package/dist/browser/spacer.js +3 -0
  190. package/dist/browser/split-view.js +11 -0
  191. package/dist/browser/state-banner.js +1 -0
  192. package/dist/browser/sunken-panel.js +3 -0
  193. package/dist/browser/surface-scaffold.js +3 -0
  194. package/dist/browser/tab-scaffold.js +4 -0
  195. package/dist/browser/text.js +3 -0
  196. package/dist/browser/toolbar-control-group.js +1 -0
  197. package/dist/browser/workbench.js +14 -0
  198. package/dist/catalog-resources.d.ts +48 -0
  199. package/dist/catalog-resources.js +22 -0
  200. package/dist/catalog-resources.js.map +1 -0
  201. package/dist/catalog.d.ts +92 -0
  202. package/dist/catalog.js +503 -0
  203. package/dist/catalog.js.map +1 -0
  204. package/dist/chip.d.ts +35 -0
  205. package/dist/chip.js +3 -0
  206. package/dist/chip.js.map +1 -0
  207. package/dist/chunk-2G2ZJQYK.js +152 -0
  208. package/dist/chunk-2G2ZJQYK.js.map +1 -0
  209. package/dist/chunk-3BYFWTP3.js +108 -0
  210. package/dist/chunk-3BYFWTP3.js.map +1 -0
  211. package/dist/chunk-47CKKLBE.js +34 -0
  212. package/dist/chunk-47CKKLBE.js.map +1 -0
  213. package/dist/chunk-4SQK27MR.js +202 -0
  214. package/dist/chunk-4SQK27MR.js.map +1 -0
  215. package/dist/chunk-5I7QGQVT.js +24 -0
  216. package/dist/chunk-5I7QGQVT.js.map +1 -0
  217. package/dist/chunk-6DFDTWGG.js +288 -0
  218. package/dist/chunk-6DFDTWGG.js.map +1 -0
  219. package/dist/chunk-7OKX3EF6.js +135 -0
  220. package/dist/chunk-7OKX3EF6.js.map +1 -0
  221. package/dist/chunk-AHEG27M7.js +66 -0
  222. package/dist/chunk-AHEG27M7.js.map +1 -0
  223. package/dist/chunk-AYUHMAI6.js +48 -0
  224. package/dist/chunk-AYUHMAI6.js.map +1 -0
  225. package/dist/chunk-B2ZMR7NY.js +85 -0
  226. package/dist/chunk-B2ZMR7NY.js.map +1 -0
  227. package/dist/chunk-BFPBS5Y4.js +250 -0
  228. package/dist/chunk-BFPBS5Y4.js.map +1 -0
  229. package/dist/chunk-DB5ADJKF.js +775 -0
  230. package/dist/chunk-DB5ADJKF.js.map +1 -0
  231. package/dist/chunk-DC6CN2DS.js +123 -0
  232. package/dist/chunk-DC6CN2DS.js.map +1 -0
  233. package/dist/chunk-DG6G5EPF.js +35 -0
  234. package/dist/chunk-DG6G5EPF.js.map +1 -0
  235. package/dist/{chunk-56RJXPHG.js → chunk-G4S2QU6V.js} +7 -4
  236. package/dist/chunk-G4S2QU6V.js.map +1 -0
  237. package/dist/chunk-GLDWRCAM.js +49 -0
  238. package/dist/chunk-GLDWRCAM.js.map +1 -0
  239. package/dist/chunk-I3Q7KKYM.js +33 -0
  240. package/dist/chunk-I3Q7KKYM.js.map +1 -0
  241. package/dist/chunk-IA7TMD4Y.js +288 -0
  242. package/dist/chunk-IA7TMD4Y.js.map +1 -0
  243. package/dist/chunk-J3KGJ6P6.js +135 -0
  244. package/dist/chunk-J3KGJ6P6.js.map +1 -0
  245. package/dist/chunk-K47P7QZC.js +17 -0
  246. package/dist/chunk-K47P7QZC.js.map +1 -0
  247. package/dist/chunk-K67Y2JNF.js +222 -0
  248. package/dist/chunk-K67Y2JNF.js.map +1 -0
  249. package/dist/chunk-KCCEH7RF.js +492 -0
  250. package/dist/chunk-KCCEH7RF.js.map +1 -0
  251. package/dist/chunk-KLJKU6ZL.js +109 -0
  252. package/dist/chunk-KLJKU6ZL.js.map +1 -0
  253. package/dist/chunk-KVBRMEPM.js +44 -0
  254. package/dist/chunk-KVBRMEPM.js.map +1 -0
  255. package/dist/chunk-M6DEEBEF.js +156 -0
  256. package/dist/chunk-M6DEEBEF.js.map +1 -0
  257. package/dist/chunk-MEY33VWB.js +44 -0
  258. package/dist/chunk-MEY33VWB.js.map +1 -0
  259. package/dist/chunk-MP2GDBQZ.js +50 -0
  260. package/dist/chunk-MP2GDBQZ.js.map +1 -0
  261. package/dist/chunk-NC4CFOID.js +188 -0
  262. package/dist/chunk-NC4CFOID.js.map +1 -0
  263. package/dist/chunk-NCSWXG7G.js +80 -0
  264. package/dist/chunk-NCSWXG7G.js.map +1 -0
  265. package/dist/chunk-NN6GYOA2.js +47 -0
  266. package/dist/chunk-NN6GYOA2.js.map +1 -0
  267. package/dist/chunk-OXO2QJWV.js +55 -0
  268. package/dist/chunk-OXO2QJWV.js.map +1 -0
  269. package/dist/chunk-P7D3EMXM.js +52 -0
  270. package/dist/chunk-P7D3EMXM.js.map +1 -0
  271. package/dist/chunk-PSHUSWQH.js +18 -0
  272. package/dist/chunk-PSHUSWQH.js.map +1 -0
  273. package/dist/chunk-Q6YU3BT7.js +138 -0
  274. package/dist/chunk-Q6YU3BT7.js.map +1 -0
  275. package/dist/chunk-QJ5VFCW3.js +131 -0
  276. package/dist/chunk-QJ5VFCW3.js.map +1 -0
  277. package/dist/chunk-RGS4WX2M.js +44 -0
  278. package/dist/chunk-RGS4WX2M.js.map +1 -0
  279. package/dist/chunk-RNQNEENY.js +146 -0
  280. package/dist/chunk-RNQNEENY.js.map +1 -0
  281. package/dist/chunk-RVERAFFY.js +291 -0
  282. package/dist/chunk-RVERAFFY.js.map +1 -0
  283. package/dist/chunk-SMZGAPCU.js +70 -0
  284. package/dist/chunk-SMZGAPCU.js.map +1 -0
  285. package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
  286. package/dist/chunk-SRSJO5QE.js.map +1 -0
  287. package/dist/chunk-T2E5WBCZ.js +482 -0
  288. package/dist/chunk-T2E5WBCZ.js.map +1 -0
  289. package/dist/chunk-TJK44RQC.js +452 -0
  290. package/dist/chunk-TJK44RQC.js.map +1 -0
  291. package/dist/chunk-UIDKY4UB.js +14 -0
  292. package/dist/chunk-UIDKY4UB.js.map +1 -0
  293. package/dist/chunk-V3DX3K65.js +43 -0
  294. package/dist/chunk-V3DX3K65.js.map +1 -0
  295. package/dist/chunk-VZOFZPSO.js +71 -0
  296. package/dist/chunk-VZOFZPSO.js.map +1 -0
  297. package/dist/chunk-W2AC6Q2A.js +83 -0
  298. package/dist/chunk-W2AC6Q2A.js.map +1 -0
  299. package/dist/chunk-WF75U3V4.js +33 -0
  300. package/dist/chunk-WF75U3V4.js.map +1 -0
  301. package/dist/chunk-WTSNV5RG.js +52 -0
  302. package/dist/chunk-WTSNV5RG.js.map +1 -0
  303. package/dist/{chunk-YGN7OMLT.js → chunk-X5QSICJ3.js} +8 -5
  304. package/dist/chunk-X5QSICJ3.js.map +1 -0
  305. package/dist/chunk-YDGNU2OD.js +61 -0
  306. package/dist/chunk-YDGNU2OD.js.map +1 -0
  307. package/dist/collapsible-panel.d.ts +133 -0
  308. package/dist/collapsible-panel.js +131 -0
  309. package/dist/collapsible-panel.js.map +1 -0
  310. package/dist/content-item.d.ts +81 -0
  311. package/dist/content-item.js +4 -0
  312. package/dist/content-item.js.map +1 -0
  313. package/dist/css-values.d.ts +107 -0
  314. package/dist/css-values.js +3 -0
  315. package/dist/css-values.js.map +1 -0
  316. package/dist/device-class.js +33 -5
  317. package/dist/device-class.js.map +1 -1
  318. package/dist/disclosure-arrow.d.ts +6 -1
  319. package/dist/disclosure-arrow.js +2 -1
  320. package/dist/empty-state.d.ts +5 -2
  321. package/dist/empty-state.js +2 -1
  322. package/dist/flex-alignment-4ms8ZbV8.d.ts +5 -0
  323. package/dist/floating-toolbar.d.ts +51 -0
  324. package/dist/floating-toolbar.js +3 -0
  325. package/dist/floating-toolbar.js.map +1 -0
  326. package/dist/grid.d.ts +50 -0
  327. package/dist/grid.js +5 -0
  328. package/dist/grid.js.map +1 -0
  329. package/dist/help-tags-register.d.ts +13 -0
  330. package/dist/help-tags-register.js +9 -0
  331. package/dist/help-tags-register.js.map +1 -0
  332. package/dist/index.d.ts +34 -14
  333. package/dist/index.js +43 -23
  334. package/dist/{menu-action-row.d.ts → list-action-row.d.ts} +21 -9
  335. package/dist/list-action-row.js +8 -0
  336. package/dist/list-action-row.js.map +1 -0
  337. package/dist/list-header.d.ts +99 -0
  338. package/dist/list-header.js +10 -0
  339. package/dist/list-header.js.map +1 -0
  340. package/dist/list-inset-control.d.ts +22 -0
  341. package/dist/list-inset-control.js +3 -0
  342. package/dist/list-inset-control.js.map +1 -0
  343. package/dist/list-inset-text.d.ts +30 -0
  344. package/dist/list-inset-text.js +4 -0
  345. package/dist/list-inset-text.js.map +1 -0
  346. package/dist/list-item.d.ts +62 -0
  347. package/dist/list-item.js +8 -0
  348. package/dist/list-item.js.map +1 -0
  349. package/dist/list.d.ts +63 -0
  350. package/dist/list.js +6 -0
  351. package/dist/list.js.map +1 -0
  352. package/dist/loading-spinner.d.ts +9 -2
  353. package/dist/loading-spinner.js +2 -1
  354. package/dist/lucide-icon.d.ts +9 -2
  355. package/dist/lucide-icon.js +2 -1
  356. package/dist/nav-stack.d.ts +66 -10
  357. package/dist/nav-stack.js +6 -1
  358. package/dist/pane.d.ts +108 -0
  359. package/dist/pane.js +4 -0
  360. package/dist/pane.js.map +1 -0
  361. package/dist/panel-toolbar-DDKh4uKd.d.ts +72 -0
  362. package/dist/popup-menu-register.d.ts +9 -0
  363. package/dist/popup-menu-register.js +244 -0
  364. package/dist/popup-menu-register.js.map +1 -0
  365. package/dist/popup-menu.d.ts +100 -0
  366. package/dist/popup-menu.js +3 -0
  367. package/dist/popup-menu.js.map +1 -0
  368. package/dist/resizable-region.d.ts +32 -3
  369. package/dist/resizable-region.js +1 -1
  370. package/dist/row.d.ts +48 -0
  371. package/dist/row.js +6 -0
  372. package/dist/row.js.map +1 -0
  373. package/dist/segmented-control.d.ts +12 -9
  374. package/dist/segmented-control.js +1 -2
  375. package/dist/select-register.d.ts +5 -1
  376. package/dist/select-register.js +243 -2
  377. package/dist/select-register.js.map +1 -1
  378. package/dist/select.d.ts +102 -8
  379. package/dist/select.js +3 -1
  380. package/dist/semantic-content-BbzjvSu9.d.ts +14 -0
  381. package/dist/sides-BPSWde0A.d.ts +4 -0
  382. package/dist/skeleton.d.ts +14 -7
  383. package/dist/skeleton.js +2 -1
  384. package/dist/spacer.d.ts +18 -0
  385. package/dist/spacer.js +4 -0
  386. package/dist/spacer.js.map +1 -0
  387. package/dist/split-view.d.ts +39 -7
  388. package/dist/split-view.js +120 -10
  389. package/dist/split-view.js.map +1 -1
  390. package/dist/state-banner.d.ts +18 -6
  391. package/dist/state-banner.js +3 -1
  392. package/dist/styles/app-tab.css +221 -0
  393. package/dist/styles/badge.css +118 -0
  394. package/dist/styles/catalog/components/catalog-example-stack.css +9 -0
  395. package/dist/styles/catalog/components/catalog-example.css +168 -0
  396. package/dist/styles/catalog/components/catalog-stage.css +55 -0
  397. package/dist/styles/catalog/components/catalog.css +12 -0
  398. package/dist/styles/catalog.css +5 -0
  399. package/dist/styles/chip.css +132 -0
  400. package/dist/styles/collapsible-panel.css +575 -0
  401. package/dist/styles/content-item.css +75 -0
  402. package/dist/styles/document.css +23 -0
  403. package/dist/styles/floating-toolbar.css +119 -0
  404. package/dist/styles/foundation.css +178 -40
  405. package/dist/styles/grid.css +35 -0
  406. package/dist/styles/layout.css +3 -41
  407. package/dist/styles/list-action-row.css +258 -0
  408. package/dist/styles/list-header.css +229 -0
  409. package/dist/styles/list-inset-control.css +30 -0
  410. package/dist/styles/list-inset-text.css +29 -0
  411. package/dist/styles/list-item.css +255 -0
  412. package/dist/styles/list.css +133 -0
  413. package/dist/styles/loading-spinner.css +4 -0
  414. package/dist/styles/lucide-icon.css +5 -0
  415. package/dist/styles/nav-stack.css +172 -47
  416. package/dist/styles/pane.css +263 -0
  417. package/dist/styles/popup-menu.css +285 -0
  418. package/dist/styles/resizable-region.css +438 -4
  419. package/dist/styles/row.css +111 -0
  420. package/dist/styles/segmented-control.css +36 -9
  421. package/dist/styles/select.css +337 -21
  422. package/dist/styles/skeleton.css +64 -3
  423. package/dist/styles/spacer.css +11 -0
  424. package/dist/styles/split-view.css +114 -3
  425. package/dist/styles/state-banner.css +94 -19
  426. package/dist/styles/styles.css +13 -4
  427. package/dist/styles/sunken-panel.css +29 -0
  428. package/dist/styles/surface-scaffold.css +56 -0
  429. package/dist/styles/tab-bar.css +147 -9
  430. package/dist/styles/tab-scaffold.css +126 -3
  431. package/dist/styles/text.css +112 -0
  432. package/dist/styles/token-search-field.css +155 -55
  433. package/dist/styles/toolbar-control-group.css +608 -29
  434. package/dist/styles/toolbar-text.css +101 -8
  435. package/dist/styles/toolbar.css +334 -12
  436. package/dist/styles/value-table.css +34 -4
  437. package/dist/styles/webawesome.css +365 -10
  438. package/dist/styles/workbench.css +980 -7
  439. package/dist/sunken-panel.d.ts +27 -0
  440. package/dist/sunken-panel.js +3 -0
  441. package/dist/sunken-panel.js.map +1 -0
  442. package/dist/surface-scaffold.d.ts +30 -0
  443. package/dist/surface-scaffold.js +3 -0
  444. package/dist/surface-scaffold.js.map +1 -0
  445. package/dist/tab-bar.d.ts +39 -6
  446. package/dist/tab-bar.js +1 -1
  447. package/dist/tab-scaffold.d.ts +57 -7
  448. package/dist/tab-scaffold.js +83 -9
  449. package/dist/tab-scaffold.js.map +1 -1
  450. package/dist/text.d.ts +56 -0
  451. package/dist/text.js +3 -0
  452. package/dist/text.js.map +1 -0
  453. package/dist/token-search-field-CVGwDn2y.d.ts +154 -0
  454. package/dist/token-search-field.d.ts +3 -43
  455. package/dist/token-search-field.js +2 -1
  456. package/dist/token-search-model.d.ts +3 -0
  457. package/dist/token-search-model.js +3 -0
  458. package/dist/token-search-model.js.map +1 -0
  459. package/dist/toolbar-control-group.d.ts +77 -7
  460. package/dist/toolbar-control-group.js +3 -1
  461. package/dist/toolbar-text.d.ts +35 -4
  462. package/dist/toolbar-text.js +2 -1
  463. package/dist/toolbar.d.ts +59 -7
  464. package/dist/toolbar.js +1 -1
  465. package/dist/types-BuHELdXR.d.ts +117 -0
  466. package/dist/value-table.d.ts +11 -3
  467. package/dist/value-table.js +2 -1
  468. package/dist/webawesome.d.ts +8 -1
  469. package/dist/wire-catalog.d.ts +82 -0
  470. package/dist/wire-catalog.js +327 -0
  471. package/dist/wire-catalog.js.map +1 -0
  472. package/dist/wire-content-items.d.ts +11 -0
  473. package/dist/wire-content-items.js +114 -0
  474. package/dist/wire-content-items.js.map +1 -0
  475. package/dist/wire-nav-stack.d.ts +4 -1
  476. package/dist/wire-nav-stack.js +147 -7
  477. package/dist/wire-nav-stack.js.map +1 -1
  478. package/dist/wire-resizable-regions.d.ts +2 -1
  479. package/dist/wire-resizable-regions.js +2 -1
  480. package/dist/wire-scroll-dividers.d.ts +72 -0
  481. package/dist/wire-scroll-dividers.js +3 -0
  482. package/dist/wire-scroll-dividers.js.map +1 -0
  483. package/dist/wire-sidebar.d.ts +63 -0
  484. package/dist/wire-sidebar.js +231 -0
  485. package/dist/wire-sidebar.js.map +1 -0
  486. package/dist/wire-tab-bars.d.ts +19 -2
  487. package/dist/wire-tab-bars.js +1 -1
  488. package/dist/wire-tab-scaffold.js +9 -4
  489. package/dist/wire-tab-scaffold.js.map +1 -1
  490. package/dist/wire-token-search-fields.d.ts +65 -3
  491. package/dist/wire-token-search-fields.js +2 -1
  492. package/dist/wire-workbench.d.ts +116 -0
  493. package/dist/wire-workbench.js +6 -0
  494. package/dist/wire-workbench.js.map +1 -0
  495. package/dist/workbench.d.ts +244 -9
  496. package/dist/workbench.js +17 -15
  497. package/dist/workbench.js.map +1 -1
  498. package/docs/accessibility.md +476 -24
  499. package/docs/app-layouts.md +106 -8
  500. package/docs/apple-hig.md +1 -0
  501. package/docs/catalog.md +483 -0
  502. package/docs/collapsible-panel.md +371 -0
  503. package/docs/component-contract.md +658 -56
  504. package/docs/component-integration.md +75 -0
  505. package/docs/component-selection.md +529 -90
  506. package/docs/design/templates/empty-state/filtered-dark.svg +1 -0
  507. package/docs/design/templates/empty-state/filtered.svg +1 -0
  508. package/docs/design/templates/empty-state/with-action-dark.svg +1 -0
  509. package/docs/design/templates/empty-state/with-action.svg +1 -0
  510. package/docs/design/templates/empty-state-dark.svg +1 -0
  511. package/docs/design/templates/empty-state.svg +1 -0
  512. package/docs/design/templates/list/compact-dark.svg +1 -0
  513. package/docs/design/templates/list/compact.svg +1 -0
  514. package/docs/design/templates/list/stack-dark.svg +1 -0
  515. package/docs/design/templates/list/stack.svg +1 -0
  516. package/docs/design/templates/list-action-row/default-dark.svg +1 -0
  517. package/docs/design/templates/list-action-row/default.svg +1 -0
  518. package/docs/design/templates/list-action-row/selected-dark.svg +1 -0
  519. package/docs/design/templates/list-action-row/selected.svg +1 -0
  520. package/docs/design/templates/list-action-row-dark.svg +1 -0
  521. package/docs/design/templates/list-action-row.svg +1 -0
  522. package/docs/design/templates/list-dark.svg +1 -0
  523. package/docs/design/templates/list-header/action-dark.svg +1 -0
  524. package/docs/design/templates/list-header/action.svg +1 -0
  525. package/docs/design/templates/list-header/count-dark.svg +1 -0
  526. package/docs/design/templates/list-header/count.svg +1 -0
  527. package/docs/design/templates/list-header/inline-action-dark.svg +1 -0
  528. package/docs/design/templates/list-header/inline-action.svg +1 -0
  529. package/docs/design/templates/list-header/toggle-collapsed-dark.svg +1 -0
  530. package/docs/design/templates/list-header/toggle-collapsed.svg +1 -0
  531. package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -0
  532. package/docs/design/templates/list-header/toggle-expanded.svg +1 -0
  533. package/docs/design/templates/list-header-dark.svg +1 -0
  534. package/docs/design/templates/list-header.svg +1 -0
  535. package/docs/design/templates/list-item/default-dark.svg +1 -0
  536. package/docs/design/templates/list-item/default.svg +1 -0
  537. package/docs/design/templates/list-item/multiline-dark.svg +1 -0
  538. package/docs/design/templates/list-item/multiline.svg +1 -0
  539. package/docs/design/templates/list-item/selected-dark.svg +1 -0
  540. package/docs/design/templates/list-item/selected.svg +1 -0
  541. package/docs/design/templates/list-item/trailing-dark.svg +1 -0
  542. package/docs/design/templates/list-item/trailing.svg +1 -0
  543. package/docs/design/templates/list-item-dark.svg +1 -0
  544. package/docs/design/templates/list-item.svg +1 -0
  545. package/docs/design/templates/list.svg +1 -0
  546. package/docs/design/templates/segmented-control/equal-dark.svg +1 -0
  547. package/docs/design/templates/segmented-control/equal.svg +1 -0
  548. package/docs/design/templates/segmented-control/pill-small-dark.svg +1 -0
  549. package/docs/design/templates/segmented-control/pill-small.svg +1 -0
  550. package/docs/design/templates/segmented-control-dark.svg +1 -0
  551. package/docs/design/templates/segmented-control.svg +1 -0
  552. package/docs/design/templates/skeleton/avatar-dark.svg +1 -0
  553. package/docs/design/templates/skeleton/avatar.svg +1 -0
  554. package/docs/design/templates/skeleton/block-dark.svg +1 -0
  555. package/docs/design/templates/skeleton/block.svg +1 -0
  556. package/docs/design/templates/skeleton/lines-dark.svg +1 -0
  557. package/docs/design/templates/skeleton/lines.svg +1 -0
  558. package/docs/design/templates/skeleton-dark.svg +1 -0
  559. package/docs/design/templates/skeleton.svg +1 -0
  560. package/docs/design/templates/state-banner/danger-dark.svg +1 -0
  561. package/docs/design/templates/state-banner/danger.svg +1 -0
  562. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -0
  563. package/docs/design/templates/state-banner/info-badge.svg +1 -0
  564. package/docs/design/templates/state-banner/info-dark.svg +1 -0
  565. package/docs/design/templates/state-banner/info.svg +1 -0
  566. package/docs/design/templates/state-banner/success-dark.svg +1 -0
  567. package/docs/design/templates/state-banner/success.svg +1 -0
  568. package/docs/design/templates/state-banner/warning-dark.svg +1 -0
  569. package/docs/design/templates/state-banner/warning.svg +1 -0
  570. package/docs/design/templates/state-banner-dark.svg +1 -0
  571. package/docs/design/templates/state-banner.svg +1 -0
  572. package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -0
  573. package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -0
  574. package/docs/design/templates/tab-bar-dark.svg +1 -0
  575. package/docs/design/templates/tab-bar.svg +1 -0
  576. package/docs/design/templates/token-search-field/empty-dark.svg +1 -0
  577. package/docs/design/templates/token-search-field/empty.svg +1 -0
  578. package/docs/design/templates/token-search-field/tokens-dark.svg +1 -0
  579. package/docs/design/templates/token-search-field/tokens.svg +1 -0
  580. package/docs/design/templates/token-search-field-dark.svg +1 -0
  581. package/docs/design/templates/token-search-field.svg +1 -0
  582. package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -0
  583. package/docs/design/templates/toolbar/title-and-actions.svg +1 -0
  584. package/docs/design/templates/toolbar-control-group/borderless-single-dark.svg +1 -0
  585. package/docs/design/templates/toolbar-control-group/borderless-single.svg +1 -0
  586. package/docs/design/templates/toolbar-control-group/icon-buttons-dark.svg +1 -0
  587. package/docs/design/templates/toolbar-control-group/icon-buttons.svg +1 -0
  588. package/docs/design/templates/toolbar-control-group/push-buttons-dark.svg +1 -0
  589. package/docs/design/templates/toolbar-control-group/push-buttons.svg +1 -0
  590. package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -0
  591. package/docs/design/templates/toolbar-control-group/with-text.svg +1 -0
  592. package/docs/design/templates/toolbar-control-group-dark.svg +1 -0
  593. package/docs/design/templates/toolbar-control-group.svg +1 -0
  594. package/docs/design/templates/toolbar-dark.svg +1 -0
  595. package/docs/design/templates/toolbar-text/default-dark.svg +1 -0
  596. package/docs/design/templates/toolbar-text/default.svg +1 -0
  597. package/docs/design/templates/toolbar-text/large-dark.svg +1 -0
  598. package/docs/design/templates/toolbar-text/large.svg +1 -0
  599. package/docs/design/templates/toolbar-text/small-dark.svg +1 -0
  600. package/docs/design/templates/toolbar-text/small.svg +1 -0
  601. package/docs/design/templates/toolbar-text-dark.svg +1 -0
  602. package/docs/design/templates/toolbar-text.svg +1 -0
  603. package/docs/design/templates/toolbar.svg +1 -0
  604. package/docs/design/templates/value-table/details-dark.svg +1 -0
  605. package/docs/design/templates/value-table/details.svg +1 -0
  606. package/docs/design/templates/value-table-dark.svg +1 -0
  607. package/docs/design/templates/value-table.svg +1 -0
  608. package/docs/design/templates.md +138 -0
  609. package/docs/design-philosophy.md +48 -20
  610. package/docs/device-class.md +10 -9
  611. package/docs/document-baseline.md +38 -0
  612. package/docs/examples/application-ui-profile.json +60 -0
  613. package/docs/examples/command-palette-adapter.tsx +69 -17
  614. package/docs/examples/component-catalog-extension.json +52 -0
  615. package/docs/examples/component-composition-extension.json +80 -0
  616. package/docs/layout.md +534 -59
  617. package/docs/nav-stack.md +138 -14
  618. package/docs/recipes.md +137 -54
  619. package/docs/split-view.md +74 -6
  620. package/docs/sunken-panel.md +87 -0
  621. package/docs/surface-scaffold.md +28 -0
  622. package/docs/tab-scaffold.md +99 -10
  623. package/docs/type-contracts.md +134 -0
  624. package/docs/ui-analyzer.md +347 -0
  625. package/docs/ui-doctor.md +128 -0
  626. package/docs/ui-evaluator.md +139 -0
  627. package/docs/ux-demo.md +41 -16
  628. package/docs/webawesome-theme.md +218 -16
  629. package/docs/workbench.md +608 -12
  630. package/doctor/cli.mjs +120 -0
  631. package/doctor/config.schema.json +72 -0
  632. package/doctor/eslint-diagnostics.d.mts +24 -0
  633. package/doctor/eslint-diagnostics.mjs +24 -0
  634. package/doctor/index.d.mts +121 -0
  635. package/doctor/index.mjs +1324 -0
  636. package/doctor/report.schema.json +118 -0
  637. package/evaluator/cli.mjs +89 -0
  638. package/evaluator/index.d.mts +90 -0
  639. package/evaluator/index.mjs +1203 -0
  640. package/evaluator/report.schema.json +152 -0
  641. package/llms.txt +445 -48
  642. package/package.json +249 -37
  643. package/scripts/component-catalog-extension-validation.mjs +28 -0
  644. package/traversal-exclusions.mjs +27 -0
  645. package/ux-demo/recipes/app-shell.tsx +205 -17
  646. package/ux-demo/recipes/collapsible-sidebar.tsx +260 -0
  647. package/ux-demo/recipes/compact-toolbar.tsx +135 -14
  648. package/ux-demo/recipes/composer-form.tsx +133 -21
  649. package/ux-demo/recipes/list-detail-dialog.tsx +282 -0
  650. package/ux-demo/recipes/list-workspace-states.tsx +183 -11
  651. package/ux-demo/recipes/loaders.ts +15 -5
  652. package/ux-demo/recipes/loading-inspector.tsx +204 -0
  653. package/ux-demo/recipes/mount-recipe.ts +28 -10
  654. package/ux-demo/recipes/navigation-sidebar.tsx +139 -13
  655. package/ux-demo/recipes/navigation-stack.tsx +79 -24
  656. package/ux-demo/recipes/types.ts +23 -2
  657. package/ux-demo/recipes/workspace-header.tsx +86 -5
  658. package/dist/browser/menu-action-row.js +0 -4
  659. package/dist/browser/menu-item.js +0 -4
  660. package/dist/chunk-2RJBFNB6.js +0 -172
  661. package/dist/chunk-2RJBFNB6.js.map +0 -1
  662. package/dist/chunk-2Z5TWHKQ.js +0 -34
  663. package/dist/chunk-2Z5TWHKQ.js.map +0 -1
  664. package/dist/chunk-3YD6ZNRA.js +0 -34
  665. package/dist/chunk-3YD6ZNRA.js.map +0 -1
  666. package/dist/chunk-55DATV3A.js +0 -10
  667. package/dist/chunk-55DATV3A.js.map +0 -1
  668. package/dist/chunk-56RJXPHG.js.map +0 -1
  669. package/dist/chunk-7BR3DO2A.js.map +0 -1
  670. package/dist/chunk-7LDCTU7D.js +0 -134
  671. package/dist/chunk-7LDCTU7D.js.map +0 -1
  672. package/dist/chunk-AQNKJRFH.js +0 -79
  673. package/dist/chunk-AQNKJRFH.js.map +0 -1
  674. package/dist/chunk-B24C4A6T.js +0 -22
  675. package/dist/chunk-B24C4A6T.js.map +0 -1
  676. package/dist/chunk-DAFFDO33.js +0 -14
  677. package/dist/chunk-DAFFDO33.js.map +0 -1
  678. package/dist/chunk-H6URQGJI.js +0 -42
  679. package/dist/chunk-H6URQGJI.js.map +0 -1
  680. package/dist/chunk-I7INRJO4.js +0 -17
  681. package/dist/chunk-I7INRJO4.js.map +0 -1
  682. package/dist/chunk-KJYXOTG3.js +0 -10
  683. package/dist/chunk-KJYXOTG3.js.map +0 -1
  684. package/dist/chunk-LC3YSAZC.js +0 -39
  685. package/dist/chunk-LC3YSAZC.js.map +0 -1
  686. package/dist/chunk-M5JRI6MN.js +0 -27
  687. package/dist/chunk-M5JRI6MN.js.map +0 -1
  688. package/dist/chunk-MBR3TYNL.js +0 -14
  689. package/dist/chunk-MBR3TYNL.js.map +0 -1
  690. package/dist/chunk-MFKMHK5W.js +0 -10
  691. package/dist/chunk-MFKMHK5W.js.map +0 -1
  692. package/dist/chunk-MQIZAD4A.js +0 -227
  693. package/dist/chunk-MQIZAD4A.js.map +0 -1
  694. package/dist/chunk-N3SUXLLS.js +0 -23
  695. package/dist/chunk-N3SUXLLS.js.map +0 -1
  696. package/dist/chunk-PONXLV5U.js +0 -19
  697. package/dist/chunk-PONXLV5U.js.map +0 -1
  698. package/dist/chunk-TZNCCM5H.js +0 -20
  699. package/dist/chunk-TZNCCM5H.js.map +0 -1
  700. package/dist/chunk-W2FK7ZNY.js +0 -26
  701. package/dist/chunk-W2FK7ZNY.js.map +0 -1
  702. package/dist/chunk-WVPYVDXY.js +0 -15
  703. package/dist/chunk-WVPYVDXY.js.map +0 -1
  704. package/dist/chunk-YGN7OMLT.js.map +0 -1
  705. package/dist/chunk-YKUUZPED.js +0 -24
  706. package/dist/chunk-YKUUZPED.js.map +0 -1
  707. package/dist/menu-action-row.js +0 -5
  708. package/dist/menu-action-row.js.map +0 -1
  709. package/dist/menu-header.d.ts +0 -43
  710. package/dist/menu-header.js +0 -7
  711. package/dist/menu-header.js.map +0 -1
  712. package/dist/menu-item.d.ts +0 -33
  713. package/dist/menu-item.js +0 -5
  714. package/dist/menu-item.js.map +0 -1
  715. package/dist/panel-header.d.ts +0 -28
  716. package/dist/panel-header.js +0 -7
  717. package/dist/panel-header.js.map +0 -1
  718. package/dist/styles/menu-action-row.css +0 -160
  719. package/dist/styles/menu-header.css +0 -160
  720. package/dist/styles/menu-item.css +0 -123
  721. package/dist/styles/panel-header.css +0 -64
  722. package/ux-demo/recipes/master-detail-dialog.tsx +0 -45
  723. package/ux-demo/recipes/recipes.css +0 -355
package/docs/layout.md CHANGED
@@ -1,64 +1,288 @@
1
1
  # Pane and content layout
2
2
 
3
- Import `@kerfjs/ui/layout.css` for the shared geometry used by sidebars, main
4
- areas, inspectors, and dialogs. The vocabulary deliberately describes structure
5
- rather than location: the same pane can be placed anywhere.
3
+ Import `Pane` from `@kerfjs/ui/pane`. Browser-aware bundlers receive its CSS
4
+ automatically; other consumers can import `@kerfjs/ui/pane.css`. Import
5
+ `@kerfjs/ui/layout.css` as well when using the `.kui-content` stack and control
6
+ layout classes; place `ContentItem` children from `@kerfjs/ui/content-item`. The vocabulary deliberately describes structure rather than
7
+ location: the same pane can be placed anywhere.
6
8
 
7
9
  ## Anatomy
8
10
 
9
11
  ```tsx
10
- <aside class="kui-pane">
11
- <div class="kui-pane__toolbar"><Toolbar label="Workspace" ... /></div>
12
- <div class="kui-pane__content kui-content">
12
+ <Pane
13
+ element="aside"
14
+ label="Workspace"
15
+ contentElement="nav"
16
+ contentLabel="Workspace pages"
17
+ separators={["inline-end"]}
18
+ header={<Toolbar label="Workspace" ... />}
19
+ footer={<Toolbar label="Actions" ... />}
20
+ >
13
21
  <section>...</section>
14
22
  <section>...</section>
15
- </div>
16
- <footer class="kui-pane__footer"><Toolbar label="Actions" ... /></footer>
17
- </aside>
23
+ </Pane>
18
24
  ```
19
25
 
20
- `.kui-pane` has no padding. It reserves rows for an optional toolbar, one
21
- scrolling content area, and an optional footer. A main area or dialog often
22
- omits the footer; a navigation pane commonly uses all three. Fixed chrome stays
23
- outside `.kui-pane__content`, which is the pane's scroll owner.
26
+ `Pane` has no padding. It reserves rows for an optional vertical header, one
27
+ scrolling vertical content area, and an optional footer. A header may contain a
28
+ top toolbar followed by secondary toolbar or status rows. A main area or dialog
29
+ often omits the footer; a navigation pane commonly uses all three. Fixed chrome
30
+ stays outside `.kui-pane__content`, which is the pane's only scroll owner.
24
31
 
25
- `.kui-content` is a vertical stack with a 24px gap between major children.
26
- Sections may contain adjacent `MenuItem` rows without adding another major gap.
27
- Ordinary surface-like children use `.kui-content-item` and own their complete
28
- geometry:
32
+ Tall fixed chrome can leave a short pane no room for its content (a small
33
+ window, or text at 200%). `chromePlacement="auto"` keeps the header and footer
34
+ pinned while the pane is at least 480px (30rem, so it scales with the text
35
+ size) tall, and below that lets the whole pane scroll as one column, header,
36
+ content, and footer together, so the content keeps its natural height. The
37
+ default `fixed` always pins them.
29
38
 
30
- - 8px inline margin from the pane edge
31
- - 1px border, transparent by default
32
- - 8px internal padding and 8px internal gap
33
- - `calc(1px + remify(11px))`, or 12px, rounded corners
39
+ ### Lowered work surfaces
40
+
41
+ Set `appearance="sunken"` when the work area itself should use the lowered
42
+ surface color, including blank space below short content and the scroll
43
+ viewport. The default appearance is unchanged. The fixed Pane paints its
44
+ content scroller; with `chromePlacement="auto"`, the Pane root paints the
45
+ surface because it becomes the scroller in a short viewport. Header and footer
46
+ chrome stay on the normal surface. No second scroll container or
47
+ `SunkenPanel` wrapper is needed.
48
+ Sunken panes draw their header/footer dividers by default, even when short
49
+ content does not scroll. Pass `chromeDividers="scroll"` to restore scroll-state
50
+ dividers or `"none"` to hide them.
51
+ For custom chrome colors in auto mode, set `--kui-pane-chrome-background`
52
+ on the Pane; it defaults to `--kui-color-surface`.
53
+
54
+ ```tsx
55
+ <Pane appearance="sunken" footer={<Composer />}>
56
+ <Conversation />
57
+ </Pane>
58
+ ```
59
+
60
+ `PaneConfig.appearance` forwards through Workbench `mainPane`, panel `pane`,
61
+ and CollapsiblePanel `pane`. Workbench also applies that choice to its main or
62
+ panel region when it renders no Pane chrome. Set `appearance: "sunken"` on a
63
+ `NavStackView` or `TabScaffoldTab` when its view or scene owns scrolling.
64
+ For a `SplitView`, put a `Pane` in the list or detail region and set its
65
+ appearance; SplitView only arranges the regions and does not own their scroll.
66
+ Choose the innermost owner when composing layouts.
67
+
68
+ The color uses `--kui-sunken-panel-background`, falling back to
69
+ `--kui-color-surface-lowered`, just like `SunkenPanel`. Select one scroll owner
70
+ in a nested layout so a translucent override paints once. The public color
71
+ override may be set at a Pane or layout boundary.
72
+
73
+ Pass any combination of logical sides to `separators`: `block-start`,
74
+ `block-end`, `inline-start`, and `inline-end`. Every line is off by default and
75
+ each enabled side uses `--kui-pane-separator-width` (1px) and
76
+ `--kui-pane-separator-color` (`--kui-color-neutral-border-normal`). Logical sides keep pane
77
+ boundaries correct in both left-to-right and right-to-left layouts.
78
+
79
+ ### Scroll dividers
34
80
 
35
- Use `.kui-content-item--pill` for the 22px pill radius expressed as
36
- `calc(1px + remify(21px))`. Consumers can make a content item visible without
37
- changing its geometry by setting `--kui-content-item-border` and
38
- `--kui-content-item-background`.
81
+ Toolbars draw no divider by default. The line between pinned chrome and the
82
+ content that scrolls beside it is scroll state, not decoration: it shows only
83
+ while content is scrolled away from that edge, the way platform navigation bars
84
+ gain a hairline once content moves beneath them.
85
+
86
+ - A near edge (top, left) hides at the scroll start.
87
+ - A far edge (bottom, right) hides at the scroll end, and whenever the content
88
+ fits and nothing scrolls.
89
+
90
+ Call `wireScrollDividers` from `@kerfjs/ui/wire-scroll-dividers` once at the
91
+ application root and keep its disposer:
92
+
93
+ ```ts
94
+ import { wireScrollDividers } from "@kerfjs/ui/wire-scroll-dividers";
95
+
96
+ const stop = wireScrollDividers(appRoot);
97
+ ```
98
+
99
+ It covers, by structure, every `Pane` below the root (the header's bottom line
100
+ and the footer's top line, whatever the chrome holds — a `Toolbar`, a
101
+ `mainHeader` list, a `TabBar`) and every `TabBar` strip (a line on each side
102
+ whose tabs are scrolled out of view). That includes the panes a `Workbench`,
103
+ `CollapsiblePanel`, or `Catalog` renders; `wireCatalog` installs it for its
104
+ own root. It also covers every `NavStack` (the top chrome's bottom line and the
105
+ bottom toolbar's top line, around the active view) and every `TabScaffold`
106
+ (the bar's top line, over the active scene). The layout keys on whichever
107
+ element actually scrolls there: the view or scene itself, or, through a sole
108
+ child with no chrome of its own on that edge, a `Pane`'s content or a nested
109
+ `NavStack`'s active view. A sole `Pane` fills its view or scene, so its content
110
+ scrolls under its pinned header; with a header it draws the line under that
111
+ header itself, so the stack's chrome never doubles it. It follows re-renders: panes that appear later are paired, and an
112
+ attribute a morph drops returns before paint.
113
+
114
+ Multiple calls in one document share one attribute writer, including calls on
115
+ overlapping roots. Each call contributes its own root and optional named
116
+ targets; its disposer removes only that registration. When the last disposer
117
+ runs, the writer removes the attributes it owns. An app that calls `wireCatalog`
118
+ for a root already has scroll dividers there and does not need another call.
119
+
120
+ The wiring only reports state; every component draws its own line. It writes
121
+ `data-scroll-overflow` (the edges with content hidden beyond them, in canonical
122
+ `t`/`r`/`b`/`l` order) on each scroller and `data-scroll-divider` (the sides to
123
+ draw) on each piece of chrome, and the Pane, NavStack, TabScaffold, TabBar,
124
+ Toolbar, and List stylesheets draw from those. The line is an inset shadow or a pseudo-element
125
+ inside the component, so no state ever moves the chrome, the content, or a tab.
126
+ Never write a border onto a component to show one.
127
+
128
+ Configure a pane with `chromeDividers`: `scroll` (the plain-pane default) follows
129
+ the scroll state and draws nothing until the wiring runs; `always` (the sunken
130
+ pane default) keeps both lines; `none` drops them. Explicit values override
131
+ either default. Layouts forward it through `PaneConfig`
132
+ (`mainPane.chromeDividers`, a panel's `pane.chromeDividers`). A `NavStack` and a
133
+ `TabScaffold` take the same `chromeDividers` for their own chrome (the stack's
134
+ top chrome and bottom toolbar, the scaffold's bar), and a `SplitView` forwards
135
+ it to its compact stack through `compactStack`.
136
+
137
+ For an app-owned arrangement outside a `Pane`, name the scroller and its chrome
138
+ by `id` in `targets`; a `Toolbar` or `List` named as chrome draws the divider
139
+ on its side facing the scroller:
140
+
141
+ ```ts
142
+ wireScrollDividers(appRoot, {
143
+ targets: [{ scroller: "results", top: "results-toolbar", bottom: "status" }],
144
+ });
145
+ ```
146
+
147
+ A CSS-only version is not used: scroll-driven animations are not available in
148
+ Firefox, scroll-state container queries only in Chromium, and neither lets
149
+ the pinned chrome — a sibling of the scroller — read the scroller's state on
150
+ its own. One wiring keeps the behavior identical in every engine.
151
+
152
+ A pane is safe-area aware. Its background and separators paint through a
153
+ device's unsafe areas while its header, content, and footer pad for each side
154
+ the pane still reaches; the content's block insets are scroll padding, so its
155
+ first and last items can always be scrolled clear. Layouts clear the sides a
156
+ pane does not reach. In an app-owned arrangement, pass `safeAreaEdges` (the
157
+ same logical sides as `separators`; all four by default, `[]` to opt out). See
158
+ [Choosing an app layout › Safe areas](app-layouts.md#safe-areas).
159
+
160
+ `.kui-content` is a vertical stack with a 24px gap between major children.
161
+ Sections may contain adjacent `ListItem` rows without adding another major gap.
162
+ Ordinary surface-like children are `ContentItem`s and own their complete
163
+ geometry (see [Content items](#content-items)).
164
+
165
+ Nested selection and hover highlights stay concentric and match their owning
166
+ control's shape. Their inner radius is the outer radius minus the full inset,
167
+ expressed by the shared `--kui-layout-highlight-inset` token (2px by default).
168
+ For example, `SegmentedControl` and `ToolbarControlGroup` place each highlight
169
+ behind a 1px control border and 1px control padding, so a rounded control's 12px
170
+ outer radius produces a 10px highlight radius; a 22px pill produces 20px.
39
171
 
40
172
  A visible parent surface does not make every child another visible card. The
41
- composer recipe keeps its form as the single surface, uses `PanelHeader` for
173
+ composer recipe keeps its form as the single surface, uses a heading `Toolbar` for
42
174
  its task hierarchy, and places field and action control edges on the shared 8px
43
175
  inline gutter instead of nesting them inside another padded content item. A
44
176
  conditional `StateBanner` remains visibly distinct because it communicates
45
177
  semantic status.
46
178
 
179
+ ## Content items
180
+
181
+ Render an ordinary surface-like `.kui-content` child with `ContentItem` from
182
+ `@kerfjs/ui/content-item` (browser-aware bundlers receive its CSS automatically;
183
+ `@kerfjs/ui/layout.css` and `@kerfjs/ui/content-item.css` both deliver it). It
184
+ owns its complete geometry:
185
+
186
+ - 8px inline margin from the pane edge
187
+ - 1px border, transparent by default
188
+ - 8px internal padding
189
+ - `calc(1px + remify(11px))`, or 12px, rounded corners
190
+
191
+ ```tsx
192
+ import { ContentItem } from "@kerfjs/ui/content-item";
193
+
194
+ <Pane label="Inspector">
195
+ <ContentItem>{details}</ContentItem>
196
+ <ContentItem frame="framed">{pendingChanges}</ContentItem>
197
+ <ContentItem flush>{markdownPreview}</ContentItem>
198
+ <ContentItem shape="pill">{summary}</ContentItem>
199
+ </Pane>;
200
+ ```
201
+
202
+ `frame="framed"` paints the standard neutral border in the 1px the item always
203
+ reserves, so framed and unframed items share the same geometry. Frame an item
204
+ only when it marks a real distinction and must read as visibly bounded; do not
205
+ frame it to make it "look contained". `shape="pill"` selects the 22px pill
206
+ radius expressed as `calc(1px + remify(21px))`. There is deliberately no filled
207
+ variant: a lowered, filled surface is `SunkenPanel`, and bare text that only
208
+ needs to align with neighboring items is `ListInsetText`. Safe `data-*`
209
+ metadata goes in `rootAttributes`. Pass `ariaLabel` only for a distinct named
210
+ region (`role="region"`), and `focusTarget` to make the item a programmatic
211
+ focus target (`tabindex="-1"`), for example a NavStack view's `data-nav-focus`
212
+ target. `flush` removes block padding and both block borders while retaining
213
+ the inline margin, padding, and border. Use it for content such as a markdown
214
+ preview that must reach the item's top and bottom edges. `title` passes through
215
+ to the root element as a native tooltip.
216
+
217
+ For a selectable card, set `interactive`, a delegated `action`, and an optional
218
+ `itemId`. Wire `wireContentItems(root)` once on the containing app root; it
219
+ activates focused cards with Enter or Space and forwards the resulting click to
220
+ the app's ordinary `data-action` handler. `selectionMode="toggle"` maps
221
+ `selected` to a button's `aria-pressed`; `selectionMode="single"` maps it to an
222
+ option's `aria-selected` and belongs in an app-owned `role="listbox"` container.
223
+ For a card with nested controls and multi-selection, place
224
+ `selectionMode="multiple"` cards inside a `List selectionMode="multiple"` with
225
+ `ariaLabel`. The List is a labeled `grid` with `aria-multiselectable`, each card
226
+ is a focusable `row` with `aria-selected`, and its content is a `gridcell` that
227
+ may contain native controls. The app owns the selection set, including
228
+ Shift/Cmd extension; the card renders the supplied `selected` state and
229
+ dispatches its `action`. Give nested controls their own actions.
230
+ When the app delegates clicks by `data-action`, guard the card's selection
231
+ handler with `isContentItemActivation(event, card)` from
232
+ `@kerfjs/ui/wire-content-items`; it ignores clicks from nested controls that
233
+ have no separate action, including a `PopupMenu` trigger.
234
+ `wireContentItems` moves focus among enabled rows with Up/Down and Home/End
235
+ when a row has focus; arrows from nested controls retain their native behavior.
236
+ An interactive card is a Tab stop, and `disabled` removes its action and Tab
237
+ stop while exposing `aria-disabled`. Hover uses the normal neutral fill so it
238
+ remains visible on a lowered surface; hover, pressed, focus, and selected paints
239
+ do not change geometry. A single-action card has no interactive descendants.
240
+ For a rich card without card selection, render a static `ContentItem` with
241
+ sibling buttons inside it. Each button then has its own focus stop and action.
242
+ `ListActionRow` already packages this pattern for a simple two-action row.
243
+ `rootAttributes` still accepts safe app `data-*` metadata, while the card owns
244
+ its interaction data.
245
+
246
+ The rendered classes — `.kui-content-item`, `.kui-content-item--framed`,
247
+ `.kui-content-item--pill`, and `.kui-content-item--flush` — stay public for the
248
+ rare element that must carry the
249
+ geometry itself (for example a `<ul>` list or a `Text` paragraph in an
250
+ application-owned adapter). Prefer `ContentItem` everywhere else so the framing
251
+ choice is typed. A plain `<div class="kui-content-item">` is exactly what
252
+ `ContentItem` renders, so the catalog records that element
253
+ (`rootElement: "div"`): `eslint-plugin-kerfjs`'s `ui-public-boundaries` reports
254
+ it in application code as `KUI-L103` ("render `ContentItem`"), and
255
+ `npm run check:guidance` derives the same boundary from the catalog to reject it
256
+ in the package's examples, browser fixtures, and UX catalog.
257
+
258
+ These classes, the layout utilities (`.kui-content`, `.kui-scroll-owner`,
259
+ `.kui-control-cluster`, `.kui-inline-metadata`), and `.kui-app-root` are the
260
+ catalog's `boundaries.placeableClasses`: the only public classes an application
261
+ writes onto its own elements. Every other public class is a component's
262
+ rendered anatomy — render `Pane` rather than writing `.kui-pane` /
263
+ `.kui-pane__content` onto an `<aside>` — and `eslint-plugin-kerfjs`'s
264
+ `ui-public-boundaries` reports it on an application-owned element as
265
+ `KUI-L103`. Selecting those classes in CSS to place your own content in a
266
+ component's context stays allowed (see `KUI-L019`).
267
+
47
268
  ## Public roles and tokens
48
269
 
49
- | Need | Class | Token / default |
50
- | --- | --- | --- |
51
- | Unpadded toolbar/content/footer structure | `.kui-pane` | — |
52
- | Scrolling pane content | `.kui-pane__content` | — |
53
- | Major vertical rhythm | `.kui-content` | `--kui-layout-content-gap: 24px` |
54
- | Self-contained child geometry | `.kui-content-item` | 8px margin + 1px border + 8px padding |
55
- | Pill child | `.kui-content-item--pill` | `--kui-layout-pill-radius: 22px` |
56
- | Related controls | `.kui-control-cluster` | `--kui-layout-control-gap: 8px` |
57
- | Inline metadata | `.kui-inline-metadata` | `--kui-layout-metadata-gap: 4px` |
58
- | Explicit scroll owner outside a pane | `.kui-scroll-owner` | `overflow: auto` |
59
-
60
- The component layer applies the same contract to `Toolbar`, `MenuHeader`,
61
- `MenuItem`, `PanelHeader`, `StateBanner`, `ValueTable`,
270
+ | Need | Class | Token / default |
271
+ | ---------------------------------------- | ---------------------------- | ------------------------------------------------------------------ |
272
+ | Unpadded header/content/footer structure | `Pane`, `.kui-pane` | — |
273
+ | Scrolling pane content | `.kui-pane__content` | — |
274
+ | Optional logical-edge separators | `Pane.separators` | `--kui-pane-separator-width: 1px` |
275
+ | Safe-area sides a pane may pad | `Pane.safeAreaEdges` | `--kui-safe-area-*: env(safe-area-inset-*)`, routed by each layout |
276
+ | Major vertical rhythm | `.kui-content` | `--kui-layout-content-gap: 24px` |
277
+ | Self-contained child geometry | `ContentItem` | 8px margin + 1px border + 8px padding |
278
+ | Pill child | `ContentItem shape="pill"` | `--kui-layout-pill-radius: 22px` |
279
+ | Visibly framed child | `ContentItem frame="framed"` | neutral 1px border, same geometry |
280
+ | Related controls | `.kui-control-cluster` | `--kui-layout-control-gap: 8px` |
281
+ | Inline metadata | `.kui-inline-metadata` | `--kui-layout-metadata-gap: 4px` |
282
+ | Explicit scroll owner outside a pane | `.kui-scroll-owner` | `overflow: auto` |
283
+
284
+ The component layer applies the same contract to `Toolbar`, `ListHeader`,
285
+ `ListItem`, `Toolbar`, `StateBanner`, `ValueTable`,
62
286
  `ValueTableRow`, tabs, and form controls. A value-table row separator starts at
63
287
  the row's 8px content inset, or at 40px when the row contains its 24px leading
64
288
  icon and 8px gap, and always ends 8px from the right edge. Each value-table row
@@ -66,13 +290,25 @@ also keeps 8px of root-scaled block padding independently of its semantic inline
66
290
  inset. Most interactive rows and toolbar groups are 44px tall.
67
291
  Toolbar groups reserve a real 1px outer border around a 42px inner area, even
68
292
  when their border and background are transparent.
69
- `PanelHeader` is a plain top `Toolbar` used as a panel, dialog, or page heading
70
- and overrides no Toolbar styles. The leading zone holds the optional icon (a
71
- normal bordered `ToolbarControlGroup` given a brand fill with a matching border,
72
- a 22px glyph) and the title as extra-large `ToolbarText`; the app's trailing
73
- controls go straight into the trailing zone, and the icon group is omitted when
74
- no icon is passed. The optional subtitle is a separate row below the toolbar, its
75
- text left-aligned with the title text.
293
+ A `Toolbar` lays its zones out against one 44px control band at its top: an
294
+ item no taller than the band is centered in it by its own size, and a taller
295
+ item (a wrapped title, a second trailing row) starts at the band's top and
296
+ grows down, so it never moves the other controls. A wrapped `ToolbarText`
297
+ centers its first line in the band.
298
+ The leading zone clips a shrinking title but reserves 4px of paint overflow
299
+ for the focus outline of a control at its edge. Focus rings in all three zones
300
+ remain visible at narrow and wide widths.
301
+ Trailing icon actions share one axis: a toolbar control centers its glyph in
302
+ that 44px slot at the 8px inline margin, and a `ListHeader` action centers its
303
+ fitted 36px square in a slot of the same size (a transparent hit layer extends
304
+ its pointer target to fill that 44px slot), so a Pane header's trailing toolbar
305
+ action and the `ListHeader` action beneath it line up (30px from the pane edge
306
+ at the default scale).
307
+ Panel, dialog, and page headings are plain `Toolbar` compositions. The leading
308
+ zone holds an optional icon `ToolbarControlGroup` and a direct extra-large
309
+ `ToolbarText`; actions belong in a trailing group. Omit empty groups. Supporting
310
+ copy is app-owned content below the toolbar and aligns with the intended content
311
+ edge.
76
312
 
77
313
  ## Spacing scale
78
314
 
@@ -81,18 +317,257 @@ expressing exactly one relationship — pick the step by **how connected two
81
317
  elements are**, not by eye. Every scalable value is `remify`-authored against the
82
318
  fixed 16px baseline, so it delivers as `rem`.
83
319
 
84
- | Value | Token | Relationship — when to use |
85
- | --- | --- | --- |
86
- | 0px | `--kui-space-none` | No separation. The elements read as a single unit (a control and its own affordance, adjacent `MenuItem` rows). |
87
- | 4px | `--kui-space-2xs` | Very minor. Still one connected cluster, but readability or aesthetics demand a hair of air (inline metadata, an icon beside its label). |
88
- | 8px | `--kui-space-xs` | Standard. Between elements **within a group** — the content-item padding/gutter, gaps between toolbar controls in a group. |
89
- | 16px | `--kui-space-m` | Minor. Between **homogeneous groups** — two lists, two sibling sections of the same kind. |
90
- | 24px | `--kui-space-l` | Major. Between **heterogeneous groups** — the `.kui-content` rhythm between major, differing regions. |
320
+ | Value | Token | Relationship — when to use |
321
+ | ----- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
322
+ | 0px | `--kui-space-none` | No separation. The elements read as a single unit (a control and its own affordance, adjacent `ListItem` rows). |
323
+ | 4px | `--kui-space-2xs` | Very minor. Still one connected cluster, but readability or aesthetics demand a hair of air (inline metadata, an icon beside its label). |
324
+ | 8px | `--kui-space-xs` | Standard. Between elements **within a group** — the content-item padding/gutter, gaps between toolbar controls in a group. |
325
+ | 16px | `--kui-space-m` | Minor. Between **homogeneous groups** — two lists, two sibling sections of the same kind. |
326
+ | 24px | `--kui-space-l` | Major. Between **heterogeneous groups** — the `.kui-content` rhythm between major, differing regions. |
91
327
 
92
- The two relationships that get confused most are 8px vs 24px: 8px is *inside* a
93
- group, 24px is *between* major, differing regions. 16px sits between them for
328
+ The two relationships that get confused most are 8px vs 24px: 8px is _inside_ a
329
+ group, 24px is _between_ major, differing regions. 16px sits between them for
94
330
  same-kind groups.
95
331
 
332
+ For `Row.gap`, `Grid.gap`, and `List.gap`, pass these token names directly (`gap="xs"`, `gap="m"`) or use
333
+ `space('xs')` from `@kerfjs/ui/css-values` when composing a value in JavaScript.
334
+ Use `rem`, `em`, `px`, `pct`, `lengthVar`, and `calc(plus(...))` only when a
335
+ named spacing relationship does not express the requirement; do not pass raw
336
+ CSS strings.
337
+
338
+ ## Text
339
+
340
+ `FieldLabel` from `@kerfjs/ui/text` gives a read-only or click-to-edit field
341
+ preview the same visible heading as a themed Web Awesome form control. Put it
342
+ in `ListInsetControl sides="trl"` above the preview so its text starts at the
343
+ same 17px content column as a `ContentItem` value. Unlike a native `<label>`, it
344
+ is a plain element: give it an `id` and name the preview's group with
345
+ `aria-labelledby`. Keep the app's preview/edit switching and hint copy beside
346
+ the preview; use the live control's own `label` when editing.
347
+
348
+ ```tsx
349
+ import { ContentItem } from "@kerfjs/ui/content-item";
350
+ import { ListInsetControl } from "@kerfjs/ui/list-inset-control";
351
+ import { FieldLabel } from "@kerfjs/ui/text";
352
+
353
+ <div role="group" aria-labelledby="needed-by-label">
354
+ <ListInsetControl sides="trl">
355
+ <FieldLabel id="needed-by-label">Needed by</FieldLabel>
356
+ </ListInsetControl>
357
+ <ContentItem>October 16, 2026</ContentItem>
358
+ </div>;
359
+ ```
360
+
361
+ Use `Text` from `@kerfjs/ui/text` for ordinary semantic headings, paragraphs,
362
+ and inline secondary text. It renders a native `p` by default; set `variant` to
363
+ `h1`–`h6` when the document outline calls for a heading, or `span` for inline
364
+ copy inside a row, label, or table cell. Ordinary global, `data-*`, and `aria-*`
365
+ attributes pass through. Block variants reset their native margin, own a 1px
366
+ transparent border, and supply the standard 8px item padding. The `span`
367
+ variant owns no margin, border, or padding. Choose heading levels from the
368
+ document outline, not for visual size. Toolbar identity and page-heading
369
+ compositions continue to use `ToolbarText`.
370
+
371
+ `Text` is also the answer for a normal-color subsection title. `ToolbarText`
372
+ below `xlarge` (`large`, `default`, `small`) is deliberately quiet: it labels a
373
+ toolbar's identity — a pane name or a status — and must not compete with the
374
+ content and controls around it, so it has no tone option. A subsection title is
375
+ document content, not toolbar identity: use `Text` with the `h2`–`h6` variant
376
+ the outline calls for (inside a `List` with `controlInsets`, its text lines up
377
+ with content items). Use `ListHeader` when the section is a list or menu group
378
+ that needs a count, badge, action, or disclosure, and keep extra-large
379
+ `ToolbarText` for the panel, dialog, or page title. A narrow peripheral rail or
380
+ drawer is the exception that proves the rule: beside a work area that already
381
+ carries the extra-large title, its header names the pane with the default size,
382
+ because extra-large would truncate there ("Inspector" becomes "Ins…" in a 160px
383
+ rail) and pane identity should stay quiet.
384
+
385
+ Presentation is independent of the native element: use `tone="quiet"` for
386
+ supporting copy, `tone="danger"` for error or validation copy, `size="compact"`
387
+ for compact metadata, `size="large"` for prominent copy, `size="xlarge"` for
388
+ display copy, and `font="monospace"` for code or identifiers (the
389
+ `--kui-font-mono` stack, which Kerf owns even with Web Awesome loaded). These
390
+ finite props compose with each other and with every semantic `variant`; omit
391
+ them to inherit the surrounding color, size, and font.
392
+
393
+ Control long copy with `wrap`: `normal` (default) restores ordinary wrapping,
394
+ `anywhere` breaks long unbroken strings, `nowrap` holds one line, and
395
+ `truncate` holds one line with an ellipsis. `truncate` sets `min-width: 0`, so
396
+ Text can shrink beside a fixed-size sibling in a `Row`; the sibling keeps its
397
+ width. On `normal` or `anywhere`, set a positive integer `maxLines` to clamp
398
+ wrapped text with an ellipsis. Omit `maxLines` for unlimited lines. The cap is
399
+ incompatible with `nowrap` and `truncate`.
400
+
401
+ ```tsx
402
+ import { Text } from "@kerfjs/ui/text";
403
+
404
+ <Text variant="h2" id="details-title">Details</Text>;
405
+ <Text variant="h3">Notifications</Text>; // normal-color subsection title
406
+ <Text aria-describedby="details-title">Supporting copy</Text>;
407
+ <Text tone="quiet" size="compact">Updated yesterday</Text>;
408
+ <Text size="large">A prominent summary</Text>;
409
+ <Text variant="h2" size="xlarge">A display-sized section title</Text>;
410
+ <strong>Inbox<Text variant="span" tone="quiet" size="compact"> · 3 msg</Text></strong>;
411
+ <Text tone="danger" font="monospace">ERR_INVALID_ID</Text>;
412
+ <Text wrap="anywhere">A-very-long-unbroken-identifier</Text>;
413
+ <Text wrap="truncate" variant="span">Long vendor name</Text>;
414
+ <Text wrap="normal" maxLines={2}>A long summary capped at two lines.</Text>;
415
+ ```
416
+
417
+ ## Spacer
418
+
419
+ Use `Spacer` from `@kerfjs/ui/spacer` for one intentional empty dimension that
420
+ is not the repeated relationship owned by a parent's `gap`. Its `width` and
421
+ `height` accept the same finite `UiSpaceName` vocabulary or a complete typed
422
+ `CssLength`. Fixed spacers use `flex: 0 0 auto`, so flex layouts do not compress
423
+ the requested dimension. Pass `flex` to use `1 1 auto` and consume the remaining
424
+ space along a `Row`, `List`, or other flex parent's main axis.
425
+
426
+ ```tsx
427
+ import { Row } from "@kerfjs/ui/row";
428
+ import { Spacer } from "@kerfjs/ui/spacer";
429
+
430
+ <Row gap="none">
431
+ <button>Back</button>
432
+ <Spacer flex />
433
+ <button>Save</button>
434
+ </Row>;
435
+ ```
436
+
437
+ Spacer is always decorative (`aria-hidden="true"`), accepts no children, and
438
+ uses physical width and height. Prefer `Row.gap` or `List.gap` for uniform
439
+ sibling rhythm, and never use Spacer to cancel or duplicate component-owned
440
+ insets.
441
+
442
+ ## Grid
443
+
444
+ Use `Grid` from `@kerfjs/ui/grid` when equal-width columns must share the
445
+ available width. Set a fixed positive `columns` count or a typed
446
+ `minColumnWidth` for automatic container-width collapse. Fixed tracks use
447
+ `minmax(0, 1fr)`; responsive tracks use `auto-fit` and cap their minimum at
448
+ 100% so a narrow container keeps one column without overflow. Grid defaults
449
+ to the `xs` gap and accepts the same finite spacing names, complete typed
450
+ `CssLength` values, and typed flex-participation contract as Row.
451
+
452
+ ```tsx
453
+ import { Grid } from "@kerfjs/ui/grid";
454
+ import { px } from "@kerfjs/ui/css-values";
455
+
456
+ <Grid columns={2} gap="m">
457
+ <label>Quantity <input /></label>
458
+ <label>Unit <input /></label>
459
+ </Grid>;
460
+
461
+ <Grid minColumnWidth={px(376)} gap="m">
462
+ <label>Provider <input /></label>
463
+ <label>Endpoint <input /></label>
464
+ </Grid>;
465
+
466
+ <Grid minColumnWidth={px(160)} autoFill gap="m">
467
+ <DocumentTile />
468
+ </Grid>;
469
+ ```
470
+
471
+ `columns` must be a positive safe integer; invalid counts throw instead of
472
+ silently producing invalid CSS. Import `px` from `@kerfjs/ui/css-values` for a
473
+ pixel minimum. `columns` and `minColumnWidth` are mutually exclusive. In the
474
+ responsive mode, the container width decides how many equal tracks fit; constrain
475
+ the Grid's outer width when the form should have a maximum count.
476
+ `autoFill` keeps the unoccupied responsive tracks so one or two tiles retain
477
+ their shared track width rather than expanding across an otherwise empty row.
478
+ It requires `minColumnWidth`; the default `auto-fit` keeps the existing form
479
+ behavior. When Grid is a direct child of a flex-owned `ListInsetControl`, pass
480
+ `flex` so the Grid takes the available row width instead of shrink-wrapping.
481
+ Grid is layout-only by default and adds no ARIA grid role. With
482
+ `selectionMode="multiple"` and a required `ariaLabel`, it supplies a labeled
483
+ multi-select grid for `ContentItem selectionMode="multiple"` tiles. Their
484
+ row/gridcell structure can contain independent controls, while
485
+ `wireContentItems` follows the rendered tile positions with arrow keys.
486
+ The application owns child
487
+ semantics.
488
+ Use application-owned CSS grid for intrinsic, asymmetric, spanning, or masonry
489
+ tracks, and use `ResizableRegion` when people must adjust a boundary.
490
+
491
+ ## Row and List alignment
492
+
493
+ Use `Row` for a horizontal flex layout and `List` for a vertical one. `Row`
494
+ defaults to `hAlign="left"`, `vAlign="full"`, `gap="xs"`, and no wrapping;
495
+ `List` retains its existing full-width, top-aligned defaults and zero gap.
496
+ Both components accept the same physical-axis vocabulary, with baseline
497
+ alignment additionally available on the horizontal `Row` cross axis:
498
+
499
+ | Axis | Values and aliases | Flex behavior |
500
+ | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
501
+ | Horizontal | `left` / `l` / `flex-start`; `center` / `c` / `space-around`; `right` / `r` / `flex-end`; `full` / `f` / `space-between` | Distributes a Row's children; aligns a List's children across its width. |
502
+ | Vertical | `top` / `t` / `flex-start`; `middle` / `m` / `c` / `space-around`; `bottom` / `b` / `flex-end`; `full` / `f` / `space-between`; Row-only `baseline` | Aligns a Row's children across its height; distributes a List's children. |
503
+
504
+ Cross-axis `space-around` and `space-between` are not valid `align-items`
505
+ values. Kerf therefore maps `middle` to centered items and `full` to stretched
506
+ items, while applying the requested distribution to `align-content` when a
507
+ Row wraps. Prefer the descriptive values in application code; the short and
508
+ CSS-shaped aliases are provided for compact or migrated call sites.
509
+ `baseline` is Row-only because CSS baseline alignment applies to a flex
510
+ container's cross axis; a vertical List's `vAlign` controls main-axis
511
+ distribution through `justify-content`, which has no baseline value.
512
+
513
+ `Row.flex` and `List.flex` share one typed participation contract. Omit the prop
514
+ for the CSS initial value, pass `true` for `1 1 auto`, select the finite
515
+ `"none"`, `"auto"`, or `"initial"` keyword, or use
516
+ `flex(grow, shrink, basis)` from `@kerfjs/ui/css-values` for a complete branded
517
+ shorthand. A `CssLength` is not a flex shorthand, and arbitrary strings are
518
+ rejected by the type contract.
519
+
520
+ ### Filling a fixed-height parent
521
+
522
+ `flex` sizes a Row, List, or Grid inside a flex layout. When one of them is the
523
+ layout **root** of a parent with a definite height (an app mount container
524
+ with the `.kui-app-root` height chain, a dialog body, or a fixed-height catalog
525
+ frame), pass `fill` instead: the root takes the parent's full height
526
+ (`height: 100%`), so its `flex` children can grow into it. Use `fill` only on
527
+ that sole layout root; a sibling inside a flex layout keeps using `flex`.
528
+
529
+ Put route, test, or recipe metadata on the same root with `rootAttributes`,
530
+ which accepts safe `data-*` pairs and keeps each component's structural
531
+ attributes (`data-component`, `data-flex`, `data-fill`, alignment, inset, and
532
+ column markers) protected:
533
+
534
+ ```tsx
535
+ <Row gap="none" fill rootAttributes={{ "data-recipe": "sidebar" }}>
536
+ <CollapsiblePanel id="rail" side="left" collapsed={railCollapsed.value}>
537
+ …
538
+ </CollapsiblePanel>
539
+ <List flex>…</List>
540
+ </Row>
541
+ ```
542
+
543
+ Do not wrap a layout in a frame `Pane` just to get a definite height or a root
544
+ attribute: the pane's content slot becomes a scroll owner that never scrolls,
545
+ and its safe-area padding keeps an edge-docked rail or drawer from painting
546
+ through the unsafe area. A `Pane` is for a real column with a header, one
547
+ scrolling content region, or a footer.
548
+
549
+ Both components also accept `textInsets` and `controlInsets` using the shared
550
+ physical `Sides` union. Values follow canonical top/right/bottom/left order
551
+ (`t`, `rb`, `tbl`, `trbl`, and so on). A selected control side adds 8px of
552
+ padding. A selected text side adds the complete content-item alignment inset —
553
+ 8px outer margin + 1px border + 8px inner padding, represented as 17px of
554
+ container padding. When both props select the same side, the text inset wins.
555
+ Each nested `Row` or `List` resolves its own four inset sides; unselected sides
556
+ reset to zero instead of inheriting a same-type parent's inset selection.
557
+ The same holds for `gap` and `flex` on a nested `List`, `Row`, or `Grid`: an
558
+ omitted prop falls back to that component's own default (no gap for `List`,
559
+ `xs` for `Row` and `Grid`; the CSS initial `flex`) rather than the enclosing
560
+ instance's value.
561
+
562
+ `ListInsetText` and `ListInsetControl` use the same `sides` vocabulary and
563
+ default to `trbl`. The text wrapper applies its complete 8/1/8 geometry only on
564
+ selected sides; the control wrapper applies its 8px outer margin only on
565
+ selected sides. Every direct child of `ListInsetControl` grows to fill the row
566
+ (a `Select`, a `wa-input`, or a `wa-button` spans the full inset width), and
567
+ several children share the row with an 8px gap; stack controls vertically with
568
+ a `List` using `controlInsets` instead. Pass `sides="rl"` for tight text that
569
+ keeps the horizontal inset without adding vertical box space.
570
+
96
571
  `--kui-space-s` (12px) and `--kui-space-xl` (32px) exist but are **off the
97
572
  canonical rhythm** — reach for them only as a deliberate exception, never as a
98
573
  default step. Prefer the five canonical tokens so spacing stays legible and
@@ -109,14 +584,14 @@ consistent across every surface.
109
584
  4. Keep one scrolling content owner per pane. Toolbar and footer siblings stay
110
585
  fixed while the content scrolls.
111
586
  5. A split item keeps dormant and interactive regions separate. For example,
112
- `MenuHeader` renders its title/count-or-badge cluster separately from its optional
587
+ `ListHeader` renders its title/count-or-badge cluster separately from its optional
113
588
  logical-end 44px action. The header fills the available inline width and its
114
589
  action glyph defaults to 18px; disclosure mode makes the title cluster itself
115
590
  the button and supplies the production `DisclosureArrow` unless `actionIcon`
116
591
  replaces it.
117
- `MenuActionRow` uses a noninteractive row root around sibling 44px primary
118
- and trailing buttons. `MenuItem.trailing` remains dormant content.
119
- In multiline `MenuItem` and `MenuActionRow` rows, the leading icon stays
592
+ `ListActionRow` uses a noninteractive row root around sibling 44px primary
593
+ and trailing buttons. `ListItem.trailing` remains dormant content.
594
+ In multiline `ListItem` and `ListActionRow` rows, the leading icon stays
120
595
  centered on the label's first line rather than the full wrapped label.
121
596
  6. Reading width, column placement, and responsive relocation remain application
122
597
  decisions. The shared classes define local geometry, not the whole shell.