@kerfjs/ui 5.0.0-beta.6 → 5.0.0-beta.61

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 (714) hide show
  1. package/README.md +494 -138
  2. package/ai/application-ui-diagnostic-ids-v1.json +109 -0
  3. package/ai/application-ui-profile-sync.cjs +529 -0
  4. package/ai/application-ui-profile.d.mts +1 -0
  5. package/ai/application-ui-profile.d.ts +102 -0
  6. package/ai/application-ui-profile.defaults.json +96 -0
  7. package/ai/application-ui-profile.mjs +626 -0
  8. package/ai/application-ui-profile.schema.json +130 -0
  9. package/ai/catalog-authoring.json +36 -0
  10. package/ai/catalog-authoring.schema.json +109 -0
  11. package/ai/compile-time-contracts-v1.json +149 -0
  12. package/ai/compile-time-contracts-v1.schema.json +52 -0
  13. package/ai/component-catalog-extension.schema.json +79 -0
  14. package/ai/component-catalog.json +4041 -591
  15. package/ai/component-catalog.schema.json +78 -1
  16. package/ai/component-class-owners.cjs +83 -0
  17. package/ai/component-composition-extension.d.ts +7 -0
  18. package/ai/component-composition-extension.schema.json +7 -0
  19. package/ai/component-composition-rules.json +524 -0
  20. package/ai/component-composition.d.ts +125 -0
  21. package/ai/component-composition.json +7074 -0
  22. package/ai/component-composition.schema.json +375 -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 +90 -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 +96 -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 +103 -0
  44. package/ai/components/loading-spinner.md +72 -0
  45. package/ai/components/lucide-icon.md +66 -0
  46. package/ai/components/nav-stack.md +103 -0
  47. package/ai/components/pane.md +100 -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 +112 -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 +112 -0
  70. package/ai/components/tab-scaffold.md +94 -0
  71. package/ai/components/tabs.md +95 -0
  72. package/ai/components/text.md +83 -0
  73. package/ai/components/token-search-field.md +103 -0
  74. package/ai/components/toolbar-control-group.md +102 -0
  75. package/ai/components/toolbar-text.md +78 -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 +114 -0
  149. package/ai/public-api-signatures-v1.md +2597 -190
  150. package/ai/skill.md +259 -65
  151. package/ai/webawesome-jsx-signatures-v1.md +9 -2
  152. package/analyzer/cli.mjs +49 -0
  153. package/analyzer/component-ownership.d.mts +56 -0
  154. package/analyzer/component-ownership.mjs +184 -0
  155. package/analyzer/index.d.mts +49 -0
  156. package/analyzer/index.mjs +1458 -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/dist/app-tab.d.ts +41 -4
  163. package/dist/app-tab.js +3 -1
  164. package/dist/badge.d.ts +52 -0
  165. package/dist/badge.js +3 -0
  166. package/dist/badge.js.map +1 -0
  167. package/dist/browser/app-tab.js +1 -0
  168. package/dist/browser/badge.js +3 -0
  169. package/dist/browser/catalog.js +25 -0
  170. package/dist/browser/chip.js +3 -0
  171. package/dist/browser/collapsible-panel.js +7 -0
  172. package/dist/browser/content-item.js +3 -0
  173. package/dist/browser/floating-toolbar.js +3 -0
  174. package/dist/browser/grid.js +3 -0
  175. package/dist/browser/list-action-row.js +5 -0
  176. package/dist/browser/list-header.js +8 -0
  177. package/dist/browser/list-inset-control.js +3 -0
  178. package/dist/browser/list-inset-text.js +3 -0
  179. package/dist/browser/list-item.js +5 -0
  180. package/dist/browser/list.js +3 -0
  181. package/dist/browser/{panel-header.js → nav-stack.js} +4 -2
  182. package/dist/browser/pane.js +3 -0
  183. package/dist/browser/popup-menu.js +3 -0
  184. package/dist/browser/row.js +3 -0
  185. package/dist/browser/select.js +2 -0
  186. package/dist/browser/skeleton.js +3 -0
  187. package/dist/browser/spacer.js +3 -0
  188. package/dist/browser/split-view.js +10 -0
  189. package/dist/browser/state-banner.js +2 -0
  190. package/dist/browser/sunken-panel.js +3 -0
  191. package/dist/browser/surface-scaffold.js +3 -0
  192. package/dist/browser/tab-scaffold.js +4 -0
  193. package/dist/browser/text.js +3 -0
  194. package/dist/browser/toolbar-text.js +1 -0
  195. package/dist/browser/value-table.js +1 -0
  196. package/dist/browser/workbench.js +10 -0
  197. package/dist/catalog-resources.d.ts +46 -0
  198. package/dist/catalog-resources.js +22 -0
  199. package/dist/catalog-resources.js.map +1 -0
  200. package/dist/catalog.d.ts +90 -0
  201. package/dist/catalog.js +501 -0
  202. package/dist/catalog.js.map +1 -0
  203. package/dist/chip.d.ts +29 -0
  204. package/dist/chip.js +3 -0
  205. package/dist/chip.js.map +1 -0
  206. package/dist/chunk-2G2ZJQYK.js +152 -0
  207. package/dist/chunk-2G2ZJQYK.js.map +1 -0
  208. package/dist/chunk-3SXMEK3B.js +43 -0
  209. package/dist/chunk-3SXMEK3B.js.map +1 -0
  210. package/dist/{chunk-W2FK7ZNY.js → chunk-4R777DUZ.js} +10 -2
  211. package/dist/chunk-4R777DUZ.js.map +1 -0
  212. package/dist/chunk-4SQK27MR.js +202 -0
  213. package/dist/chunk-4SQK27MR.js.map +1 -0
  214. package/dist/chunk-5I7QGQVT.js +24 -0
  215. package/dist/chunk-5I7QGQVT.js.map +1 -0
  216. package/dist/chunk-5PESG2VP.js +115 -0
  217. package/dist/chunk-5PESG2VP.js.map +1 -0
  218. package/dist/chunk-5Q3N6EV7.js +156 -0
  219. package/dist/chunk-5Q3N6EV7.js.map +1 -0
  220. package/dist/chunk-6ZXOQEAN.js +27 -0
  221. package/dist/chunk-6ZXOQEAN.js.map +1 -0
  222. package/dist/chunk-7JUBXOIV.js +103 -0
  223. package/dist/chunk-7JUBXOIV.js.map +1 -0
  224. package/dist/chunk-A3CKOW2R.js +622 -0
  225. package/dist/chunk-A3CKOW2R.js.map +1 -0
  226. package/dist/chunk-AHEG27M7.js +66 -0
  227. package/dist/chunk-AHEG27M7.js.map +1 -0
  228. package/dist/chunk-AUKT3KMG.js +37 -0
  229. package/dist/chunk-AUKT3KMG.js.map +1 -0
  230. package/dist/chunk-AYUHMAI6.js +48 -0
  231. package/dist/chunk-AYUHMAI6.js.map +1 -0
  232. package/dist/chunk-BFPBS5Y4.js +250 -0
  233. package/dist/chunk-BFPBS5Y4.js.map +1 -0
  234. package/dist/{chunk-MQIZAD4A.js → chunk-C4OYOKWX.js} +138 -22
  235. package/dist/chunk-C4OYOKWX.js.map +1 -0
  236. package/dist/chunk-DG6G5EPF.js +35 -0
  237. package/dist/chunk-DG6G5EPF.js.map +1 -0
  238. package/dist/chunk-E36EVCKG.js +34 -0
  239. package/dist/chunk-E36EVCKG.js.map +1 -0
  240. package/dist/chunk-EAC4CDY7.js +57 -0
  241. package/dist/chunk-EAC4CDY7.js.map +1 -0
  242. package/dist/chunk-EZVNC4J6.js +104 -0
  243. package/dist/chunk-EZVNC4J6.js.map +1 -0
  244. package/dist/chunk-F4QMLOXJ.js +135 -0
  245. package/dist/chunk-F4QMLOXJ.js.map +1 -0
  246. package/dist/chunk-GLDWRCAM.js +49 -0
  247. package/dist/chunk-GLDWRCAM.js.map +1 -0
  248. package/dist/chunk-I3Q7KKYM.js +33 -0
  249. package/dist/chunk-I3Q7KKYM.js.map +1 -0
  250. package/dist/chunk-IA7TMD4Y.js +288 -0
  251. package/dist/chunk-IA7TMD4Y.js.map +1 -0
  252. package/dist/chunk-JCV4GXWB.js +249 -0
  253. package/dist/chunk-JCV4GXWB.js.map +1 -0
  254. package/dist/chunk-K47P7QZC.js +17 -0
  255. package/dist/chunk-K47P7QZC.js.map +1 -0
  256. package/dist/chunk-KLJKU6ZL.js +109 -0
  257. package/dist/chunk-KLJKU6ZL.js.map +1 -0
  258. package/dist/{chunk-56RJXPHG.js → chunk-KROD7KZK.js} +7 -4
  259. package/dist/chunk-KROD7KZK.js.map +1 -0
  260. package/dist/chunk-MA73TA6D.js +42 -0
  261. package/dist/chunk-MA73TA6D.js.map +1 -0
  262. package/dist/chunk-MERWRTBG.js +45 -0
  263. package/dist/chunk-MERWRTBG.js.map +1 -0
  264. package/dist/chunk-MEY33VWB.js +44 -0
  265. package/dist/chunk-MEY33VWB.js.map +1 -0
  266. package/dist/chunk-MP2GDBQZ.js +50 -0
  267. package/dist/chunk-MP2GDBQZ.js.map +1 -0
  268. package/dist/chunk-N3GKMPDW.js +51 -0
  269. package/dist/chunk-N3GKMPDW.js.map +1 -0
  270. package/dist/chunk-NAPE7WUS.js +75 -0
  271. package/dist/chunk-NAPE7WUS.js.map +1 -0
  272. package/dist/chunk-NN6GYOA2.js +47 -0
  273. package/dist/chunk-NN6GYOA2.js.map +1 -0
  274. package/dist/chunk-NNMLEDMD.js +399 -0
  275. package/dist/chunk-NNMLEDMD.js.map +1 -0
  276. package/dist/chunk-NYL63PSD.js +95 -0
  277. package/dist/chunk-NYL63PSD.js.map +1 -0
  278. package/dist/chunk-P7D3EMXM.js +52 -0
  279. package/dist/chunk-P7D3EMXM.js.map +1 -0
  280. package/dist/chunk-PSHUSWQH.js +18 -0
  281. package/dist/chunk-PSHUSWQH.js.map +1 -0
  282. package/dist/chunk-Q6YU3BT7.js +138 -0
  283. package/dist/chunk-Q6YU3BT7.js.map +1 -0
  284. package/dist/chunk-RRB26JRJ.js +247 -0
  285. package/dist/chunk-RRB26JRJ.js.map +1 -0
  286. package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
  287. package/dist/chunk-SRSJO5QE.js.map +1 -0
  288. package/dist/chunk-SWVW56CV.js +188 -0
  289. package/dist/chunk-SWVW56CV.js.map +1 -0
  290. package/dist/chunk-TEYARRAK.js +216 -0
  291. package/dist/chunk-TEYARRAK.js.map +1 -0
  292. package/dist/chunk-UCKKT6KO.js +71 -0
  293. package/dist/chunk-UCKKT6KO.js.map +1 -0
  294. package/dist/chunk-UIDKY4UB.js +14 -0
  295. package/dist/chunk-UIDKY4UB.js.map +1 -0
  296. package/dist/chunk-VCBTX62E.js +135 -0
  297. package/dist/chunk-VCBTX62E.js.map +1 -0
  298. package/dist/chunk-VZOFZPSO.js +71 -0
  299. package/dist/chunk-VZOFZPSO.js.map +1 -0
  300. package/dist/{chunk-TRNBHPNW.js → chunk-X5QSICJ3.js} +13 -7
  301. package/dist/chunk-X5QSICJ3.js.map +1 -0
  302. package/dist/chunk-Y74NWGQW.js +418 -0
  303. package/dist/chunk-Y74NWGQW.js.map +1 -0
  304. package/dist/chunk-ZLWQZUGF.js +27 -0
  305. package/dist/chunk-ZLWQZUGF.js.map +1 -0
  306. package/dist/collapsible-panel.d.ts +122 -0
  307. package/dist/collapsible-panel.js +115 -0
  308. package/dist/collapsible-panel.js.map +1 -0
  309. package/dist/content-item.d.ts +46 -0
  310. package/dist/content-item.js +4 -0
  311. package/dist/content-item.js.map +1 -0
  312. package/dist/css-values.d.ts +107 -0
  313. package/dist/css-values.js +3 -0
  314. package/dist/css-values.js.map +1 -0
  315. package/dist/device-class.js +33 -5
  316. package/dist/device-class.js.map +1 -1
  317. package/dist/disclosure-arrow.d.ts +6 -1
  318. package/dist/disclosure-arrow.js +1 -1
  319. package/dist/empty-state.d.ts +5 -2
  320. package/dist/empty-state.js +1 -1
  321. package/dist/flex-alignment-4ms8ZbV8.d.ts +5 -0
  322. package/dist/floating-toolbar.d.ts +51 -0
  323. package/dist/floating-toolbar.js +3 -0
  324. package/dist/floating-toolbar.js.map +1 -0
  325. package/dist/grid.d.ts +42 -0
  326. package/dist/grid.js +5 -0
  327. package/dist/grid.js.map +1 -0
  328. package/dist/help-tags-register.d.ts +13 -0
  329. package/dist/help-tags-register.js +9 -0
  330. package/dist/help-tags-register.js.map +1 -0
  331. package/dist/index.d.ts +35 -14
  332. package/dist/index.js +43 -22
  333. package/dist/list-action-row.d.ts +64 -0
  334. package/dist/list-action-row.js +8 -0
  335. package/dist/list-action-row.js.map +1 -0
  336. package/dist/list-header.d.ts +99 -0
  337. package/dist/list-header.js +10 -0
  338. package/dist/list-header.js.map +1 -0
  339. package/dist/list-inset-control.d.ts +22 -0
  340. package/dist/list-inset-control.js +3 -0
  341. package/dist/list-inset-control.js.map +1 -0
  342. package/dist/list-inset-text.d.ts +30 -0
  343. package/dist/list-inset-text.js +4 -0
  344. package/dist/list-inset-text.js.map +1 -0
  345. package/dist/list-item.d.ts +62 -0
  346. package/dist/list-item.js +8 -0
  347. package/dist/list-item.js.map +1 -0
  348. package/dist/list.d.ts +59 -0
  349. package/dist/list.js +6 -0
  350. package/dist/list.js.map +1 -0
  351. package/dist/loading-spinner.d.ts +3 -1
  352. package/dist/loading-spinner.js +1 -1
  353. package/dist/lucide-icon.d.ts +3 -1
  354. package/dist/lucide-icon.js +1 -1
  355. package/dist/nav-stack.d.ts +60 -10
  356. package/dist/nav-stack.js +6 -1
  357. package/dist/pane.d.ts +102 -0
  358. package/dist/pane.js +4 -0
  359. package/dist/pane.js.map +1 -0
  360. package/dist/panel-toolbar-DqwtBxQL.d.ts +63 -0
  361. package/dist/popup-menu-register.d.ts +9 -0
  362. package/dist/popup-menu-register.js +31 -0
  363. package/dist/popup-menu-register.js.map +1 -0
  364. package/dist/popup-menu.d.ts +99 -0
  365. package/dist/popup-menu.js +3 -0
  366. package/dist/popup-menu.js.map +1 -0
  367. package/dist/resizable-region.d.ts +32 -3
  368. package/dist/resizable-region.js +1 -1
  369. package/dist/row.d.ts +48 -0
  370. package/dist/row.js +6 -0
  371. package/dist/row.js.map +1 -0
  372. package/dist/segmented-control.d.ts +13 -8
  373. package/dist/segmented-control.js +1 -1
  374. package/dist/select-register.d.ts +5 -1
  375. package/dist/select-register.js +243 -2
  376. package/dist/select-register.js.map +1 -1
  377. package/dist/select.d.ts +101 -8
  378. package/dist/select.js +4 -1
  379. package/dist/semantic-content-BbzjvSu9.d.ts +14 -0
  380. package/dist/sides-BPSWde0A.d.ts +4 -0
  381. package/dist/skeleton.d.ts +31 -0
  382. package/dist/skeleton.js +4 -0
  383. package/dist/skeleton.js.map +1 -0
  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 +19 -5
  391. package/dist/state-banner.js +4 -1
  392. package/dist/styles/app-tab.css +104 -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 +164 -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 +118 -0
  400. package/dist/styles/collapsible-panel.css +575 -0
  401. package/dist/styles/content-item.css +30 -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 +28 -0
  406. package/dist/styles/layout.css +3 -41
  407. package/dist/styles/list-action-row.css +257 -0
  408. package/dist/styles/list-header.css +228 -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 +245 -0
  412. package/dist/styles/list.css +133 -0
  413. package/dist/styles/nav-stack.css +158 -50
  414. package/dist/styles/pane.css +229 -0
  415. package/dist/styles/popup-menu.css +271 -0
  416. package/dist/styles/resizable-region.css +429 -4
  417. package/dist/styles/row.css +111 -0
  418. package/dist/styles/segmented-control.css +33 -9
  419. package/dist/styles/select.css +262 -9
  420. package/dist/styles/skeleton.css +92 -0
  421. package/dist/styles/spacer.css +11 -0
  422. package/dist/styles/split-view.css +108 -3
  423. package/dist/styles/state-banner.css +94 -19
  424. package/dist/styles/styles.css +14 -4
  425. package/dist/styles/sunken-panel.css +22 -0
  426. package/dist/styles/surface-scaffold.css +56 -0
  427. package/dist/styles/tab-bar.css +132 -9
  428. package/dist/styles/tab-scaffold.css +113 -3
  429. package/dist/styles/text.css +65 -0
  430. package/dist/styles/token-search-field.css +49 -43
  431. package/dist/styles/toolbar-control-group.css +465 -28
  432. package/dist/styles/toolbar-text.css +88 -4
  433. package/dist/styles/toolbar.css +322 -11
  434. package/dist/styles/value-table.css +34 -4
  435. package/dist/styles/webawesome.css +348 -10
  436. package/dist/styles/workbench.css +828 -7
  437. package/dist/sunken-panel.d.ts +22 -0
  438. package/dist/sunken-panel.js +3 -0
  439. package/dist/sunken-panel.js.map +1 -0
  440. package/dist/surface-scaffold.d.ts +30 -0
  441. package/dist/surface-scaffold.js +3 -0
  442. package/dist/surface-scaffold.js.map +1 -0
  443. package/dist/tab-bar.d.ts +31 -6
  444. package/dist/tab-bar.js +1 -1
  445. package/dist/tab-scaffold.d.ts +54 -7
  446. package/dist/tab-scaffold.js +82 -9
  447. package/dist/tab-scaffold.js.map +1 -1
  448. package/dist/text.d.ts +38 -0
  449. package/dist/text.js +3 -0
  450. package/dist/text.js.map +1 -0
  451. package/dist/token-search-field-DvgFLhLL.d.ts +130 -0
  452. package/dist/token-search-field.d.ts +3 -43
  453. package/dist/token-search-field.js +1 -1
  454. package/dist/token-search-model.d.ts +3 -0
  455. package/dist/token-search-model.js +3 -0
  456. package/dist/token-search-model.js.map +1 -0
  457. package/dist/toolbar-control-group.d.ts +65 -7
  458. package/dist/toolbar-control-group.js +1 -1
  459. package/dist/toolbar-text.d.ts +37 -4
  460. package/dist/toolbar-text.js +3 -1
  461. package/dist/toolbar.d.ts +56 -7
  462. package/dist/toolbar.js +1 -1
  463. package/dist/types-BuHELdXR.d.ts +117 -0
  464. package/dist/value-table.d.ts +13 -3
  465. package/dist/value-table.js +3 -1
  466. package/dist/webawesome.d.ts +8 -1
  467. package/dist/wire-catalog.d.ts +82 -0
  468. package/dist/wire-catalog.js +327 -0
  469. package/dist/wire-catalog.js.map +1 -0
  470. package/dist/wire-nav-stack.d.ts +4 -1
  471. package/dist/wire-nav-stack.js +147 -7
  472. package/dist/wire-nav-stack.js.map +1 -1
  473. package/dist/wire-resizable-regions.d.ts +2 -1
  474. package/dist/wire-resizable-regions.js +2 -1
  475. package/dist/wire-scroll-dividers.d.ts +69 -0
  476. package/dist/wire-scroll-dividers.js +3 -0
  477. package/dist/wire-scroll-dividers.js.map +1 -0
  478. package/dist/wire-sidebar.d.ts +63 -0
  479. package/dist/wire-sidebar.js +231 -0
  480. package/dist/wire-sidebar.js.map +1 -0
  481. package/dist/wire-tab-bars.d.ts +19 -2
  482. package/dist/wire-tab-bars.js +1 -1
  483. package/dist/wire-tab-scaffold.js +9 -4
  484. package/dist/wire-tab-scaffold.js.map +1 -1
  485. package/dist/wire-token-search-fields.d.ts +65 -3
  486. package/dist/wire-token-search-fields.js +1 -1
  487. package/dist/wire-workbench.d.ts +109 -0
  488. package/dist/wire-workbench.js +6 -0
  489. package/dist/wire-workbench.js.map +1 -0
  490. package/dist/workbench.d.ts +218 -7
  491. package/dist/workbench.js +13 -15
  492. package/dist/workbench.js.map +1 -1
  493. package/docs/accessibility.md +413 -23
  494. package/docs/app-layouts.md +106 -8
  495. package/docs/catalog.md +440 -0
  496. package/docs/collapsible-panel.md +363 -0
  497. package/docs/component-contract.md +560 -52
  498. package/docs/component-integration.md +75 -0
  499. package/docs/component-selection.md +421 -89
  500. package/docs/design/templates/empty-state/filtered-dark.svg +1 -0
  501. package/docs/design/templates/empty-state/filtered.svg +1 -0
  502. package/docs/design/templates/empty-state/with-action-dark.svg +1 -0
  503. package/docs/design/templates/empty-state/with-action.svg +1 -0
  504. package/docs/design/templates/empty-state-dark.svg +1 -0
  505. package/docs/design/templates/empty-state.svg +1 -0
  506. package/docs/design/templates/list/compact-dark.svg +1 -0
  507. package/docs/design/templates/list/compact.svg +1 -0
  508. package/docs/design/templates/list/stack-dark.svg +1 -0
  509. package/docs/design/templates/list/stack.svg +1 -0
  510. package/docs/design/templates/list-action-row/default-dark.svg +1 -0
  511. package/docs/design/templates/list-action-row/default.svg +1 -0
  512. package/docs/design/templates/list-action-row/selected-dark.svg +1 -0
  513. package/docs/design/templates/list-action-row/selected.svg +1 -0
  514. package/docs/design/templates/list-action-row-dark.svg +1 -0
  515. package/docs/design/templates/list-action-row.svg +1 -0
  516. package/docs/design/templates/list-dark.svg +1 -0
  517. package/docs/design/templates/list-header/action-dark.svg +1 -0
  518. package/docs/design/templates/list-header/action.svg +1 -0
  519. package/docs/design/templates/list-header/count-dark.svg +1 -0
  520. package/docs/design/templates/list-header/count.svg +1 -0
  521. package/docs/design/templates/list-header/inline-action-dark.svg +1 -0
  522. package/docs/design/templates/list-header/inline-action.svg +1 -0
  523. package/docs/design/templates/list-header/toggle-collapsed-dark.svg +1 -0
  524. package/docs/design/templates/list-header/toggle-collapsed.svg +1 -0
  525. package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -0
  526. package/docs/design/templates/list-header/toggle-expanded.svg +1 -0
  527. package/docs/design/templates/list-header-dark.svg +1 -0
  528. package/docs/design/templates/list-header.svg +1 -0
  529. package/docs/design/templates/list-item/default-dark.svg +1 -0
  530. package/docs/design/templates/list-item/default.svg +1 -0
  531. package/docs/design/templates/list-item/multiline-dark.svg +1 -0
  532. package/docs/design/templates/list-item/multiline.svg +1 -0
  533. package/docs/design/templates/list-item/selected-dark.svg +1 -0
  534. package/docs/design/templates/list-item/selected.svg +1 -0
  535. package/docs/design/templates/list-item/trailing-dark.svg +1 -0
  536. package/docs/design/templates/list-item/trailing.svg +1 -0
  537. package/docs/design/templates/list-item-dark.svg +1 -0
  538. package/docs/design/templates/list-item.svg +1 -0
  539. package/docs/design/templates/list.svg +1 -0
  540. package/docs/design/templates/segmented-control/equal-dark.svg +1 -0
  541. package/docs/design/templates/segmented-control/equal.svg +1 -0
  542. package/docs/design/templates/segmented-control/pill-small-dark.svg +1 -0
  543. package/docs/design/templates/segmented-control/pill-small.svg +1 -0
  544. package/docs/design/templates/segmented-control-dark.svg +1 -0
  545. package/docs/design/templates/segmented-control.svg +1 -0
  546. package/docs/design/templates/skeleton/avatar-dark.svg +1 -0
  547. package/docs/design/templates/skeleton/avatar.svg +1 -0
  548. package/docs/design/templates/skeleton/block-dark.svg +1 -0
  549. package/docs/design/templates/skeleton/block.svg +1 -0
  550. package/docs/design/templates/skeleton/lines-dark.svg +1 -0
  551. package/docs/design/templates/skeleton/lines.svg +1 -0
  552. package/docs/design/templates/skeleton-dark.svg +1 -0
  553. package/docs/design/templates/skeleton.svg +1 -0
  554. package/docs/design/templates/state-banner/danger-dark.svg +1 -0
  555. package/docs/design/templates/state-banner/danger.svg +1 -0
  556. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -0
  557. package/docs/design/templates/state-banner/info-badge.svg +1 -0
  558. package/docs/design/templates/state-banner/info-dark.svg +1 -0
  559. package/docs/design/templates/state-banner/info.svg +1 -0
  560. package/docs/design/templates/state-banner/success-dark.svg +1 -0
  561. package/docs/design/templates/state-banner/success.svg +1 -0
  562. package/docs/design/templates/state-banner/warning-dark.svg +1 -0
  563. package/docs/design/templates/state-banner/warning.svg +1 -0
  564. package/docs/design/templates/state-banner-dark.svg +1 -0
  565. package/docs/design/templates/state-banner.svg +1 -0
  566. package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -0
  567. package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -0
  568. package/docs/design/templates/tab-bar-dark.svg +1 -0
  569. package/docs/design/templates/tab-bar.svg +1 -0
  570. package/docs/design/templates/token-search-field/empty-dark.svg +1 -0
  571. package/docs/design/templates/token-search-field/empty.svg +1 -0
  572. package/docs/design/templates/token-search-field/tokens-dark.svg +1 -0
  573. package/docs/design/templates/token-search-field/tokens.svg +1 -0
  574. package/docs/design/templates/token-search-field-dark.svg +1 -0
  575. package/docs/design/templates/token-search-field.svg +1 -0
  576. package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -0
  577. package/docs/design/templates/toolbar/title-and-actions.svg +1 -0
  578. package/docs/design/templates/toolbar-control-group/borderless-single-dark.svg +1 -0
  579. package/docs/design/templates/toolbar-control-group/borderless-single.svg +1 -0
  580. package/docs/design/templates/toolbar-control-group/icon-buttons-dark.svg +1 -0
  581. package/docs/design/templates/toolbar-control-group/icon-buttons.svg +1 -0
  582. package/docs/design/templates/toolbar-control-group/push-buttons-dark.svg +1 -0
  583. package/docs/design/templates/toolbar-control-group/push-buttons.svg +1 -0
  584. package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -0
  585. package/docs/design/templates/toolbar-control-group/with-text.svg +1 -0
  586. package/docs/design/templates/toolbar-control-group-dark.svg +1 -0
  587. package/docs/design/templates/toolbar-control-group.svg +1 -0
  588. package/docs/design/templates/toolbar-dark.svg +1 -0
  589. package/docs/design/templates/toolbar-text/default-dark.svg +1 -0
  590. package/docs/design/templates/toolbar-text/default.svg +1 -0
  591. package/docs/design/templates/toolbar-text/large-dark.svg +1 -0
  592. package/docs/design/templates/toolbar-text/large.svg +1 -0
  593. package/docs/design/templates/toolbar-text/small-dark.svg +1 -0
  594. package/docs/design/templates/toolbar-text/small.svg +1 -0
  595. package/docs/design/templates/toolbar-text-dark.svg +1 -0
  596. package/docs/design/templates/toolbar-text.svg +1 -0
  597. package/docs/design/templates/toolbar.svg +1 -0
  598. package/docs/design/templates/value-table/details-dark.svg +1 -0
  599. package/docs/design/templates/value-table/details.svg +1 -0
  600. package/docs/design/templates/value-table-dark.svg +1 -0
  601. package/docs/design/templates/value-table.svg +1 -0
  602. package/docs/design/templates.md +138 -0
  603. package/docs/design-philosophy.md +48 -20
  604. package/docs/device-class.md +10 -9
  605. package/docs/document-baseline.md +38 -0
  606. package/docs/examples/application-ui-profile.json +60 -0
  607. package/docs/examples/command-palette-adapter.tsx +69 -17
  608. package/docs/examples/component-catalog-extension.json +45 -0
  609. package/docs/examples/component-composition-extension.json +80 -0
  610. package/docs/layout.md +409 -59
  611. package/docs/nav-stack.md +126 -14
  612. package/docs/recipes.md +137 -54
  613. package/docs/split-view.md +69 -6
  614. package/docs/sunken-panel.md +58 -0
  615. package/docs/surface-scaffold.md +25 -0
  616. package/docs/tab-scaffold.md +94 -10
  617. package/docs/type-contracts.md +134 -0
  618. package/docs/ui-analyzer.md +306 -0
  619. package/docs/ui-doctor.md +107 -0
  620. package/docs/ui-evaluator.md +139 -0
  621. package/docs/ux-demo.md +40 -16
  622. package/docs/webawesome-theme.md +175 -16
  623. package/docs/workbench.md +534 -12
  624. package/doctor/cli.mjs +115 -0
  625. package/doctor/config.schema.json +68 -0
  626. package/doctor/eslint-diagnostics.d.mts +24 -0
  627. package/doctor/eslint-diagnostics.mjs +24 -0
  628. package/doctor/index.d.mts +116 -0
  629. package/doctor/index.mjs +1277 -0
  630. package/doctor/report.schema.json +118 -0
  631. package/evaluator/cli.mjs +89 -0
  632. package/evaluator/index.d.mts +90 -0
  633. package/evaluator/index.mjs +1203 -0
  634. package/evaluator/report.schema.json +152 -0
  635. package/llms.txt +423 -42
  636. package/package.json +241 -37
  637. package/traversal-exclusions.mjs +27 -0
  638. package/ux-demo/recipes/app-shell.tsx +205 -17
  639. package/ux-demo/recipes/collapsible-sidebar.tsx +260 -0
  640. package/ux-demo/recipes/compact-toolbar.tsx +135 -14
  641. package/ux-demo/recipes/composer-form.tsx +133 -21
  642. package/ux-demo/recipes/list-detail-dialog.tsx +282 -0
  643. package/ux-demo/recipes/list-workspace-states.tsx +183 -11
  644. package/ux-demo/recipes/loaders.ts +15 -5
  645. package/ux-demo/recipes/loading-inspector.tsx +204 -0
  646. package/ux-demo/recipes/mount-recipe.ts +28 -10
  647. package/ux-demo/recipes/navigation-sidebar.tsx +139 -13
  648. package/ux-demo/recipes/navigation-stack.tsx +79 -24
  649. package/ux-demo/recipes/types.ts +23 -2
  650. package/ux-demo/recipes/workspace-header.tsx +86 -5
  651. package/dist/browser/menu-action-row.js +0 -3
  652. package/dist/browser/menu-header.js +0 -5
  653. package/dist/browser/menu-item.js +0 -3
  654. package/dist/chunk-24Z2XE6C.js +0 -10
  655. package/dist/chunk-24Z2XE6C.js.map +0 -1
  656. package/dist/chunk-2RJBFNB6.js +0 -172
  657. package/dist/chunk-2RJBFNB6.js.map +0 -1
  658. package/dist/chunk-55DATV3A.js +0 -10
  659. package/dist/chunk-55DATV3A.js.map +0 -1
  660. package/dist/chunk-56RJXPHG.js.map +0 -1
  661. package/dist/chunk-7BR3DO2A.js.map +0 -1
  662. package/dist/chunk-7LDCTU7D.js +0 -134
  663. package/dist/chunk-7LDCTU7D.js.map +0 -1
  664. package/dist/chunk-AQNKJRFH.js +0 -79
  665. package/dist/chunk-AQNKJRFH.js.map +0 -1
  666. package/dist/chunk-CTQKI2XL.js +0 -28
  667. package/dist/chunk-CTQKI2XL.js.map +0 -1
  668. package/dist/chunk-DAFFDO33.js +0 -14
  669. package/dist/chunk-DAFFDO33.js.map +0 -1
  670. package/dist/chunk-EGHL5S4P.js +0 -33
  671. package/dist/chunk-EGHL5S4P.js.map +0 -1
  672. package/dist/chunk-KZKSBUKC.js +0 -19
  673. package/dist/chunk-KZKSBUKC.js.map +0 -1
  674. package/dist/chunk-M5JRI6MN.js +0 -27
  675. package/dist/chunk-M5JRI6MN.js.map +0 -1
  676. package/dist/chunk-MBR3TYNL.js +0 -14
  677. package/dist/chunk-MBR3TYNL.js.map +0 -1
  678. package/dist/chunk-MFKMHK5W.js +0 -10
  679. package/dist/chunk-MFKMHK5W.js.map +0 -1
  680. package/dist/chunk-MQIZAD4A.js.map +0 -1
  681. package/dist/chunk-NPPD2A6O.js +0 -40
  682. package/dist/chunk-NPPD2A6O.js.map +0 -1
  683. package/dist/chunk-R6JHHBKQ.js +0 -19
  684. package/dist/chunk-R6JHHBKQ.js.map +0 -1
  685. package/dist/chunk-RBTVBGRD.js +0 -23
  686. package/dist/chunk-RBTVBGRD.js.map +0 -1
  687. package/dist/chunk-S3TPM2LP.js +0 -23
  688. package/dist/chunk-S3TPM2LP.js.map +0 -1
  689. package/dist/chunk-TRNBHPNW.js.map +0 -1
  690. package/dist/chunk-VHW5YNIB.js +0 -17
  691. package/dist/chunk-VHW5YNIB.js.map +0 -1
  692. package/dist/chunk-W2FK7ZNY.js.map +0 -1
  693. package/dist/chunk-WVPYVDXY.js +0 -15
  694. package/dist/chunk-WVPYVDXY.js.map +0 -1
  695. package/dist/chunk-XZXRLY5Q.js +0 -33
  696. package/dist/chunk-XZXRLY5Q.js.map +0 -1
  697. package/dist/menu-action-row.d.ts +0 -50
  698. package/dist/menu-action-row.js +0 -4
  699. package/dist/menu-action-row.js.map +0 -1
  700. package/dist/menu-header.d.ts +0 -41
  701. package/dist/menu-header.js +0 -6
  702. package/dist/menu-header.js.map +0 -1
  703. package/dist/menu-item.d.ts +0 -31
  704. package/dist/menu-item.js +0 -4
  705. package/dist/menu-item.js.map +0 -1
  706. package/dist/panel-header.d.ts +0 -26
  707. package/dist/panel-header.js +0 -6
  708. package/dist/panel-header.js.map +0 -1
  709. package/dist/styles/menu-action-row.css +0 -160
  710. package/dist/styles/menu-header.css +0 -160
  711. package/dist/styles/menu-item.css +0 -123
  712. package/dist/styles/panel-header.css +0 -59
  713. package/ux-demo/recipes/master-detail-dialog.tsx +0 -45
  714. package/ux-demo/recipes/recipes.css +0 -355
