@kerfjs/ui 5.0.0-beta.55 → 5.0.0-beta.57

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 (418) hide show
  1. package/README.md +74 -41
  2. package/ai/application-ui-diagnostic-ids-v1.json +9 -1
  3. package/ai/application-ui-profile-sync.cjs +1 -1
  4. package/ai/application-ui-profile.defaults.json +63 -8
  5. package/ai/application-ui-profile.mjs +1 -1
  6. package/ai/compile-time-contracts-v1.json +2 -2
  7. package/ai/component-catalog.json +407 -80
  8. package/ai/component-catalog.schema.json +2 -0
  9. package/ai/component-class-owners.cjs +83 -0
  10. package/ai/component-composition-extension.d.ts +7 -0
  11. package/ai/component-composition-extension.schema.json +7 -0
  12. package/ai/{component-catalog-v2-overrides.json → component-composition-rules.json} +2 -1
  13. package/ai/{component-catalog-v2.d.ts → component-composition.d.ts} +9 -5
  14. package/ai/{component-catalog-v2.json → component-composition.json} +302 -61
  15. package/ai/{component-catalog-v2.schema.json → component-composition.schema.json} +21 -5
  16. package/ai/components/README.md +170 -0
  17. package/ai/components/application-tabs.md +65 -0
  18. package/ai/components/badge.md +72 -0
  19. package/ai/components/collapsible-panel.md +102 -0
  20. package/ai/components/content-item.md +90 -0
  21. package/ai/components/disclosure-arrow.md +77 -0
  22. package/ai/components/document-baseline.md +75 -0
  23. package/ai/components/empty-state.md +80 -0
  24. package/ai/components/feedback.md +71 -0
  25. package/ai/components/floating-toolbar.md +80 -0
  26. package/ai/components/foundation.md +65 -0
  27. package/ai/components/grid.md +93 -0
  28. package/ai/components/headers.md +63 -0
  29. package/ai/components/layout.md +75 -0
  30. package/ai/components/list-action-row.md +91 -0
  31. package/ai/components/list-header.md +89 -0
  32. package/ai/components/list-inset-control.md +74 -0
  33. package/ai/components/list-inset-text.md +72 -0
  34. package/ai/components/list-item.md +88 -0
  35. package/ai/components/list.md +103 -0
  36. package/ai/components/loading-spinner.md +72 -0
  37. package/ai/components/lucide-icon.md +66 -0
  38. package/ai/components/nav-stack.md +103 -0
  39. package/ai/components/pane.md +100 -0
  40. package/ai/components/popup-menu.md +82 -0
  41. package/ai/components/recipe-app-shell.md +57 -0
  42. package/ai/components/recipe-collapsible-sidebar.md +57 -0
  43. package/ai/components/recipe-compact-toolbar.md +57 -0
  44. package/ai/components/recipe-composer-form.md +57 -0
  45. package/ai/components/recipe-list-detail-dialog.md +57 -0
  46. package/ai/components/recipe-list-workspace-states.md +57 -0
  47. package/ai/components/recipe-loading-inspector.md +57 -0
  48. package/ai/components/recipe-navigation-sidebar.md +57 -0
  49. package/ai/components/recipe-navigation-stack.md +57 -0
  50. package/ai/components/recipe-workspace-header.md +57 -0
  51. package/ai/components/resize.md +101 -0
  52. package/ai/components/row.md +96 -0
  53. package/ai/components/segmented-control.md +82 -0
  54. package/ai/components/select.md +107 -0
  55. package/ai/components/skeleton.md +84 -0
  56. package/ai/components/spacer.md +86 -0
  57. package/ai/components/split-view.md +102 -0
  58. package/ai/components/state-banner.md +92 -0
  59. package/ai/components/sunken-panel.md +79 -0
  60. package/ai/components/surface-scaffold.md +78 -0
  61. package/ai/components/tab-bar.md +112 -0
  62. package/ai/components/tab-scaffold.md +94 -0
  63. package/ai/components/tabs.md +90 -0
  64. package/ai/components/text.md +82 -0
  65. package/ai/components/token-search-field.md +101 -0
  66. package/ai/components/toolbar-control-group.md +100 -0
  67. package/ai/components/toolbar-text.md +76 -0
  68. package/ai/components/toolbar.md +95 -0
  69. package/ai/components/value-table.md +72 -0
  70. package/ai/components/wa-accordion-item.md +55 -0
  71. package/ai/components/wa-accordion.md +65 -0
  72. package/ai/components/wa-animated-image.md +55 -0
  73. package/ai/components/wa-animation.md +55 -0
  74. package/ai/components/wa-avatar.md +55 -0
  75. package/ai/components/wa-badge.md +55 -0
  76. package/ai/components/wa-breadcrumb-item.md +53 -0
  77. package/ai/components/wa-breadcrumb.md +55 -0
  78. package/ai/components/wa-button-group.md +59 -0
  79. package/ai/components/wa-button.md +55 -0
  80. package/ai/components/wa-callout.md +58 -0
  81. package/ai/components/wa-card.md +59 -0
  82. package/ai/components/wa-carousel-item.md +53 -0
  83. package/ai/components/wa-carousel.md +55 -0
  84. package/ai/components/wa-checkbox-group.md +55 -0
  85. package/ai/components/wa-checkbox.md +55 -0
  86. package/ai/components/wa-color-picker.md +55 -0
  87. package/ai/components/wa-comparison.md +55 -0
  88. package/ai/components/wa-copy-button.md +55 -0
  89. package/ai/components/wa-details.md +61 -0
  90. package/ai/components/wa-dialog.md +59 -0
  91. package/ai/components/wa-divider.md +53 -0
  92. package/ai/components/wa-drawer.md +55 -0
  93. package/ai/components/wa-dropdown-item.md +60 -0
  94. package/ai/components/wa-dropdown.md +60 -0
  95. package/ai/components/wa-format-bytes.md +53 -0
  96. package/ai/components/wa-format-date.md +53 -0
  97. package/ai/components/wa-format-number.md +53 -0
  98. package/ai/components/wa-icon.md +58 -0
  99. package/ai/components/wa-include.md +53 -0
  100. package/ai/components/wa-input.md +59 -0
  101. package/ai/components/wa-intersection-observer.md +53 -0
  102. package/ai/components/wa-known-date.md +53 -0
  103. package/ai/components/wa-markdown.md +53 -0
  104. package/ai/components/wa-mutation-observer.md +53 -0
  105. package/ai/components/wa-number-input.md +55 -0
  106. package/ai/components/wa-option.md +59 -0
  107. package/ai/components/wa-otp-input.md +53 -0
  108. package/ai/components/wa-page.md +53 -0
  109. package/ai/components/wa-pagination.md +55 -0
  110. package/ai/components/wa-popover.md +55 -0
  111. package/ai/components/wa-popup.md +53 -0
  112. package/ai/components/wa-progress-bar.md +53 -0
  113. package/ai/components/wa-progress-ring.md +53 -0
  114. package/ai/components/wa-qr-code.md +53 -0
  115. package/ai/components/wa-radio-group.md +59 -0
  116. package/ai/components/wa-radio.md +55 -0
  117. package/ai/components/wa-random-content.md +53 -0
  118. package/ai/components/wa-rating.md +55 -0
  119. package/ai/components/wa-relative-time.md +53 -0
  120. package/ai/components/wa-resize-observer.md +53 -0
  121. package/ai/components/wa-scroller.md +53 -0
  122. package/ai/components/wa-select.md +63 -0
  123. package/ai/components/wa-skeleton.md +53 -0
  124. package/ai/components/wa-slider.md +55 -0
  125. package/ai/components/wa-spinner.md +58 -0
  126. package/ai/components/wa-split-panel.md +58 -0
  127. package/ai/components/wa-switch.md +53 -0
  128. package/ai/components/wa-tab-group.md +69 -0
  129. package/ai/components/wa-tab-panel.md +60 -0
  130. package/ai/components/wa-tab.md +59 -0
  131. package/ai/components/wa-tag.md +59 -0
  132. package/ai/components/wa-textarea.md +53 -0
  133. package/ai/components/wa-time-input.md +55 -0
  134. package/ai/components/wa-toast-item.md +60 -0
  135. package/ai/components/wa-toast.md +60 -0
  136. package/ai/components/wa-tooltip.md +55 -0
  137. package/ai/components/wa-tree-item.md +55 -0
  138. package/ai/components/wa-tree.md +55 -0
  139. package/ai/components/wa-zoomable-frame.md +55 -0
  140. package/ai/components/workbench.md +114 -0
  141. package/ai/public-api-signatures-v1.md +572 -101
  142. package/ai/skill.md +107 -52
  143. package/ai/webawesome-jsx-signatures-v1.md +8 -2
  144. package/analyzer/component-ownership.d.mts +56 -0
  145. package/analyzer/component-ownership.mjs +184 -0
  146. package/analyzer/index.d.mts +3 -0
  147. package/analyzer/index.mjs +274 -20
  148. package/analyzer/selectors.d.mts +21 -0
  149. package/analyzer/selectors.mjs +212 -0
  150. package/dist/app-tab.js +1 -1
  151. package/dist/badge.d.ts +35 -7
  152. package/dist/badge.js +1 -1
  153. package/dist/browser/catalog.js +25 -0
  154. package/dist/browser/collapsible-panel.js +7 -0
  155. package/dist/browser/content-item.js +3 -0
  156. package/dist/browser/nav-stack.js +8 -0
  157. package/dist/browser/select.js +1 -0
  158. package/dist/browser/split-view.js +10 -0
  159. package/dist/browser/tab-scaffold.js +4 -0
  160. package/dist/browser/workbench.js +10 -0
  161. package/dist/catalog-resources.d.ts +12 -1
  162. package/dist/catalog.d.ts +14 -3
  163. package/dist/catalog.js +53 -43
  164. package/dist/catalog.js.map +1 -1
  165. package/dist/{chunk-WZ2GLEY4.js → chunk-2G2ZJQYK.js} +2 -14
  166. package/dist/chunk-2G2ZJQYK.js.map +1 -0
  167. package/dist/{chunk-R754MHXX.js → chunk-553ASUK6.js} +8 -8
  168. package/dist/chunk-553ASUK6.js.map +1 -0
  169. package/dist/{chunk-D7GWXIAS.js → chunk-5I7QGQVT.js} +1 -1
  170. package/dist/chunk-5I7QGQVT.js.map +1 -0
  171. package/dist/{chunk-RNRUVPJ3.js → chunk-63ZWBGE3.js} +3 -2
  172. package/dist/chunk-63ZWBGE3.js.map +1 -0
  173. package/dist/{chunk-44IG7PFV.js → chunk-6CINWX2E.js} +3 -3
  174. package/dist/{chunk-44IG7PFV.js.map → chunk-6CINWX2E.js.map} +1 -1
  175. package/dist/{chunk-MTM43SJO.js → chunk-6YFHCLHG.js} +2 -2
  176. package/dist/chunk-6YFHCLHG.js.map +1 -0
  177. package/dist/{chunk-C2FAYFDE.js → chunk-AGXQQFKZ.js} +2 -2
  178. package/dist/{chunk-C2FAYFDE.js.map → chunk-AGXQQFKZ.js.map} +1 -1
  179. package/dist/{chunk-ATHXW6RP.js → chunk-AHEG27M7.js} +2 -2
  180. package/dist/{chunk-ATHXW6RP.js.map → chunk-AHEG27M7.js.map} +1 -1
  181. package/dist/chunk-BFPBS5Y4.js +250 -0
  182. package/dist/chunk-BFPBS5Y4.js.map +1 -0
  183. package/dist/{chunk-5OLVUEND.js → chunk-DG6G5EPF.js} +4 -6
  184. package/dist/chunk-DG6G5EPF.js.map +1 -0
  185. package/dist/{chunk-LZXQVUGN.js → chunk-EVYKTVBQ.js} +5 -14
  186. package/dist/chunk-EVYKTVBQ.js.map +1 -0
  187. package/dist/{chunk-7GUQYHKA.js → chunk-EZVNC4J6.js} +7 -1
  188. package/dist/chunk-EZVNC4J6.js.map +1 -0
  189. package/dist/{chunk-RNZAKSME.js → chunk-F4QMLOXJ.js} +5 -4
  190. package/dist/chunk-F4QMLOXJ.js.map +1 -0
  191. package/dist/{chunk-EAX2GSS4.js → chunk-G2RKFVRB.js} +54 -20
  192. package/dist/chunk-G2RKFVRB.js.map +1 -0
  193. package/dist/chunk-JCV4GXWB.js +249 -0
  194. package/dist/chunk-JCV4GXWB.js.map +1 -0
  195. package/dist/chunk-K47P7QZC.js +17 -0
  196. package/dist/chunk-K47P7QZC.js.map +1 -0
  197. package/dist/{chunk-HMQ2ZDGG.js → chunk-KROD7KZK.js} +3 -2
  198. package/dist/chunk-KROD7KZK.js.map +1 -0
  199. package/dist/{chunk-5NDQABWK.js → chunk-M7QV3IHH.js} +3 -1
  200. package/dist/chunk-M7QV3IHH.js.map +1 -0
  201. package/dist/chunk-MA73TA6D.js +42 -0
  202. package/dist/chunk-MA73TA6D.js.map +1 -0
  203. package/dist/{chunk-ZMBU522F.js → chunk-MEY33VWB.js} +2 -2
  204. package/dist/{chunk-ZMBU522F.js.map → chunk-MEY33VWB.js.map} +1 -1
  205. package/dist/chunk-MP2GDBQZ.js +50 -0
  206. package/dist/chunk-MP2GDBQZ.js.map +1 -0
  207. package/dist/{chunk-3NBL3OUQ.js → chunk-NAPE7WUS.js} +2 -2
  208. package/dist/chunk-NAPE7WUS.js.map +1 -0
  209. package/dist/{chunk-BSKEH3UC.js → chunk-NBYTIVHS.js} +2 -2
  210. package/dist/{chunk-BSKEH3UC.js.map → chunk-NBYTIVHS.js.map} +1 -1
  211. package/dist/{chunk-T22EM4ET.js → chunk-OUK6QRDR.js} +71 -31
  212. package/dist/chunk-OUK6QRDR.js.map +1 -0
  213. package/dist/chunk-PWXNJS2B.js +115 -0
  214. package/dist/chunk-PWXNJS2B.js.map +1 -0
  215. package/dist/{chunk-GUIHMIT2.js → chunk-QOWG4ZCL.js} +5 -4
  216. package/dist/chunk-QOWG4ZCL.js.map +1 -0
  217. package/dist/{chunk-5I22LMCV.js → chunk-VZOFZPSO.js} +2 -2
  218. package/dist/chunk-VZOFZPSO.js.map +1 -0
  219. package/dist/{chunk-4BIMLITI.js → chunk-WLG6SSNT.js} +5 -3
  220. package/dist/chunk-WLG6SSNT.js.map +1 -0
  221. package/dist/{chunk-NE5JAOQS.js → chunk-WOUF7YXM.js} +3 -3
  222. package/dist/{chunk-NE5JAOQS.js.map → chunk-WOUF7YXM.js.map} +1 -1
  223. package/dist/{chunk-N7FHFNT6.js → chunk-XCO6YCYM.js} +34 -5
  224. package/dist/chunk-XCO6YCYM.js.map +1 -0
  225. package/dist/{chunk-TZ5IHWB2.js → chunk-XDKAYSVD.js} +5 -3
  226. package/dist/chunk-XDKAYSVD.js.map +1 -0
  227. package/dist/collapsible-panel.d.ts +14 -3
  228. package/dist/collapsible-panel.js +13 -16
  229. package/dist/collapsible-panel.js.map +1 -1
  230. package/dist/content-item.d.ts +46 -0
  231. package/dist/content-item.js +4 -0
  232. package/dist/content-item.js.map +1 -0
  233. package/dist/css-values.d.ts +5 -11
  234. package/dist/css-values.js +1 -1
  235. package/dist/disclosure-arrow.d.ts +4 -1
  236. package/dist/disclosure-arrow.js +1 -1
  237. package/dist/floating-toolbar.d.ts +17 -6
  238. package/dist/floating-toolbar.js +1 -1
  239. package/dist/grid.js +1 -1
  240. package/dist/help-tags-register.d.ts +13 -0
  241. package/dist/help-tags-register.js +9 -0
  242. package/dist/help-tags-register.js.map +1 -0
  243. package/dist/index.d.ts +7 -5
  244. package/dist/index.js +29 -26
  245. package/dist/list-action-row.js +2 -1
  246. package/dist/list-header.d.ts +14 -1
  247. package/dist/list-header.js +1 -1
  248. package/dist/list-inset-control.d.ts +1 -1
  249. package/dist/list-inset-control.js +1 -1
  250. package/dist/list-inset-text.d.ts +3 -10
  251. package/dist/list-inset-text.js +1 -1
  252. package/dist/list-item.js +2 -1
  253. package/dist/list.d.ts +10 -3
  254. package/dist/list.js +1 -1
  255. package/dist/nav-stack.d.ts +50 -5
  256. package/dist/nav-stack.js +4 -1
  257. package/dist/pane.d.ts +37 -2
  258. package/dist/pane.js +1 -1
  259. package/dist/{panel-toolbar-BFQxFITu.d.ts → panel-toolbar-BN4x0rth.d.ts} +13 -1
  260. package/dist/popup-menu-register.js +3 -2
  261. package/dist/popup-menu-register.js.map +1 -1
  262. package/dist/popup-menu.js +1 -1
  263. package/dist/row.d.ts +1 -1
  264. package/dist/row.js +1 -1
  265. package/dist/select-register.js +70 -3
  266. package/dist/select-register.js.map +1 -1
  267. package/dist/select.d.ts +46 -8
  268. package/dist/select.js +2 -1
  269. package/dist/{divider-sides-BzB6rphT.d.ts → sides-BPSWde0A.d.ts} +1 -3
  270. package/dist/skeleton.js +1 -1
  271. package/dist/spacer.js +1 -1
  272. package/dist/split-view.d.ts +31 -3
  273. package/dist/split-view.js +34 -5
  274. package/dist/split-view.js.map +1 -1
  275. package/dist/state-banner.js +1 -1
  276. package/dist/styles/app-tab.css +31 -0
  277. package/dist/styles/badge.css +32 -11
  278. package/dist/styles/catalog/components/catalog-example.css +1 -1
  279. package/dist/styles/catalog/components/catalog-stage.css +1 -1
  280. package/dist/styles/collapsible-panel.css +199 -42
  281. package/dist/styles/content-item.css +30 -0
  282. package/dist/styles/floating-toolbar.css +26 -2
  283. package/dist/styles/foundation.css +28 -19
  284. package/dist/styles/layout.css +1 -21
  285. package/dist/styles/list-action-row.css +13 -1
  286. package/dist/styles/list-header.css +0 -12
  287. package/dist/styles/list-inset-text.css +1 -2
  288. package/dist/styles/list-item.css +14 -1
  289. package/dist/styles/list.css +5 -5
  290. package/dist/styles/nav-stack.css +63 -71
  291. package/dist/styles/pane.css +83 -1
  292. package/dist/styles/popup-menu.css +229 -0
  293. package/dist/styles/resizable-region.css +70 -15
  294. package/dist/styles/select.css +60 -19
  295. package/dist/styles/skeleton.css +30 -3
  296. package/dist/styles/split-view.css +31 -32
  297. package/dist/styles/state-banner.css +0 -19
  298. package/dist/styles/surface-scaffold.css +8 -3
  299. package/dist/styles/tab-bar.css +79 -28
  300. package/dist/styles/tab-scaffold.css +60 -14
  301. package/dist/styles/text.css +17 -1
  302. package/dist/styles/token-search-field.css +4 -4
  303. package/dist/styles/toolbar-control-group.css +143 -69
  304. package/dist/styles/toolbar-text.css +21 -0
  305. package/dist/styles/toolbar.css +22 -37
  306. package/dist/styles/value-table.css +19 -2
  307. package/dist/styles/webawesome.css +3 -1
  308. package/dist/styles/workbench.css +145 -42
  309. package/dist/tab-scaffold.d.ts +46 -2
  310. package/dist/tab-scaffold.js +52 -16
  311. package/dist/tab-scaffold.js.map +1 -1
  312. package/dist/token-search-field.d.ts +4 -2
  313. package/dist/token-search-field.js +1 -1
  314. package/dist/toolbar-text.d.ts +7 -1
  315. package/dist/toolbar-text.js +1 -1
  316. package/dist/toolbar.d.ts +20 -5
  317. package/dist/toolbar.js +1 -1
  318. package/dist/{types-D6vzj-VT.d.ts → types-BuHELdXR.d.ts} +39 -6
  319. package/dist/value-table.js +1 -1
  320. package/dist/webawesome.d.ts +7 -1
  321. package/dist/wire-catalog.d.ts +15 -2
  322. package/dist/wire-catalog.js +12 -2
  323. package/dist/wire-catalog.js.map +1 -1
  324. package/dist/wire-scroll-dividers.d.ts +69 -0
  325. package/dist/wire-scroll-dividers.js +3 -0
  326. package/dist/wire-scroll-dividers.js.map +1 -0
  327. package/dist/wire-token-search-fields.js +1 -1
  328. package/dist/workbench.d.ts +60 -22
  329. package/dist/workbench.js +1 -1
  330. package/docs/accessibility.md +116 -7
  331. package/docs/app-layouts.md +18 -8
  332. package/docs/catalog.md +26 -7
  333. package/docs/collapsible-panel.md +32 -9
  334. package/docs/component-contract.md +182 -30
  335. package/docs/component-selection.md +59 -46
  336. package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
  337. package/docs/design/templates/empty-state/with-action.svg +1 -1
  338. package/docs/design/templates/empty-state-dark.svg +1 -1
  339. package/docs/design/templates/empty-state.svg +1 -1
  340. package/docs/design/templates/list/compact-dark.svg +1 -1
  341. package/docs/design/templates/list/compact.svg +1 -1
  342. package/docs/design/templates/list/stack-dark.svg +1 -1
  343. package/docs/design/templates/list/stack.svg +1 -1
  344. package/docs/design/templates/list-action-row/default-dark.svg +1 -1
  345. package/docs/design/templates/list-action-row/default.svg +1 -1
  346. package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
  347. package/docs/design/templates/list-action-row/selected.svg +1 -1
  348. package/docs/design/templates/list-action-row-dark.svg +1 -1
  349. package/docs/design/templates/list-action-row.svg +1 -1
  350. package/docs/design/templates/list-dark.svg +1 -1
  351. package/docs/design/templates/list-item/default-dark.svg +1 -1
  352. package/docs/design/templates/list-item/default.svg +1 -1
  353. package/docs/design/templates/list-item/selected-dark.svg +1 -1
  354. package/docs/design/templates/list-item/selected.svg +1 -1
  355. package/docs/design/templates/list-item/trailing-dark.svg +1 -1
  356. package/docs/design/templates/list-item/trailing.svg +1 -1
  357. package/docs/design/templates/list-item-dark.svg +1 -1
  358. package/docs/design/templates/list-item.svg +1 -1
  359. package/docs/design/templates/list.svg +1 -1
  360. package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -1
  361. package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -1
  362. package/docs/design/templates/tab-bar-dark.svg +1 -1
  363. package/docs/design/templates/tab-bar.svg +1 -1
  364. package/docs/design/templates/value-table/details-dark.svg +1 -1
  365. package/docs/design/templates/value-table/details.svg +1 -1
  366. package/docs/design/templates/value-table-dark.svg +1 -1
  367. package/docs/design/templates/value-table.svg +1 -1
  368. package/docs/design-philosophy.md +31 -4
  369. package/docs/examples/application-ui-profile.json +4 -4
  370. package/docs/examples/command-palette-adapter.tsx +3 -2
  371. package/docs/examples/{component-catalog-extension-v2.json → component-composition-extension.json} +3 -3
  372. package/docs/layout.md +148 -29
  373. package/docs/nav-stack.md +77 -3
  374. package/docs/recipes.md +4 -3
  375. package/docs/split-view.md +54 -5
  376. package/docs/tab-scaffold.md +73 -2
  377. package/docs/type-contracts.md +21 -20
  378. package/docs/ui-analyzer.md +99 -5
  379. package/docs/ui-doctor.md +10 -0
  380. package/docs/ux-demo.md +2 -2
  381. package/docs/webawesome-theme.md +1 -2
  382. package/docs/workbench.md +57 -11
  383. package/doctor/index.mjs +6 -1
  384. package/llms.txt +117 -24
  385. package/package.json +29 -6
  386. package/ux-demo/recipes/collapsible-sidebar.tsx +3 -3
  387. package/ux-demo/recipes/composer-form.tsx +0 -1
  388. package/ux-demo/recipes/list-detail-dialog.tsx +0 -2
  389. package/ux-demo/recipes/list-workspace-states.tsx +0 -1
  390. package/ux-demo/recipes/loading-inspector.tsx +0 -1
  391. package/ux-demo/recipes/navigation-sidebar.tsx +3 -2
  392. package/ux-demo/recipes/navigation-stack.tsx +3 -2
  393. package/ux-demo/recipes/workspace-header.tsx +0 -1
  394. package/ai/component-catalog-extension-v2.d.ts +0 -7
  395. package/ai/component-catalog-extension-v2.schema.json +0 -7
  396. package/dist/chunk-3NBL3OUQ.js.map +0 -1
  397. package/dist/chunk-4BIMLITI.js.map +0 -1
  398. package/dist/chunk-5I22LMCV.js.map +0 -1
  399. package/dist/chunk-5NDQABWK.js.map +0 -1
  400. package/dist/chunk-5OLVUEND.js.map +0 -1
  401. package/dist/chunk-7GUQYHKA.js.map +0 -1
  402. package/dist/chunk-D7GWXIAS.js.map +0 -1
  403. package/dist/chunk-DQA5FMOX.js +0 -85
  404. package/dist/chunk-DQA5FMOX.js.map +0 -1
  405. package/dist/chunk-EAX2GSS4.js.map +0 -1
  406. package/dist/chunk-GUIHMIT2.js.map +0 -1
  407. package/dist/chunk-HMQ2ZDGG.js.map +0 -1
  408. package/dist/chunk-LZXQVUGN.js.map +0 -1
  409. package/dist/chunk-MTM43SJO.js.map +0 -1
  410. package/dist/chunk-N7FHFNT6.js.map +0 -1
  411. package/dist/chunk-R754MHXX.js.map +0 -1
  412. package/dist/chunk-RNRUVPJ3.js.map +0 -1
  413. package/dist/chunk-RNZAKSME.js.map +0 -1
  414. package/dist/chunk-T22EM4ET.js.map +0 -1
  415. package/dist/chunk-TZ5IHWB2.js.map +0 -1
  416. package/dist/chunk-WZ2GLEY4.js.map +0 -1
  417. package/dist/chunk-XD7DWYXG.js +0 -34
  418. package/dist/chunk-XD7DWYXG.js.map +0 -1
@@ -44,7 +44,9 @@ the layouts handle the insets for you. There is nothing to configure:
44
44
  not inset on that edge. Collapse the rail and the center picks up the edge.
45
45
  - **No double inset.** Whichever region applies an inset clears it for its
46
46
  descendants. A layout region whose only child is a `Pane` or another layout
47
- lets that child own the insets. A `Pane` header or footer whose only child is
47
+ lets that child own the insets. That child fills the region — a `Workbench`
48
+ area or panel, a `NavStack` view, a `TabScaffold` scene — so a sole `Pane`'s
49
+ header stays pinned while its own content scrolls. A `Pane` header or footer whose only child is
48
50
  a `Toolbar` hands the inline insets to the toolbar, so the toolbar's dividers
49
51
  still reach the edge.
50
52
 
@@ -79,13 +81,15 @@ nothing routes that edge, while the bar's surface and divider still reach the
79
81
  screen edge. A claimed toolbar inside a `Pane` header or footer adds nothing
80
82
  extra, because the pane already owns those edges.
81
83
 
82
- Pass `safeAreaEdges={[]}` for a pane that never sits at a screen edge. For a
83
- region you own, set `--kui-edge-inset-block-start`, `--kui-edge-inset-block-end`,
84
- `--kui-edge-inset-inline-start`, or `--kui-edge-inset-inline-end` to `0px` on the
85
- region for each edge it does not reach, and kerf descendants follow. A
86
- `CollapsiblePanel` does this for its direct flex siblings automatically. A
87
- panel wrapped in your own grid cell cannot see its siblings, so route those
88
- edges yourself.
84
+ Pass `safeAreaEdges={[]}` for a pane that never sits at a screen edge. In an
85
+ arrangement you own, give each `Pane` (and each edge-claiming `Toolbar`)
86
+ `safeAreaEdges` listing only the sides its region reaches. The toolbar
87
+ configurations layouts accept (a Workbench `mainToolbar` / `mainBottomToolbar`,
88
+ and a Workbench panel's or `CollapsiblePanel`'s `toolbar`) forward
89
+ `safeAreaEdges` to their `Toolbar` the same way.
90
+ A `CollapsiblePanel` clears the edge it covers for its direct flex siblings
91
+ automatically; a panel wrapped in your own grid cell cannot see its siblings,
92
+ so pass the neighboring panes' `safeAreaEdges` yourself.
89
93
 