package/docs/nav-stack.md CHANGED
@@ -5,14 +5,19 @@ and out over one another while the top chrome settles. A **single-pane layout is
5
5
  a `NavStack` with one entry**. It is one of the opt-in app layouts (see
6
6
  [`../../docs/23-app-layouts.md`](../../docs/23-app-layouts.md)).
7
7
 
8
- Import the component and its companion stylesheet:
8
+ Import the component and its wiring helper:
9
9
 
10
10
  ```ts
11
- import { NavStack, type NavStackView } from '@kerfjs/ui/nav-stack';
12
- import { wireNavStack } from '@kerfjs/ui/wire-nav-stack';
13
- import '@kerfjs/ui/nav-stack.css';
11
+ import { NavStack, type NavStackView } from "@kerfjs/ui/nav-stack";
12
+ import { wireNavStack } from "@kerfjs/ui/wire-nav-stack";
14
13
  ```
15
14
 
15
+ In a browser bundler that honors the `browser` export condition (Vite, esbuild, and
16
+ webpack do by default), the import above also
17
+ loads NavStack's stylesheet and those of the components it renders internally
18
+ (`Toolbar`, `ToolbarControlGroup`, `ToolbarText`, `LucideIcon`). Without that condition, import the manual stylesheets instead:
19
+ `@kerfjs/ui/nav-stack.css` plus those components' CSS, or `@kerfjs/ui/styles.css`.
20
+
16
21
  ## State lives in the app