90
94
  The device insets come from `--kui-safe-area-block-start`, `-block-end`,
91
95
  `-inline-start`, and `-inline-end`, which default to `env(safe-area-inset-*)`.
@@ -129,6 +133,12 @@ device in tests.
129
133
  `content` a `NavStack`. On a tablet/desktop, render the same sections as a
130
134
  `Workbench` left rail instead of a bottom bar.
131
135
 
136
+ Whatever the layout, call `wireScrollDividers(appRoot)` from
137
+ `@kerfjs/ui/wire-scroll-dividers` once: every `Pane` a layout renders, every
138
+ `NavStack`'s top chrome and bottom toolbar, and every `TabScaffold` bar then
139
+ draw the line between the pinned chrome and the scrolling content only while
140
+ content is scrolled beneath them, and toolbars need no divider of their own. See [Scroll dividers](layout.md#scroll-dividers).
141
+
132
142
  ## Dialogs
133
143
 
134
144
  Pick the dialog's inner layout by the same complexity axis, then apply the device
package/docs/catalog.md CHANGED
@@ -281,7 +281,7 @@ import {
281
281
  wireCatalog,
282
282
  wireCatalogGeometryOverlay,
283
283
  } from "@kerfjs/ui/wire-catalog";
284
- import "@kerfjs/ui/styles.css"; // or import each primitive's CSS + @kerfjs/ui/catalog.css
284
+ // A CSS-aware (browser-condition) bundler loads the Catalog's CSS with its import.
285
285
 
286
286
  type DemoKind = "component" | "composition";
287
287
  type DemoEntry = CatalogSection["entries"][number] & { kind: DemoKind };
@@ -396,9 +396,25 @@ revealCatalogEntry(app, initial, { block: "center" });
396
396
  Pass the same signal as `wireCatalog`'s `collapsed` option so the sidebar is
397
397
  wired as a Workbench rail (transient on small screens, focus handed to the
398
398
  relocated toggle).
399
- - **`headerPlacement` / `footerPlacement`** choose whether the entry toolbar and the
400
- status + resource footer stay pinned (`fixed`, default) or scroll with the preview
401
- (`scroll`) — useful where large text would leave pinned chrome little room.
399
+ - **`headerPlacement` / `footerPlacement`** choose whether the entry toolbar and
400
+ description, and the status + resource footer, stay pinned (`fixed`), scroll with
401
+ the preview (`scroll`), or stay pinned while the entry pane is tall enough and
402
+ scroll with the preview when it is short (`auto`, the default) — so a short
403
+ window or large text never squeezes the preview out.
404
+ - **`sidebar`** configures the sidebar rail — it forwards to the Workbench's left
405
+ rail: `size` (default 288px), `resizable` (`true` or `{ min, max }`),
406
+ `separator`, `collapseMotion`, `presentation`, `responsiveOverlayAt` (default
407
+ `narrow`), `compactOverlay` (default `inset`), and `toolbar` (the sidebar
408
+ header's `ToolbarConfig`). A resizable sidebar's width is app state like
409
+ `collapsed`: render your size signal as `sidebar.size` and pass the same signal
410
+ as `wireCatalog`'s `sidebarSize` (plus `sidebarStorageKey` to remember it).
411
+ - **`mainToolbar` / `footerToolbar`** take the entry toolbar's and the resource
412
+ footer toolbar's `ToolbarConfig` (`dividerSides`, `centerAlign`, `responsive`,
413
+ `responsiveAt`, `safeAreaEdges`). The defaults are a wrapping entry toolbar
414
+ and a footer toolbar that stacks at `narrow`, all without dividers of their
415
+ own: `wireCatalog` wires `wireScrollDividers`, so the shell's panes draw
416
+ their chrome dividers only while scrolled; an omitted or
417
+ `undefined` field keeps them. Configure these instead of styling the shell.
402
418
  - **`theme`** is a global preference — the app's signal; `wireCatalog` only reports
403
419
  the toggle, the app applies the theme (the shell reads `theme` to show the toggle's
404
420
  opposite-state label). Omit `theme` to hide the toggle entirely.
@@ -415,7 +431,10 @@ matching options on `wireCatalog`) if they collide with your own action table.
415
431
  `Catalog` composes public components (`Workbench`, `Pane`, `Toolbar`, `List`,
416
432
  `ListHeader`, `ListItem`, `ListInsetText`, `Text`, …) and owns only the preview stage
417
433
  (the checkerboard and centered canvas), the geometry overlay, the example viewport
418
- options, and the brand mark's size. Import `@kerfjs/ui/styles.css` for the whole
419
- layer, or `@kerfjs/ui/catalog.css` plus `@kerfjs/ui/workbench.css` and each composed
420
- primitive's CSS. Like any Workbench it needs a definite containing height — the
434
+ options, and the brand mark's size. A bundler that honors the `browser` export
435
+ condition loads the Catalog's stylesheets and those of every component it renders
436
+ internally with the `@kerfjs/ui/catalog` import alone — no dependence on which other
437
+ subpaths the app happens to import. Without that condition, import
438
+ `@kerfjs/ui/styles.css` for the whole layer, or `@kerfjs/ui/catalog.css` plus
439
+ `@kerfjs/ui/workbench.css` and each composed primitive's CSS. Like any Workbench it needs a definite containing height — the
421
440
  `@kerfjs/ui/document.css` baseline's `.kui-app-root`.
@@ -10,7 +10,10 @@ subpath-only, tree-shakeable modules that add nothing to the main barrel.
10
10
  npm install @kerfjs/ui # kerfjs is a peer
11
11
  ```
12
12
 
13
- Import the panel CSS (`@kerfjs/ui/collapsible-panel.css`) alongside `foundation.css`.
13
+ A browser bundler that honors the `browser` export condition loads the panel's CSS
14
+ and that of the components it renders (`Pane`, `Toolbar`, `ToolbarControlGroup`,
15
+ `LucideIcon`) with `@kerfjs/ui/collapsible-panel`. Without that condition, import
16
+ `@kerfjs/ui/collapsible-panel.css` plus those stylesheets alongside `foundation.css`.
14
17
 
15
18
  ## The pieces
16
19
 
@@ -57,7 +60,15 @@ Import the panel CSS (`@kerfjs/ui/collapsible-panel.css`) alongside `foundation.
57
60
  the rest of the page, including under the compact overlay's backdrop. The