17
22
 
18
23
  Like every `@kerfjs/ui` component, `NavStack` is declarative: the app owns the
@@ -20,28 +25,135 @@ stack as a `signal<NavStackView[]>`, `NavStack({ views })` renders it, and
20
25
  `wireNavStack` animates the transitions.
21
26
 
22
27
  ```tsx
23
- const views = signal<NavStackView[]>([{ key: 'inbox', title: 'Inbox', content: <InboxView /> }]);
28
+ const views = signal<NavStackView[]>([
29
+ {
30
+ key: "inbox",
31
+ title: "Inbox",
32
+ content: <InboxView />,
33
+ bottomToolbar: <InboxStatus />,
34
+ },
35
+ ]);
24
36
 
25
37
  // render inside mount():
26
38
  <NavStack id="mail" label="Mail" views={views.value} />;
27
39
 
28
40
  // once, after first render:
29
- const dispose = wireNavStack(root, { onBack: () => { views.value = views.value.slice(0, -1); } });
41
+ const dispose = wireNavStack(root, {
42
+ onBack: () => {
43
+ views.value = views.value.slice(0, -1);
44
+ },
45
+ });
30
46
 
31
47
  // push / pop by editing the signal:
32
- views.value = [...views.value, { key: id, title: 'Message', content: <MessageView id={id} /> }];
48
+ views.value = [
49
+ ...views.value,
50
+ { key: id, title: "Message", content: <MessageView id={id} /> },
51
+ ];
33
52
  ```