58
61
  control takes `--kui-collapsible-panel-restore-z`, which defaults to two less
59
62
  than `--kui-collapsible-panel-overlay-z` (38); the backdrop defaults to one
60
- less (39), so moving the overlay z-index moves both. Escape, a backdrop
63
+ less (39), so moving the overlay z-index moves both. While a left or right
64
+ overlay is open (the `wireSidebar` compact overlay, or
65
+ `presentation="overlay"`), the content's floating controls — restore
66
+ corners and any `FloatingToolbar` — are also hidden outright (out of the
67
+ tab order and the accessibility tree), so they never paint over the overlay
68
+ whatever stacking context the app creates; they return as it closes. The
69
+ overlay's own floating controls stay, and a bottom overlay hides nothing. A
70
+ horizontal `presentation="overlay"` `ResizableRegion` does the same for its
71
+ siblings. Escape, a backdrop
61
72
  press, or the panel's own close control reveals the control again, and a
62
73
  collapsed overlay leaves it clickable. `ResizableRegion`'s `restoreControl`
63
74
  follows the same rules, two below `--kui-resizable-region-overlay-z` (39).
@@ -118,8 +129,21 @@ Give a panel a `toolbar` (the same roles as a
118
129
  [Workbench panel toolbar](workbench.md#panel-toolbars)) and it composes its own
119
130
  top toolbar over a `Pane`, with an optional `footer` below its content:
120
131
 
121
- - `title` and `panelOnly` groups lead it and are available only while it is open;
122
- - `constant` groups and the standard `toggle: { action, name }` trail it.
132
+ - `title` and `panelOnly` groups lead it and are available only while it is open,
133
+ as is optional `center` content;
134
+ - `constant` groups and the standard `toggle: { action, name, showLabel?,
135
+ hideLabel? }` trail it.
136
+
137
+ The toolbar also takes the `Toolbar`'s configuration (`dividerSides`,
138
+ `centerAlign`, `responsive`, `responsiveAt`, `safeAreaEdges`); it draws no
139
+ divider of its own unless `dividerSides` says so. The `Pane` under it draws
140
+ the line under the toolbar only while its content is scrolled (see
141
+ [Scroll dividers](./layout.md#scroll-dividers)), and takes the panel's `pane`
142
+ (`PaneConfig`: `contentElement`, `contentLabel`, `separators`,
143
+ `safeAreaEdges`, `chromeDividers`) — for example `{ contentElement: "nav",
144
+ contentLabel: "Sections" }` for a navigation rail. An omitted or `undefined`
145
+ field keeps the `Pane` default; without a `toolbar` there is no `Pane`, so
146
+ `pane` is ignored.
123
147
 
124
148
  A standalone panel does not own the rest of the screen, so the app places a
125
149
  `CollapsiblePanelRelocated` in its own work-area toolbar: it renders the panel's
@@ -222,7 +246,6 @@ import {
222
246
  CollapsiblePanelToggle,
223
247
  } from "@kerfjs/ui/collapsible-panel";
224
248
  import { wireSidebar } from "@kerfjs/ui/wire-sidebar";
225
- import "@kerfjs/ui/collapsible-panel.css";
226
249
 
227
250
  const device = deviceClass();
228
251
  // Start collapsed on a compact device; `inlineCollapsed` keeps the open inline
@@ -289,10 +312,10 @@ panel to the compact overlay (`wireSidebar`) where the viewport cannot hold it.
289
312
 
290
313
  A panel grows by the unsafe inset of the edge it docks to and pads its content
291
314
  for every edge it touches except its interior edge. While expanded inline, it
292
- also clears that edge for its direct flex siblings, so a neighboring pane gains
293
- the inset when the panel collapses. When you wrap the panel in your own grid
294
- cell, set `--kui-edge-inset-*: 0px` on the sibling regions yourself (or pass
295
- `safeAreaEdges` to a sibling `Pane`). See [Choosing an app layout › Safe areas](app-layouts.md#safe-areas).
315
+ also clears that edge for every other direct child of its container, so a
316
+ neighboring pane gains the inset when the panel collapses. When you wrap the panel in your own grid
317
+ cell, pass each sibling `Pane` a `safeAreaEdges` that omits the edge the panel
318
+ covers. See [Choosing an app layout › Safe areas](app-layouts.md#safe-areas).
296
319
 
297
320
  ## When to use which
298
321
 
@@ -18,12 +18,33 @@ package delivery paths, Web Awesome's installed manifest, AI guidance, and
18
18
  documentation links. Nuanced prose in this contract and the selection guide
19
19
  remains authored rather than generated.
20
20
 
21
- ### Composition catalog v2
22
-
23
- [`component-catalog-v2.json`](../ai/component-catalog-v2.json) adds a formal,
24
- machine-evaluable composition layer without changing the v1 selection and
25
- delivery contract. Every v1 entry projects once, in order, under the stable
26
- qualified key `package:id`. Each v2 entry explicitly covers parents/contexts,
21
+ ### Markdown component reference (AI entry point)
22
+
23
+ [`ai/components/README.md`](../ai/components/README.md) and one
24
+ `ai/components/<id>.md` page per catalog entry are the assistant-facing view of
25
+ both catalogs. An assistant reads the index, then only the pages it uses,
26
+ instead of loading the full JSON. Each page merges the entry's selection facts
27
+ (purpose, use/avoid, alternatives), delivery (JavaScript subpath, CSS,
28
+ registration, wiring helpers), a link into `public-api-signatures-v1.md` for
29
+ exact props, composition (parents, contexts, zones with their JSX prop and
30
+ cardinality, children), state and wiring ownership including wiring-owned
31
+ state attributes, geometry, accessibility obligations, public class and token
32
+ hooks framed as a styling boundary (components own their styles; configure
33
+ through props rather than overriding internals), and `KUI-C###` diagnostics
34
+ with their conditions. `scripts/sync-component-docs.mjs` renders them only from
35
+ `component-catalog.json` and `component-composition.json` (plus the signature
36
+ file's module headings for anchors), sorted and Prettier-formatted;
37
+ `check:catalog` rejects a stale, missing, or orphaned page. The JSON files stay
38
+ the canonical tool-facing sources.
39
+
40
+ ### Composition catalog
41
+
42
+ [`component-composition.json`](../ai/component-composition.json) adds a formal,
43
+ machine-evaluable composition layer beside `component-catalog.json` without
44
+ changing its selection and delivery contract; it is a generated companion, not
45
+ a newer version of that catalog. Every component-catalog entry projects once,
46
+ in order, under the stable qualified key `package:id`. Each composition entry
47
+ explicitly covers parents/contexts,
27
48
  named zones and cardinality, optional explicit JSX prop bindings, child concepts, state ownership, required wiring,
28
49
  responsive ownership, layout and geometry, accessibility obligations, public
29
50
  CSS boundaries, diagnostics, and provenance. A wrapper entry may add
@@ -31,6 +52,18 @@ CSS boundaries, diagnostics, and provenance. A wrapper entry may add
31
52
  composition checks treat its elements as each root rather than as an unknown
32
53
  child.
33
54
 
55
+ `boundaries.placeableClasses` names the subset of `publicClasses` an
56
+ application may write onto its own elements (layout utilities, the document
57
+ root, item geometry on another carrier); absent means none, and every other
58
+ public class is the component's rendered anatomy. `boundaries.rootElement`
59
+ names the element a component renders around its own placeable classes
60
+ (`content-item`: `div`), so a plain element of that tag carrying them is still
61
+ the component recreated. `eslint-plugin-kerfjs`'s `ui-public-boundaries`
62
+ reports both as `KUI-L103` with the export to render — for `@kerfjs/ui` and for
63
+ every consumer catalog a `.kerf-ui-profile.json` declares, whatever the class
64
+ prefix. `create-kerf-component` packages declare the same fields in
65
+ `kerf.components.json`.
66
+
34
67
  An entry's optional `cssValueProps` makes CSS-adjacent prop grammar equally
35
68
  machine-evaluable. Each path records the property grammar, finite shorthands,
36
69
  canonical versus exceptional spacing choices, standalone and expression-only
@@ -46,7 +79,8 @@ ESLint, `kerf-ui-analyze`, and `kerf-ui-doctor` then issue the same stable
46
79
  (`on`), the `helper` that writes it, and what it means. An application must not
47
80
  render, remove, or treat these attributes as its own state; tools use the list
48
81
  to tell them apart from app-authored attributes. They are declared once, on the
49
- helper's wiring item in the v1 catalog, and v2 flattens them. `check:catalog`
82
+ helper's wiring item in the component catalog, and the composition catalog
83
+ flattens them. `check:catalog`
50
84
  reads each `wire*` helper's source and fails when its declarations differ from
51
85
  the `data-*` attributes it actually writes. First-party entries always carry
52
86
  the list, empty when their helpers write none; it is optional in extension
@@ -55,7 +89,7 @@ catalogs.
55
89
  The generator starts with permissive defaults. An `any` mode records that the
56
90
  catalog has no defensible prohibition; it does not claim every composition is
57
91
  recommended. Objective rules live in
58
- `component-catalog-v2-overrides.json` and may carry stable `KUI-C###`
92
+ `component-composition-rules.json` and may carry stable `KUI-C###`
59
93
  diagnostics. A tool reports a diagnostic only after proving its exact `when`
60
94
  condition. Subjective choice, product policy, and visual taste remain prose.
61
95
 
@@ -64,7 +98,7 @@ Use `children` for one homogeneous primary region; use explicit named
64
98
  `SafeHtml` props for semantic positions or replacement content such as
65
99
  `header`, `footer`, `leading`, `trailing`, `icon`, and `action`. These are typed
66
100
  function-component props, not native web-component `<slot>` elements and not a
67
- generic `slots={{...}}` object. A v2 zone declares `jsx.prop` only when tooling
101
+ generic `slots={{...}}` object. A composition zone declares `jsx.prop` only when tooling
68
102
  can soundly bind that zone to one public JSX prop; `children` is spelled
69
103
  explicitly. Zones without that binding remain guidance and are never guessed
70
104
  from their ids. Static tools inspect only visible JSX structure and leave
@@ -85,13 +119,14 @@ can return a region plus a sibling restore control, leaving no single root that
85
119
  can truthfully own native slot assignment. Their single-root controls and all
86
120
  alternate-root branches of supported components retain the contract.
87
121
 
88
- V1 consumers continue unchanged. V2 consumers read v1 for selection/delivery
89
- and v2 for composition. `npm run catalog:sync` projects every new component,
122
+ Component-catalog consumers continue unchanged. Composition-aware consumers
123
+ read `component-catalog.json` for selection/delivery and
124
+ `component-composition.json` for composition. `npm run catalog:sync` projects every new component,
90
125
  recipe, and supported Web Awesome entry, and the completeness gate prevents
91
- silent omissions. Downstream catalogs use the v2 extension schema and types,
126
+ silent omissions. Downstream catalogs use the composition extension schema and types,
92
127
  retain their own package identity, and qualify cross-catalog references. See
93
128
  the checked
94
- [`component-catalog-extension-v2.json`](./examples/component-catalog-extension-v2.json)
129
+ [`component-composition-extension.json`](./examples/component-composition-extension.json)
95
130
  application-owned example.
96
131
 
97
132
  ### Compile-time contract boundary
@@ -117,10 +152,11 @@ layout/responsive conventions, and narrow rule exceptions there. Product
117
152
  records, copy, permissions, user preferences, and transport state do not belong
118
153
  in this policy file.
119
154
 
120
- Every catalog location names a v2 composition artifact. `selection` is optional
121
- for consumer packages whose generated metadata declares v1 selection guidance
122
- not applicable; `@kerfjs/ui` retains its required v1 selection artifact. This
123
- lets a generated `component-catalog-v2.json` participate directly without a
155
+ Every catalog location names a composition artifact. `selection` is optional
156
+ for consumer packages whose generated metadata declares component-catalog
157
+ selection guidance not applicable; `@kerfjs/ui` retains its required
158
+ `component-catalog.json` selection artifact. This
159
+ lets a generated `component-composition.json` participate directly without a
124
160
  fabricated compatibility file.
125
161
 
126
162
  Discovery and precedence are deterministic:
@@ -147,6 +183,22 @@ I/O.
147
183
  See the
148
184
  [`application-ui-profile.json`](./examples/application-ui-profile.json) example.
149
185
 
186
+ The package defaults avoid every `Discouraged` Web Awesome entry — each
187
+ `webawesome` catalog entry whose `recommendation` is not `supported`, except the
188
+ encouraged `wa-popup` primitive — under a concept whose `preferred` value is the
189
+ Kerf component that wraps or replaces it (`command-menu` → `PopupMenu`,
190
+ `value-selection` → `Select`, `application-tabs` → `TabBar`, `icon` →
191
+ `LucideIcon`, `resizable-pane` → `ResizableRegion`, `exclusive-choice` →
192
+ `SegmentedControl`, `hierarchy-navigation` → `List`, `embedded-media` →
193
+ `ContentItem`). `eslint-plugin-kerfjs` `ui-preferences` (`KUI-L301`, also run by
194
+ `kerf-ui-doctor`) therefore reports a Discouraged element written directly as a
195
+ JSX tag (`<wa-dropdown>`) as well as through an imported component. A declared
196
+ component's own source file is exempt, because that wrapper is the sanctioned
197
+ owner of the element it renders. A unit test holds the avoid set and the
198
+ catalog's Discouraged set equal in both directions, so neither can drift. A
199
+ product that genuinely needs one of these elements records a narrow `KUI-L301`
200
+ profile exception for the file that renders it.
201
+
150
202
  Catalog detail footers use one standard resource vocabulary and order. Build
151
203
  them with `catalogResources()` from `@kerfjs/ui/catalog-resources`: `Demo source`
152
204
  first, optional `Component source` and `Design template`, then `Guidance`.
@@ -232,7 +284,72 @@ documented props and tokens; package components may compose other components
232
284
  only through those public contracts, never by styling a child's classes from a
233
285
  parent stylesheet.
234
286
 
235
- The v2 composition catalog additionally requires `boundaries.rootClass` to be
287
+ Inside the package, a component never styles another component or writes
288
+ another component's variables. When a child must adapt to a composing parent,
289
+ the child styles itself in that context from its own stylesheet: the parent's
290
+ class and state appear only in an ancestor compound, the styled compound is
291
+ the child's own class (or one of the child's own unclassed internals below
292
+ it), and the child reads context values the parent provides under the
293
+ parent's name. `ResizableRegion` widens its edge extent by the unsafe inset a
294
+ split `SplitView` provides, and a `Skeleton` derives its fill from a solid
295
+ `Badge`'s on-solid color, both in their own stylesheets; an `AppTab` rounds its
296
+ outer corners in a segmented `TabBar` and shares a fill-allocated strip from
297
+ `app-tab.css`. A `PopupMenu` sizes
298
+ its trigger and applies a group's `menuInset` in its own stylesheet, and an
299
+ icon-only `Select` reads the control slot a `ToolbarControlGroup` provides
300
+ (`--_kui-toolbar-control-group-slot-*`). A parent may still style its own
301
+ elements keyed on a child's state, naming the child by class inside `:has()`
302
+ (`:has(> .kui-select[open])`, or `TabBar` insetting a segmented strip that
303
+ holds compact tabs), and it keeps styling raw native and raw Web
304
+ Awesome children no kerf component owns, excluding kerf children by class
305
+ (`wa-dropdown:not(.kui-popup-menu)`). `npm run check:css-ownership` enforces
306
+ this in every component stylesheet (a `src/*.css` with a same-basename
307
+ component), deriving the component names, the Web Awesome tags each component
308
+ renders, and its composed children from `src/*.tsx`:
309
+
310
+ - **Foreign classes.** Another component's class or `[data-component]` may
311
+ appear only in an ancestor compound or inside `:has()` / `:not()`; the
312
+ styled compound is the stylesheet's own class.
313
+ - **Owned Web Awesome tags.** Kerf components are named by class, never by a
314
+ `wa-*` tag they render. A tag another component renders (`wa-dropdown`,
315
+ `wa-select`, `wa-option`, a `PopupMenu`'s trigger `wa-button`) — as the
316
+ subject, or as an ancestor whose internals the rule reaches — must be scoped
317
+ to that component by its class or excluded with `:not()`. A direct child
318
+ that cannot be the owner's internal
319
+ (`.kui-toolbar-control-group > wa-button`) needs no exclusion.
320
+ - **Variables.** A stylesheet writes only its own `--_kui-<self>-*` private
321
+ variables, and never overrides a public `--kui-<other>-*` token that another
322
+ component reads. Shared foundation tokens (`--kui-layout-*`,
323
+ `--kui-color-*`, …) are not any one component's. Context a parent provides
324
+ is named after the parent.
325
+ - **Context on any child.** Custom properties set on a subject that can be any
326
+ element (`.kui-x > *`, `> :not(…)`) also land on composed components' roots.
327
+ - **Hook classes.** A class the component places on a composed kerf child's
328
+ root (`<ToolbarText className="kui-nav-stack__title">`, a class NavStack once styled) may not be styled;
329
+ the child styles itself in that context instead.
330
+
331
+ The documented exceptions live with their reasons in
332
+ `scripts/lib/css-ownership.mjs`, and an exception that stops matching fails the
333
+ check, so the list only shrinks. The layout regions' inherited edge-inset
334
+ context (`--kui-edge-inset-*` handed to a sole Pane or layout child and cleared
335
+ for any other content, and a Toolbar clearing it for its zones) is the one
336
+ design exception; the others name the open fix ticket.
337
+
338
+ Applications and component packages built on the package follow the same
339
+ rules, and the downstream tools enforce them against the composition catalog
340
+ instead of package source: `kerf-ui-analyze` / `kerf-ui-doctor` report a rule
341
+ whose subject is another package's component (`KUI-L019`), another
342
+ component's private `--_*` variable (`KUI-L020`), an override of a token a
343
+ typed prop sets (`KUI-L021`), and a hook class on a component's root
344
+ (`KUI-L022`); `eslint-plugin-kerfjs`'s `ui-component-ownership` reports
345
+ `KUI-L020` / `KUI-L021` in script. Both share the selector parsing in
346
+ `analyzer/selectors.mjs` with `check:css-ownership`, and
347
+ `check:css-ownership` fails when a component renders a Web Awesome tag the
348
+ catalog does not list, so `KUI-L019` keeps covering every tag a kerf component
349
+ renders. Each finding names the configuration to use and routes a missing
350
+ prop to a component-gap report (see [the analyzer guide](./ui-analyzer.md#component-ownership-kui-l019kui-l022)).
351
+
352
+ The composition catalog additionally requires `boundaries.rootClass` to be
236
353
  either one exact member of `publicClasses` or `null` when the entry has no
237
354
  rendered class root. Runtime geometry tooling uses this explicit field; array
238
355
  order never implies root ownership.
@@ -258,11 +375,19 @@ rows align that 18px visual with the first inherited text line. The row clips
258
375
  descendant painting to its rounded root so labels, status, and dormant trailing
259
376
  content cannot escape its visible boundary. Rows with descriptions grow enough
260
377
  to keep their owned two-line label stack readable; use `multiline` when the
261
- primary label should wrap rather than truncate.
262
-
263
- `DisclosureArrow` uses an 18px root-scaled visual by default. Override
264
- `--kui-disclosure-arrow-size` on the component or its containing scope when a
265
- consumer needs another size. Kerf `Select` uses a separate Web Awesome expand
378
+ primary label should wrap rather than truncate. A single-line row ends its
379
+ primary label and description with an ellipsis before the trailing status
380
+ slot, even when the label is one long word; a `multiline` row wraps instead,
381
+ breaking a word wider than the label column (a long component or file name)
382
+ rather than letting it run under the trailing slot. A string label in a
383
+ `multiline` row gets line-break opportunities at its camelCase and acronym
384
+ boundaries, so `QuickTicketComposer` wraps as `QuickTicket` / `Composer`
385
+ rather than mid-word; breaking anywhere is only the last resort for a single
386
+ word that is still too wide. The text and accessible name are unchanged. `ListActionRow` labels
387
+ follow the same single-line and `multiline` rules before the trailing action.
388
+
389
+ `DisclosureArrow` uses an 18px root-scaled visual by default. Pass its typed
390
+ `size` prop when a consumer needs another size. Kerf `Select` uses a separate Web Awesome expand
266
391
  glyph contract, `--kui-disclosure-icon-scale: .5`; changing one contract does
267
392
  not implicitly change the other. Direction changes take the shortest rotation
268
393
  path; a 180-degree closed-to-open tie uses counterclockwise rotation.
@@ -304,7 +429,9 @@ inset. `ToolbarControlGroup` publishes its derived radius to nested toolbar
304
429
  highlights concentric when the group switches between pill and rounded shapes.
305
430
 
306
431
  `ResizableRegion` owns the Hot Sheet 2 split treatment: a persistent 1px
307
- separator with a compact grip that appears on hover or keyboard focus. Override
432
+ separator with a compact grip that appears on hover or keyboard focus. The grip
433
+ is drawn centered on the separator line even though the pointer target is wider
434
+ than the line, so the handle never reads as offset into a pane. Override
308
435
  `--kui-resizable-region-separator-color`,
309
436
  `--kui-resizable-region-handle-color`, or
310
437
  `--kui-resizable-region-handle-active-color` on a region when its containing
@@ -341,9 +468,10 @@ and do not type-check there. Never exchange these property grammars. List rows e
341
468
  `className`, public tokens, and semantic props instead of unrestricted `style`
342
469
  declarations.
343
470
  `.kui-content` gives major children 24px vertical separation.
344
- `.kui-content-item` gives one child 8px inline margin, a real 1px border,
345
- 8px padding, and 12px corners; border and background may be transparent without
346
- changing geometry. `.kui-content-item--pill` selects the 22px radius.
471
+ `ContentItem` (`@kerfjs/ui/content-item`, rendering `.kui-content-item`) gives
472
+ one child 8px inline margin, a real 1px border, 8px padding, and 12px corners;
473
+ the border stays transparent unless `frame="framed"`, so framing never changes
474
+ geometry. `shape="pill"` selects the 22px radius.
347
475
 
348
476
  `ToolbarControlGroup` is the unit of toolbar organization, even for dormant
349
477
  text. Each group reserves `calc(2px + remify(42px))`, or 44px, with 8px between
@@ -357,13 +485,22 @@ group that replaces wider toolbar controls below the Toolbar's compact container
357
485
  breakpoint; do not hide the group with an application class. Reach for
358
486
  `wa-button` only when you need
359
487
  a Web Awesome feature; a popup menu is a `PopupMenu`, which renders its own
360
- trigger. For a compact mixed-content group, set `nestedDropdown`; a
488
+ trigger. Nothing wraps inside a group: an icon sits beside its label on one
489
+ row, and a group's controls never break onto a second line — the group sizes
490
+ to its content and the enclosing `Toolbar`'s responsive policy relocates whole
491
+ groups. For a compact mixed-content group, set `nestedDropdown`; a
361
492
  text-and-caret trigger grows to its intrinsic width while an icon-only trigger
362
493
  can remain square. A compact icon `<button>` is a 32px circle, so a selected
363
494
  compact segment never becomes an oval. An icon-only `Select` joins a group as
364
495
  one more segment with its siblings' inset, radius, hover, and focus ring; only a
365
496
  lone Select grows the group to its icon-and-caret pill. Set `menuInset` to configure the dropdown menu surface
366
- without application `::part(menu)` CSS. Compact mixed controls retain the standard
497
+ without application `::part(menu)` CSS; the default `standard` keeps each menu's
498
+ own inset (8px for a raw `wa-dropdown`, the Select listbox's 4px for a
499
+ `PopupMenu`), while `compact` and `list-zero` apply to every nested menu. A
500
+ `PopupMenu` and a `Select` draw one popup: the same caret that turns to face the
501
+ open popup, fade-in surface, surface inset, row height and padding, reserved
502
+ check column, current-row fill, and group titles, all read from one private
503
+ popup-choice contract in `foundation.css`. Compact mixed controls retain the standard
367
504
  item padding, omit an internal separator, and let the raised selected item paint
368
505
  over the outer border instead of shrinking to an inset highlight. The Web
369
506
  Awesome trigger's shadow base owns max-content sizing, so icons, localized text,
@@ -374,7 +511,12 @@ choose `responsive="stack"` with `responsiveAt="compact" | "narrow"`,
374
511
  `responsive="wrap"` for a heading whose title must stay whole, or
375
512
  `responsive="center-priority"` instead of selecting its zone classes from a
376
513
  parent stylesheet. No policy clips an action: the trailing zone, and a stacked
377
- center zone, wrap whole groups onto another row.
514
+ center zone, wrap whole groups onto another row. The center zone never
515
+ compresses below its content width, so when the leading identity, center, and
516
+ trailing zones share a row that is too narrow, the leading title is what gives
517
+ way: it truncates with an ellipsis (as a platform toolbar's title does) instead
518
+ of the center group painting over it. When everything fits, the center group
519
+ keeps its place, centered in the track between the leading and trailing zones.
378
520
  `ListHeader` similarly separates its dormant title and
379
521
  optional count or badge from its optional 44px action. Use the mutually
380
522
  exclusive `count`/`countLabel` pair for non-negative safe-integer section
@@ -400,6 +542,16 @@ padding + 24px icon + 8px gap) and 8px from the right edge for an icon-bearing
400
542
  row. Applications own the values, formatting, and whether an icon is decorative
401
543
  or meaningfully labeled.
402
544
 
545
+ A row follows the settings-style key/value priority: the value keeps its
546
+ content and the label gives way. The label and value are two content-sized
547
+ columns that share the row's free space equally, each stopping once its content
548
+ fits. A short value therefore stays whole on one line beside any label, and a
549
+ long label takes the remaining width, wrapping at its spaces and ending a word
550
+ wider than its column (a long component or file name) in an ellipsis before the
551
+ value rather than running under it. A short label keeps its width beside a
552
+ long value, which wraps; when both are long they split the row, so neither is
553
+ starved.
554
+
403
555
  ## Imports and side effects
404
556
 
405
557
  Every component has an explicit JS and CSS subpath. In CSS-aware browser builds,