34
53
 
35
54
  `NavStack` renders every entry stacked, the last one active and the rest kept
36
- mounted (so their DOM state and focus survive) but hidden. Each entry carries a
37
- `key` (stable identity), `content`, an optional `title`, and optional per-view
38
- `toolbar` actions. The back control appears automatically once the stack has more
39
- than one entry; `wireNavStack`'s `onBack` is where the app pops its own signal.
55
+ mounted (so their DOM state survives) but hidden. Each entry carries a
56
+ `key` (stable identity), `content`, an optional `title`, optional per-view
57
+ `leading`, `center`, and trailing `toolbar` groups for the top toolbar, and an
58
+ optional per-view `bottomToolbar`. The component-level
59
+ `bottomToolbar` remains a persistent fallback for views that do not provide one.
60
+ The back control appears automatically once the stack has more than one entry;
61
+ `wireNavStack`'s `onBack` is where the app pops its own signal.
62
+
63
+ ## The top toolbar
64
+
65
+ The top chrome is a real `Toolbar`, so it follows the same zone,
66
+ group, and responsive rules as every other toolbar. Its leading zone holds the
67
+ back control (a borderless `ToolbarControlGroup`, shown once the stack has
68
+ depth), then the active view's `leading` groups, then the view's `title` as a
69
+ `ToolbarText`. The view's `center` fills the center zone and its `toolbar`
70
+ fills the trailing zone. Give each zone `ToolbarControlGroup`s or `ToolbarText`,
71
+ as in any toolbar.
72
+
73
+ Configure the toolbar with `toolbarConfig` instead of styling it:
74
+
75
+ ```tsx
76
+ <NavStack
77
+ id="mail"
78
+ label="Mail"
79
+ views={views.value}
80
+ backText={previousTitle}
81
+ toolbarConfig={{
82
+ headingLevel: 1,
83
+ titleSize: "xlarge",
84
+ dividerSides: "b",
85
+ responsive: "wrap",
86
+ }}
87
+ />
88
+ ```
89
+
90
+ - `toolbarConfig` forwards the `Toolbar` configuration (`dividerSides`,
91
+ `centerAlign`, `responsive`, `responsiveAt`, `safeAreaEdges`) and adds
92
+ `label` (the toolbar's accessible name), `titleSize` (the title's
93
+ `ToolbarText` size, default `large`), and `headingLevel` (expose the title as
94
+ a heading; default a plain span). The defaults keep the stack's own chrome:
95
+ no divider, the standard Toolbar height (a 44px control band with 8px above and below), and the top and side safe-area edges
96
+ claimed.
97
+ - `backIcon` replaces the default chevron-left icon. `backText` adds visible
98
+ text beside it (for example, the previous view's title); visible text names
99
+ the control, so `backLabel` applies only to the icon-only control.
100
+
101
+ The catalog's **Configured toolbar** example shows these together: a level-2
102
+ heading title over a bottom divider, leading and center groups on the root
103
+ view, a trailing group on the pushed view, and `backText` set to the previous
104
+ view's title.
105
+
106
+ Focus follows the controlled stack automatically. On push, `wireNavStack`
107
+ remembers the focused descendant of the departing view and moves focus into the
108
+ new top view. On pop it restores that exact descendant when it still exists. A
109
+ new view prefers a descendant marked `data-nav-focus`, then its first enabled
110
+ focusable descendant, and finally the view container itself. Use
111
+ `data-nav-focus` for a heading or primary control when DOM order is not the best
112
+ initial reading position; it may use `tabindex="-1"` for programmatic focus.
113
+ When a remembered control was removed during the controlled rerender, the same
114
+ fallback order applies. Disposing the helper stops future transitions and
115
+ cleans up any temporary fallback `tabindex` it added.
116
+
117
+ ## Scroll dividers
118
+
119
+ The stack draws no permanent line between its chrome and the view. With
120
+ `wireScrollDividers(appRoot)` installed (see
121
+ [Layout › Scroll dividers](layout.md#scroll-dividers)), the top chrome shows a
122
+ line along its bottom edge only while the active view's content is scrolled
123
+ beneath it, and the bottom toolbar a line along its top edge only while more
124
+ content lies below it — neither when the content fits. The line follows the
125
+ active view across a push or pop. The chrome's line is overlaid on its bottom
126
+ edge and the bottom toolbar's is its always-present 1px top border, colored
127
+ only while shown, so neither ever moves the chrome or the content. When the view's only child is a `Pane`,
128
+ the line keys on whichever actually scrolls — the view, or the Pane's content —
129
+ and a Pane header or footer draws its own boundary instead. An explicit
130
+ `toolbarConfig.dividerSides` still draws a permanent Toolbar edge.
131
+
132
+ `chromeDividers` configures both lines, with the same values as a `Pane`'s:
133
+ `scroll` (the default) follows the scroll state above and draws nothing until
134
+ the wiring runs; `always` keeps both lines, with or without the wiring; `none`
135
+ drops them even when the wiring reports scroll state. It does not change the
136
+ top Toolbar's own `dividerSides`.
137
+
138
+ ```tsx
139
+ <NavStack id="settings" label="Settings" views={views.value} chromeDividers="always" />
140
+ ```
141
+
142
+ ## Safe areas
143
+
144
+ The stack paints through a device's unsafe areas. Its chrome pads for the top
145
+ and side insets, its bottom toolbar for the bottom and side insets, and each
146
+ view pads the remaining edges inside its scroller, so content scrolls under the
147
+ unsafe area but can always be scrolled clear. A view whose only child is a
148
+ `Pane` or layout lets that child own the insets. See [Choosing an app layout › Safe areas](app-layouts.md#safe-areas).
40
149
 
41
150
  ## Transitions
42
151
 
43
152
  `wireNavStack(root, { onBack, duration? })` observes the rendered stack and
44
153
  animates each change: a pushed view slides in from the trailing edge; a popped
45
- view slides back off it over the revealed view. It returns a disposer. The
46
- animation honors `prefers-reduced-motion` (transitions collapse to instant) and
47
- `duration: 0` disables it. Applicable at every device size and inside dialogs.
154
+ view slides back off it over the revealed view; and snapshots of the previous
155
+ top and bottom chrome cross-fade into the active view's chrome. Focus moves to
156
+ the new top view independently of animation duration. It returns a disposer.
157
+ The animation honors `prefers-reduced-motion` (transitions collapse to instant)
158
+ and `duration: 0` disables it. Applicable at every device size and inside
159
+ dialogs.
package/docs/recipes.md CHANGED
@@ -1,25 +1,25 @@
1
1
  # Production composition recipes
2
2
 
3
- These seven reference compositions sit between individual primitives and product
4
- code. Open each stable UX-catalog route to run it, then copy the linked TSX and
5
- CSS. The examples import public package subpaths, use semantic layout owners,
6
- and keep state in a per-instance application adapter. They are not new
7
- monolithic components.
3
+ These ten reference compositions sit between individual primitives and product
4
+ code. Open each stable UX-catalog route to run it, then copy the linked TSX. The
5
+ examples import public package subpaths, compose components through their
6
+ props and tokens, and keep state in a per-instance application adapter. They
7
+ ship no stylesheet of their own and are not new monolithic components.
8
8
 
9
9
  Copy the recipe source together with the catalog-independent
10
10
  [`mount-recipe.ts`](../ux-demo/recipes/mount-recipe.ts) adapter. It mounts the
11
11
  controller at one stable application root, uses `delegateActions()` for recipe
12
- commands, forwards form and dialog lifecycle events, wires resize commits with
13
- the public `onCommit` callback, retains every disposer, and returns one
14
- idempotent disposer:
12
+ commands, forwards form and dialog lifecycle events, runs the recipe's own
13
+ `wire()` (for example `wireWorkbench` or `wireSidebar`), retains every
14
+ disposer, and returns one idempotent disposer:
15
15
 
16
16
  ```ts
17
- import { createRecipe } from './navigation-sidebar.js';
18
- import { mountRecipe } from './mount-recipe.js';
17
+ import { createRecipe } from "./navigation-sidebar.js";
18
+ import { mountRecipe } from "./mount-recipe.js";
19
19
 
20
- const root = document.querySelector<HTMLElement>('#navigation')!;
20
+ const root = document.querySelector<HTMLElement>("#navigation")!;
21
21
  const stopRecipe = mountRecipe(root, createRecipe(announce));
22
- window.addEventListener('pagehide', stopRecipe, { once: true });
22
+ window.addEventListener("pagehide", stopRecipe, { once: true });
23
23
  ```
24
24
 
25
25
  The adapter is delivered as reference source, not a new package runtime export.
@@ -28,63 +28,86 @@ specific dispatch; either way, wire once at a stable root and retain disposal.
28
28
 
29
29
  ## Desktop application shell
30
30
 
31
- [Open the recipe](../ux-demo/?component=recipe-app-shell) · [TSX source](../ux-demo/recipes/app-shell.tsx) · [shared CSS](../ux-demo/recipes/recipes.css)
32
-
33
- Use `Toolbar`, controlled `ResizableRegion` panes, and one
34
- `.kui-pane__content` scroll owner per pane. The recipe owns the shell topology;
35
- the app owns routing, responsive pane visibility, sizes, persistence, and data.
36
- Keep each visible pane's collapse action in its own toolbar. Once hidden, put
37
- its restore action in the adjacent main toolbar on the same logical edge:
38
- leading for an inline-start sidebar and trailing for an inline-end inspector.
39
- Collapse the pane completely rather than preserving an empty icon rail.
40
- Adapt only public `--kui-layout-*` and component variables.
31
+ [Open the recipe](../ux-demo/?component=recipe-app-shell) · [TSX source](../ux-demo/recipes/app-shell.tsx)
32
+
33
+ A filling `List` (`fill`, with the recipe's `data-*` markers through
34
+ `rootAttributes`) stacks the app-bar `Toolbar` above a `Workbench`
35
+ (`@kerfjs/ui/workbench`): resizable navigation and inspector rails around the
36
+ task list. Each rail composes its own panel toolbar — a default-size title and
37
+ the standard hide toggle — and the work area's `mainToolbar` carries the xl
38
+ view title. While a rail is hidden, `Workbench` relocates its show toggle into
39
+ the work-area toolbar on the same logical edge (leading for the navigation
40
+ rail, trailing for the inspector), and `wireWorkbench` hands focus between the
41
+ two positions. Collapse a rail completely rather than preserving an empty icon
42
+ rail. Only the three real panes own a `.kui-pane__content` scroll owner; no
43
+ frame `Pane` wraps the layout in a scroll owner that never scrolls, and the
44
+ app-bar `Toolbar` claims the top edge and both sides with its own
45
+ `safeAreaEdges`.
46
+
47
+ On a narrow container the rails overlay the task list one at a time instead of
48
+ squeezing it, leaving a 44px strip on the far side that dismisses the overlay
49
+ (`responsiveOverlayAt`, on by default; `compactOverlay: 'full'` covers the
50
+ whole width). The app owns each rail's collapsed and size signals — which
51
+ `wireWorkbench` keeps in sync with resizing and overlay dismissal — plus
52
+ routing, persistence, and data. Adapt only public `--kui-layout-*` and
53
+ component variables.
41
54
 
42
55
  ## Navigation sidebar
43
56
 
44
57
  [Open the recipe](../ux-demo/?component=recipe-navigation-sidebar) · [TSX source](../ux-demo/recipes/navigation-sidebar.tsx)
45
58
 
46
59
  One unpadded `.kui-pane` owns toolbar/content/footer structure. Its
47
- `.kui-content` uses 24px major gaps; `MenuHeader`, `MenuItem`, and other
48
- `.kui-content-item` children own their 8px margin, 1px border, and 8px padding.
60
+ `.kui-content` uses 24px major gaps; `ListHeader`, `ListItem`, and
61
+ `ContentItem` children own their 8px margin, 1px border, and 8px padding.
49
62
  Rows and footer toolbar groups remain 44px tall. The app owns routes,
50
63
  permissions, labels, selection, valid section counts and their localized
51
64
  `countLabel` phrases, non-count badge content, disclosure state, and revealed
52
- content. A toggled `MenuHeader` supplies the production `DisclosureArrow` when
65
+ content. A toggled `ListHeader` supplies the production `DisclosureArrow` when
53
66
  no custom `actionIcon` is needed; ordinary navigation rows stay chevron-free.
54
67
 
55
68
  ## Workspace header
56
69
 
57
70
  [Open the recipe](../ux-demo/?component=recipe-workspace-header) · [TSX source](../ux-demo/recipes/workspace-header.tsx)
58
71
 
59
- `PanelHeader` owns the page heading while one control cluster holds secondary,
72
+ The page heading is a direct `Toolbar`/`ToolbarText` composition while one control cluster holds secondary,
60
73
  overflow, and primary actions. The app owns authorization and command policy;
61
74
  controls relocate without changing focus order.
62
75
 
63
- ## Master-detail dialog
64
-
65
- [Open the recipe](../ux-demo/?component=recipe-master-detail-dialog) · [TSX source](../ux-demo/recipes/master-detail-dialog.tsx)
66
-
67
- The production Web Awesome dialog owns modal focus and Escape; the thin recipe
68
- adapter restores the invoking control consistently after the hide event.
69
- `PanelHeader`, `MenuHeader`, `MenuItem`, and `ValueTable` own their included
70
- anatomy. The application owns open state, selection, dismissal policy, and
71
- record actions. `PanelHeader` places the trailing controls the app passes
72
- directly into its top toolbar's trailing zone.
73
- The header sits on the dialog edge while retaining its internal control inset;
74
- the selected title receives the full content gutter, the metadata table fills
75
- the available detail width between the usual outer margins, and the action
76
- cluster uses one outer gutter without a second content-item inset.
77
- Do not rebuild the dialog or reach into private shadow parts.
76
+ ## List-detail dialog
77
+
78
+ [Open the recipe](../ux-demo/?component=recipe-list-detail-dialog) · [TSX source](../ux-demo/recipes/list-detail-dialog.tsx)
79
+
80
+ A list-detail dialog is laid out like a `Workbench` with a left sidebar: on
81
+ roomy devices the list is a full-height sidebar and the detail is a full-height
82
+ main column, each a `Pane` with its own top `Toolbar`. The sidebar's toolbar
83
+ carries its quiet default-size title (and it may add a bottom toolbar for
84
+ sidebar-only actions); the main column's toolbar carries the dialog's primary
85
+ extra-large title and the close control, and its footer carries the record
86
+ actions. The Web Awesome dialog therefore renders `without-header` there —
87
+ its label still names the modal — and the close button uses
88
+ `data-dialog="close"`. Web Awesome keeps modal focus and Escape, and the thin
89
+ recipe adapter restores the invoking control after the hide event.
90
+ `DialogSurface` chooses the large modal with no body inset, because the panes
91
+ own their geometry. On compact devices the dialog becomes a full-screen sheet
92
+ with its own labeled header and footer actions, and `SplitView` becomes a
93
+ `NavStack` drill-down whose back control the application pops. The
94
+ application owns open state, selection, the pushed detail, dismissal policy,
95
+ and record actions. Do not put the primary title in a header spanning both
96
+ columns, rebuild the dialog, or reach into private shadow parts.
78
97
 
79
98
  ## Composer form
80
99
 
81
100
  [Open the recipe](../ux-demo/?component=recipe-composer-form) · [TSX source](../ux-demo/recipes/composer-form.tsx)
82
101
 
83
- `PanelHeader` supplies the task title and summary, with their ids referenced
84
- by the form. Production fields own labels, help, and native focus. The field
85
- and footer control edges sit directly on the shared 8px inline gutter rather
86
- than acquiring a second content-item padding inset; major children remain 24px
87
- apart and related controls use 8px gaps. The app owns
102
+ A direct `ToolbarText` supplies the task title, with app-owned supporting copy
103
+ below; their ids are referenced by the form. `ListInsetText` gives that bare
104
+ supporting copy the same content-item text inset as the fields. The title and
105
+ supporting line share a nested heading `List` with `gap="none"`, so the heading
106
+ unit stays together instead of taking the form's 24px section gap. Production
107
+ fields own labels, help, and native focus. One `List` owns the 24px major
108
+ rhythm; the field `List` and the action `Row` use `controlInsets` to sit on the
109
+ shared 8px inline gutter with 8px gaps between related controls, rather than
110
+ acquiring a second content-item padding inset. The app owns
88
111
  validation, drafts, permissions, and transport. Persistent error or success
89
112
  feedback is the only nested semantic surface and uses `StateBanner`, not a toast.
90
113
  Because upgraded Web Awesome fields retain live value properties, controlled
@@ -106,8 +129,12 @@ rows.
106
129
 
107
130
  Use `ToolbarControlGroup` for related commands, `SegmentedControl` for a few
108
131
  visible exclusive choices, `Select` for a longer value list, and an ordinary
109
- button for an independent command. The app owns values, actions, persistence,
110
- and responsive priority.
132
+ button for an independent command. Even that independent button sits in a
133
+ single-control `ToolbarControlGroup`, which keeps its height, pill shape, focus,
134
+ and hover treatment aligned with the adjacent toolbar controls. At compact
135
+ widths the toolbar stacks its zones and wraps whole trailing groups onto another
136
+ row, so the last action is never clipped. The app owns values, actions,
137
+ persistence, and responsive priority.
111
138
 
112
139
  ## Navigation stack
113
140
 
@@ -116,11 +143,59 @@ and responsive priority.
116
143
  Drill from a library list into a detail and back with `NavStack`
117
144
  (`@kerfjs/ui/nav-stack`): the app owns the stack as a signal of views and
118
145
  pushes/pops it, `NavStack` renders it, and `wireNavStack` slides the content and
119
- settles the chrome (reduced motion collapses the slide to instant). A live
120
- `deviceClass()` badge shows the current size/orientation. See the layout guide
146
+ settles the chrome (reduced motion collapses the slide to instant). See the
147
+ layout guide
121
148
  [`app-layouts.md`](app-layouts.md) for choosing among `NavStack`, `SplitView`,
122
149
  `Workbench`, and `TabScaffold`.
123
150
 
151
+ ## Loading inspector
152
+
153
+ [Open the recipe](../ux-demo/?component=recipe-loading-inspector) · [TSX source](../ux-demo/recipes/loading-inspector.tsx)
154
+
155
+ A record inspector whose per-record values load asynchronously. Every
156
+ value-bearing component (`ToolbarText`, `ValueTable`/`ValueTableRow`, `Select`,
157
+ `SegmentedControl`, `ListItem`, `StateBanner`) takes its `placeholder` from one
158
+ loading flag, so the same real chrome renders a faithful loading state and then
159
+ the populated record — no separate skeleton markup. The composition is the point;
160
+ `Skeleton` is the primitive it builds on. Its heading `Toolbar` uses
161
+ `responsive="wrap"`, so on a narrow inspector the toggle moves below a whole
162
+ record title instead of truncating it. The app owns the loading lifecycle and
163
+ which values are still unknown.
164
+
165
+ ## Collapsible sidebar
166
+
167
+ [Open the recipe](../ux-demo/?component=recipe-collapsible-sidebar) · [TSX source](../ux-demo/recipes/collapsible-sidebar.tsx)
168
+
169
+ A mini app frame whose left navigation rail and bottom activity drawer are
170
+ standalone `CollapsiblePanel`s (`@kerfjs/ui/collapsible-panel`) driven by
171
+ `wireSidebar` (`@kerfjs/ui/wire-sidebar`). Each panel takes a `toolbar` — a
172
+ title plus the standard per-side toggle — so the hide control lives in the
173
+ panel's own header, and `CollapsiblePanelRelocated` renders the matching show
174
+ control only while the panel is collapsed, so exactly one control owns each
175
+ action and a collapsed panel is still reachable. The rail's relocated toggle
176
+ leads the always-visible main header; the drawer's sits in a
177
+ `FloatingToolbar` passed as the drawer's own `restoreControl`, which the panel
178
+ floats in its column's safe-area-aware bottom-end corner, next to where the
179
+ drawer opens — do not hand-roll a conditional floating control beside the
180
+ panel. `wireSidebar` owns the toggle delegation, moves focus into a
181
+ panel on open, restores it on close (to the trigger, or to the panel's expand toggle when
182
+ the trigger sits inside the collapsed panel), and — when a `deviceClass()` reports
183
+ `compact` — presents the panels as a dismissable **overlay** (backdrop, Escape
184
+ and backdrop-click collapse, and a trapped Tab ring, the ARIA dialog pattern).
185
+ The overlay starts closed and opens only from a toggle; the rail's signal is
186
+ seeded from the device class with `inlineCollapsed: false`, so the first compact
187
+ render has no overlay and a wide crossing restores the open inline rail. It
188
+ also persists each panel's inline collapsed state through a supplied storage hook. A
189
+ filling `Row` (`fill` plus `rootAttributes`) is the root: it takes the frame's
190
+ definite height and places the rail beside a `List` column, and a one-column
191
+ `Grid` grows the main pane above the drawer. Because the panels sit at the real
192
+ frame edges, each grows through its edge's safe area and hands that edge back to
193
+ its siblings when it collapses; the drawer's activity log is a `ValueTable`. The app owns each
194
+ `collapsed` signal, the panel sizes, and the content; the wire owns the
195
+ ephemeral interaction. For a full three-pane shell use `Workbench` instead — see
196
+ [`app-layouts.md`](app-layouts.md). This recipe is covered end-to-end across
197
+ Chromium, Firefox, and WebKit by `tests/browser/collapsible-sidebar-recipe.spec.ts`.
198
+
124
199
  ## Rules shared by every recipe
125
200
 
126
201
  - Import `@kerfjs/ui/layout.css`; keep every pane unpadded and use exactly one
@@ -128,9 +203,17 @@ settles the chrome (reduced motion collapses the slide to instant). A live
128
203
  - For direct `wa-*` JSX, import types from `@kerfjs/ui/webawesome`. Import only
129
204
  individual Web Awesome registration modules and theme them with
130
205
  `@kerfjs/ui/webawesome.css`.
131
- - Prefer public props and variables at the composition boundary. When a recipe
132
- needs responsive topology, join only classes listed in the catalog's
133
- `publicClasses`; do not copy component markup or select descendants by tag,
134
- id, attribute alone, or an unlisted implementation class.
206
+ - Compose, don't style. A recipe ships no stylesheet, sets no inline style, and
207
+ names no class outside the published layout vocabulary (`.kui-content`,
208
+ `.kui-control-cluster`, …) and themed Web Awesome classes — a content item is
209
+ a `ContentItem`, not a hand-written `.kui-content-item`; it configures
210
+ components through props, `rootAttributes`, and tokens. When a recipe needs a
211
+ capability no component offers, record it as a component gap rather than
212
+ papering over it with CSS. `npm run check:recipes` enforces these rules on
213
+ every file in `ux-demo/recipes/`.
214
+ - Each recipe also exports a catalog-only `presentation`: the `CatalogExample`
215
+ viewport that frames it in the UX catalog and its ownership note. An
216
+ application that copies the recipe ignores that export and mounts the
217
+ controller into its own container.
135
218
  - Start from the copyable mount adapter, or reproduce its complete boundary:
136
219
  wire stable `data-action` hooks once and retain every disposer.
@@ -1,18 +1,31 @@
1
1
  # Split view (list-detail)
2
2
 
3
- `@kerfjs/ui/split-view` is a list-detail (master-detail) layout: a list and a
3
+ `@kerfjs/ui/split-view` is a list-detail layout: a list and a
4
4
  detail side by side on roomy screens, collapsing to a `NavStack` (list → detail)
5
5
  on compact ones. One of the opt-in app layouts (see
6
6
  [`../../docs/23-app-layouts.md`](../../docs/23-app-layouts.md)).
7
7
 
8
8
  ```ts
9
- import { SplitView } from '@kerfjs/ui/split-view';
10
- import { deviceClass } from '@kerfjs/ui/device-class';
11
- import '@kerfjs/ui/split-view.css';
12
- // plus nav-stack.css when the compact path is reachable, and
13
- // wireResizableRegions / wireNavStack for the interactive behavior.
9
+ import { SplitView } from "@kerfjs/ui/split-view";
10
+ import { deviceClass } from "@kerfjs/ui/device-class";
11
+ // plus wireResizableRegions / wireNavStack for the interactive behavior.
14
12
  ```
15
13
 
14
+ In a browser bundler that honors the `browser` export condition (Vite, esbuild, and
15
+ webpack do by default), the import above also
16
+ loads SplitView's stylesheet and those of the components it renders internally
17
+ (its compact `NavStack`, `ResizableRegion`, and the toolbar
18
+ components). Without that condition, import the manual stylesheets instead:
19
+ `@kerfjs/ui/split-view.css` plus those components' CSS, or `@kerfjs/ui/styles.css`.
20
+
21
+ ## Safe areas
22
+
23
+ The list pane grows by the inline-start unsafe inset and pads for the edges it
24
+ touches; the detail pads for its own outer edges. Neither is inset on the
25
+ shared interior edge. A pane whose only child is a `Pane` lets that child own
26
+ the insets, and the compact form hands them to its `NavStack`. See
27
+ [Choosing an app layout › Safe areas](app-layouts.md#safe-areas).
28
+
16
29
  ## Responsive by device class
17
30
 
18
31
  `SplitView` is declarative; the app derives `compact` from the device class and
@@ -45,5 +58,55 @@ const selected = signal<string | null>(null);
45
58
  app's selection). This is the portrait-tablet / handset presentation; as a
46
59
  dialog the compact form is a full-screen or large partial-cover modal.
47
60
 
61
+ ## Configuring the list region and the compact stack
62
+
63
+ `resizable` forwards the list's `ResizableRegion` configuration alongside
64
+ `size`, `min`, and `max`: `separator` (`"hidden"` keeps the resize hit target
65
+ but paints no line), `handleIcon`, `contentOverflow`, and collapse —
66
+ `collapsed`, `transitioning`, `collapseMotion`, `restoreControl`, and
67
+ `restorePosition`. A collapsed list snaps to zero width, renders `inert` and
68
+ `aria-hidden`, and the detail fills the split; the app owns the `collapsed`
69
+ flag and renders the restore control (usually a `FloatingToolbar`). Omitted
70
+ options keep the region's defaults.
71
+
72
+ ```tsx
73
+ resizable={{
74
+ size: listWidth.value,
75
+ min: 220,
76
+ max: 480,
77
+ collapsed: listCollapsed.value,
78
+ restoreControl: <ShowThreadsToolbar />,
79
+ }}
80
+ ```
81
+
82
+ `compactStack` configures the compact `NavStack`: `toolbarConfig`, `backIcon`,
83
+ `backText`, `hideToolbar`, the persistent `bottomToolbar`, and `chromeDividers`
84
+ forward to the stack, and `list` / `detail` give each view its own top-toolbar groups
85
+ (`leading`, `center`, trailing `toolbar`) and `bottomToolbar`:
86
+
87
+ ```tsx
88
+ compactStack={{
89
+ backText: "Threads",
90
+ toolbarConfig: { headingLevel: 1 },
91
+ list: { toolbar: <ComposeGroup /> },
92
+ detail: { toolbar: <ReplyGroup />, bottomToolbar: <MessageActions /> },
93
+ }}
94
+ ```
95
+
96
+ The catalog's **Interactive compact drill-down** example exercises this exact
97
+ controlled flow: a list action sets the selected message, `detailActive` pushes
98
+ its detail, and the wired Back action clears the selection to reveal the
99
+ preserved list. It also forwards `compactStack`: a level-2 heading title over
100
+ a bottom divider, a Compose group on the list view, and a Reply group plus a
101
+ bottom toolbar on the detail. Use the same structure in application demos so
102
+ compact examples show the interaction rather than rendering a disconnected
103
+ detail state.
104
+
105
+ The catalog's **Resizable, collapsible list** example forwards `resizable`: a
106
+ hidden separator that still resizes the list (its committed width comes back
107
+ through `wireResizableRegions`' `onCommit` into the app's size signal), a Hide
108
+ control in the list's own toolbar, and a `FloatingToolbar` restore control in
109
+ the split's bottom-start corner.
110
+
48
111
  Compose the interactive wiring from the existing helpers — `SplitView` adds no
49
112
  wire of its own.
@@ -0,0 +1,58 @@
1
+ # SunkenPanel
2
+
3
+ `SunkenPanel` is a visually lowered application surface with one compact inset
4
+ and a vertical content stack. Use it for a main work area or nested panel whose
5
+ background should sit behind ordinary content, such as the primary stage in an
6
+ issue tracker or component catalog.
7
+
8
+ ```tsx
9
+ import { SunkenPanel } from '@kerfjs/ui/sunken-panel';
10
+
11
+ <SunkenPanel ariaLabel="Release workspace">
12
+ <ReleaseSummary />
13
+ <ReleaseChecks />
14
+ </SunkenPanel>;
15
+ ```
16
+
17
+ The default `shape="rounded"` uses the shared rounded-rectangle radius. Choose
18
+ `shape="square"` for a flush or edge-to-edge area that needs `border-radius: 0`:
19
+
20
+ ```tsx
21
+ <SunkenPanel shape="square">
22
+ <Workspace />
23
+ </SunkenPanel>
24
+ ```
25
+
26
+ ## Ownership
27
+
28
+ The root owns its lowered background, 8px padding, and 8px vertical gap.
29
+ Children own their borders and internal geometry. The application owns child
30
+ order, responsive placement, and scrolling; `SunkenPanel` deliberately does not
31
+ create another scroll container.
32
+
33
+ Use `ariaLabel` only when the surface is a distinct region people need to find
34
+ by name. With a label, the root receives `role="region"`; without one it remains
35
+ a non-landmark grouping.
36
+
37
+ Do not use `SunkenPanel` merely to add padding, as a substitute for pane
38
+ header/content/footer anatomy, or around a child that already owns the same
39
+ outer surface.
40
+
41
+ ## Public styling boundary
42
+
43
+ Override the public properties at the composition boundary:
44
+
45
+ - `--kui-sunken-panel-background`
46
+ - `--kui-sunken-panel-foreground`
47
+ - `--kui-sunken-panel-padding`
48
+ - `--kui-sunken-panel-gap`
49
+ - `--kui-sunken-panel-radius`
50
+
51
+ `--kui-sunken-panel-background` can be overridden for a known backdrop. Keep
52
+ the default lowered surface opaque; a translucent override compounds when
53
+ sunken panels nest. See [Contextual transparency](./webawesome-theme.md#contextual-transparency)
54
+ for the color and contrast evaluation.
55
+
56
+ The public root class is `.kui-sunken-panel`. Prefer the properties above over
57
+ styling descendants. The `square` shape deliberately overrides the radius
58
+ property with zero; use `rounded` when customizing the radius token.
@@ -0,0 +1,25 @@
1
+ # Dialog and popup surface scaffolds
2
+
3
+ `DialogSurface` and `PopupSurface` configure recurring Web Awesome surface
4
+ geometry without application `::part()` overrides. They do not replace Web
5
+ Awesome behavior: the application still owns open state, focus lifecycle,
6
+ dismissal policy, ids, labels, and content.
7
+
8
+ Wrap one `wa-dialog` with `DialogSurface`. Choose `size` (`small`, `medium`, or
9
+ `large`), `presentation` (`modal`, `side-sheet`, or `fullscreen`), and independent
10
+ `bodyInset` / `footerInset` (`none`, `compact`, or `comfortable`). The defaults
11
+ match Kerf's medium modal, 8px body, and 16px footer rhythm.
12
+
13
+ Treat a dialog body as a `List` by default. When its rows or sections own their
14
+ standard list geometry, set `bodyInset="none"` so the dialog does not add a
15
+ second inset. Bare prose is still a list child: wrap it in `ListInsetText` so its
16
+ text edge receives the standard 8px margin + 1px transparent border + 8px
17
+ padding and aligns with bordered siblings. Reserve `compact` or `comfortable`
18
+ body insets for exceptional content that does not already have list/content-item
19
+ geometry.
20
+
21
+ Wrap one `PopupMenu` (or another single `wa-dropdown`) with `PopupSurface`. `inset="list-zero"` removes menu
22
+ padding for a child that already owns row insets, `compact` uses 4px, and
23
+ `standard` uses the shared 8px surface inset. Keep the dropdown trigger named and
24
+ preserve `data-morph-skip-children` when its upgraded light-DOM items must retain
25
+ identity across Kerf rerenders.