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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (723) hide show
  1. package/README.md +501 -139
  2. package/ai/application-ui-diagnostic-ids-v1.json +109 -0
  3. package/ai/application-ui-profile-sync.cjs +548 -0
  4. package/ai/application-ui-profile.d.mts +1 -0
  5. package/ai/application-ui-profile.d.ts +106 -0
  6. package/ai/application-ui-profile.defaults.json +96 -0
  7. package/ai/application-ui-profile.mjs +653 -0
  8. package/ai/application-ui-profile.schema.json +140 -0
  9. package/ai/catalog-authoring.json +36 -0
  10. package/ai/catalog-authoring.schema.json +109 -0
  11. package/ai/compile-time-contracts-v1.json +149 -0
  12. package/ai/compile-time-contracts-v1.schema.json +52 -0
  13. package/ai/component-catalog-extension.schema.json +104 -0
  14. package/ai/component-catalog.json +3910 -464
  15. package/ai/component-catalog.schema.json +92 -1
  16. package/ai/component-class-owners.cjs +83 -0
  17. package/ai/component-composition-extension.d.ts +7 -0
  18. package/ai/component-composition-extension.schema.json +7 -0
  19. package/ai/component-composition-rules.json +524 -0
  20. package/ai/component-composition.d.ts +127 -0
  21. package/ai/component-composition.json +7128 -0
  22. package/ai/component-composition.schema.json +399 -0
  23. package/ai/components/README.md +171 -0
  24. package/ai/components/application-tabs.md +65 -0
  25. package/ai/components/badge.md +72 -0
  26. package/ai/components/chip.md +72 -0
  27. package/ai/components/collapsible-panel.md +102 -0
  28. package/ai/components/content-item.md +93 -0
  29. package/ai/components/disclosure-arrow.md +77 -0
  30. package/ai/components/document-baseline.md +75 -0
  31. package/ai/components/empty-state.md +80 -0
  32. package/ai/components/feedback.md +71 -0
  33. package/ai/components/floating-toolbar.md +82 -0
  34. package/ai/components/foundation.md +65 -0
  35. package/ai/components/grid.md +98 -0
  36. package/ai/components/headers.md +63 -0
  37. package/ai/components/layout.md +75 -0
  38. package/ai/components/list-action-row.md +91 -0
  39. package/ai/components/list-header.md +89 -0
  40. package/ai/components/list-inset-control.md +74 -0
  41. package/ai/components/list-inset-text.md +72 -0
  42. package/ai/components/list-item.md +94 -0
  43. package/ai/components/list.md +105 -0
  44. package/ai/components/loading-spinner.md +73 -0
  45. package/ai/components/lucide-icon.md +78 -0
  46. package/ai/components/nav-stack.md +104 -0
  47. package/ai/components/pane.md +101 -0
  48. package/ai/components/popup-menu.md +171 -0
  49. package/ai/components/recipe-app-shell.md +57 -0
  50. package/ai/components/recipe-collapsible-sidebar.md +57 -0
  51. package/ai/components/recipe-compact-toolbar.md +57 -0
  52. package/ai/components/recipe-composer-form.md +57 -0
  53. package/ai/components/recipe-list-detail-dialog.md +57 -0
  54. package/ai/components/recipe-list-workspace-states.md +57 -0
  55. package/ai/components/recipe-loading-inspector.md +57 -0
  56. package/ai/components/recipe-navigation-sidebar.md +57 -0
  57. package/ai/components/recipe-navigation-stack.md +57 -0
  58. package/ai/components/recipe-workspace-header.md +57 -0
  59. package/ai/components/resize.md +106 -0
  60. package/ai/components/row.md +96 -0
  61. package/ai/components/segmented-control.md +82 -0
  62. package/ai/components/select.md +113 -0
  63. package/ai/components/skeleton.md +84 -0
  64. package/ai/components/spacer.md +86 -0
  65. package/ai/components/split-view.md +102 -0
  66. package/ai/components/state-banner.md +94 -0
  67. package/ai/components/sunken-panel.md +79 -0
  68. package/ai/components/surface-scaffold.md +78 -0
  69. package/ai/components/tab-bar.md +113 -0
  70. package/ai/components/tab-scaffold.md +94 -0
  71. package/ai/components/tabs.md +95 -0
  72. package/ai/components/text.md +85 -0
  73. package/ai/components/token-search-field.md +106 -0
  74. package/ai/components/toolbar-control-group.md +102 -0
  75. package/ai/components/toolbar-text.md +79 -0
  76. package/ai/components/toolbar.md +97 -0
  77. package/ai/components/value-table.md +73 -0
  78. package/ai/components/wa-accordion-item.md +55 -0
  79. package/ai/components/wa-accordion.md +65 -0
  80. package/ai/components/wa-animated-image.md +55 -0
  81. package/ai/components/wa-animation.md +55 -0
  82. package/ai/components/wa-avatar.md +55 -0
  83. package/ai/components/wa-badge.md +55 -0
  84. package/ai/components/wa-breadcrumb-item.md +53 -0
  85. package/ai/components/wa-breadcrumb.md +55 -0
  86. package/ai/components/wa-button-group.md +59 -0
  87. package/ai/components/wa-button.md +55 -0
  88. package/ai/components/wa-callout.md +58 -0
  89. package/ai/components/wa-card.md +59 -0
  90. package/ai/components/wa-carousel-item.md +53 -0
  91. package/ai/components/wa-carousel.md +55 -0
  92. package/ai/components/wa-checkbox-group.md +55 -0
  93. package/ai/components/wa-checkbox.md +55 -0
  94. package/ai/components/wa-color-picker.md +55 -0
  95. package/ai/components/wa-comparison.md +55 -0
  96. package/ai/components/wa-copy-button.md +55 -0
  97. package/ai/components/wa-details.md +61 -0
  98. package/ai/components/wa-dialog.md +59 -0
  99. package/ai/components/wa-divider.md +53 -0
  100. package/ai/components/wa-drawer.md +55 -0
  101. package/ai/components/wa-dropdown-item.md +60 -0
  102. package/ai/components/wa-dropdown.md +60 -0
  103. package/ai/components/wa-format-bytes.md +53 -0
  104. package/ai/components/wa-format-date.md +53 -0
  105. package/ai/components/wa-format-number.md +53 -0
  106. package/ai/components/wa-icon.md +58 -0
  107. package/ai/components/wa-include.md +53 -0
  108. package/ai/components/wa-input.md +59 -0
  109. package/ai/components/wa-intersection-observer.md +53 -0
  110. package/ai/components/wa-known-date.md +53 -0
  111. package/ai/components/wa-markdown.md +53 -0
  112. package/ai/components/wa-mutation-observer.md +53 -0
  113. package/ai/components/wa-number-input.md +55 -0
  114. package/ai/components/wa-option.md +59 -0
  115. package/ai/components/wa-otp-input.md +53 -0
  116. package/ai/components/wa-page.md +53 -0
  117. package/ai/components/wa-pagination.md +55 -0
  118. package/ai/components/wa-popover.md +55 -0
  119. package/ai/components/wa-popup.md +53 -0
  120. package/ai/components/wa-progress-bar.md +53 -0
  121. package/ai/components/wa-progress-ring.md +53 -0
  122. package/ai/components/wa-qr-code.md +53 -0
  123. package/ai/components/wa-radio-group.md +59 -0
  124. package/ai/components/wa-radio.md +55 -0
  125. package/ai/components/wa-random-content.md +53 -0
  126. package/ai/components/wa-rating.md +55 -0
  127. package/ai/components/wa-relative-time.md +53 -0
  128. package/ai/components/wa-resize-observer.md +53 -0
  129. package/ai/components/wa-scroller.md +53 -0
  130. package/ai/components/wa-select.md +63 -0
  131. package/ai/components/wa-skeleton.md +53 -0
  132. package/ai/components/wa-slider.md +55 -0
  133. package/ai/components/wa-spinner.md +58 -0
  134. package/ai/components/wa-split-panel.md +58 -0
  135. package/ai/components/wa-switch.md +53 -0
  136. package/ai/components/wa-tab-group.md +69 -0
  137. package/ai/components/wa-tab-panel.md +60 -0
  138. package/ai/components/wa-tab.md +59 -0
  139. package/ai/components/wa-tag.md +59 -0
  140. package/ai/components/wa-textarea.md +53 -0
  141. package/ai/components/wa-time-input.md +55 -0
  142. package/ai/components/wa-toast-item.md +60 -0
  143. package/ai/components/wa-toast.md +60 -0
  144. package/ai/components/wa-tooltip.md +55 -0
  145. package/ai/components/wa-tree-item.md +55 -0
  146. package/ai/components/wa-tree.md +55 -0
  147. package/ai/components/wa-zoomable-frame.md +55 -0
  148. package/ai/components/workbench.md +118 -0
  149. package/ai/public-api-signatures-v1.md +2748 -210
  150. package/ai/skill.md +286 -66
  151. package/ai/webawesome-jsx-signatures-v1.md +9 -2
  152. package/analyzer/cli.mjs +49 -0
  153. package/analyzer/component-ownership.d.mts +72 -0
  154. package/analyzer/component-ownership.mjs +286 -0
  155. package/analyzer/index.d.mts +52 -0
  156. package/analyzer/index.mjs +2038 -0
  157. package/analyzer/loud-pairs.d.mts +49 -0
  158. package/analyzer/loud-pairs.mjs +357 -0
  159. package/analyzer/report.schema.json +66 -0
  160. package/analyzer/selectors.d.mts +21 -0
  161. package/analyzer/selectors.mjs +212 -0
  162. package/catalog-projection-cli.mjs +96 -0
  163. package/catalog-projection.d.mts +55 -0
  164. package/catalog-projection.mjs +62 -0
  165. package/dist/app-tab.d.ts +39 -4
  166. package/dist/app-tab.js +2 -1
  167. package/dist/badge.d.ts +52 -0
  168. package/dist/badge.js +3 -0
  169. package/dist/badge.js.map +1 -0
  170. package/dist/browser/badge.js +3 -0
  171. package/dist/browser/catalog.js +26 -0
  172. package/dist/browser/chip.js +3 -0
  173. package/dist/browser/collapsible-panel.js +9 -0
  174. package/dist/browser/content-item.js +3 -0
  175. package/dist/browser/floating-toolbar.js +3 -0
  176. package/dist/browser/grid.js +3 -0
  177. package/dist/browser/list-action-row.js +5 -0
  178. package/dist/browser/{menu-header.js → list-header.js} +4 -2
  179. package/dist/browser/list-inset-control.js +3 -0
  180. package/dist/browser/list-inset-text.js +3 -0
  181. package/dist/browser/list-item.js +5 -0
  182. package/dist/browser/list.js +3 -0
  183. package/dist/browser/{panel-header.js → nav-stack.js} +5 -3
  184. package/dist/browser/pane.js +3 -0
  185. package/dist/browser/popup-menu.js +3 -0
  186. package/dist/browser/row.js +3 -0
  187. package/dist/browser/segmented-control.js +0 -1
  188. package/dist/browser/select.js +1 -0
  189. package/dist/browser/spacer.js +3 -0
  190. package/dist/browser/split-view.js +11 -0
  191. package/dist/browser/state-banner.js +1 -0
  192. package/dist/browser/sunken-panel.js +3 -0
  193. package/dist/browser/surface-scaffold.js +3 -0
  194. package/dist/browser/tab-scaffold.js +4 -0
  195. package/dist/browser/text.js +3 -0
  196. package/dist/browser/toolbar-control-group.js +1 -0
  197. package/dist/browser/workbench.js +14 -0
  198. package/dist/catalog-resources.d.ts +48 -0
  199. package/dist/catalog-resources.js +22 -0
  200. package/dist/catalog-resources.js.map +1 -0
  201. package/dist/catalog.d.ts +92 -0
  202. package/dist/catalog.js +503 -0
  203. package/dist/catalog.js.map +1 -0
  204. package/dist/chip.d.ts +35 -0
  205. package/dist/chip.js +3 -0
  206. package/dist/chip.js.map +1 -0
  207. package/dist/chunk-2G2ZJQYK.js +152 -0
  208. package/dist/chunk-2G2ZJQYK.js.map +1 -0
  209. package/dist/chunk-3BYFWTP3.js +108 -0
  210. package/dist/chunk-3BYFWTP3.js.map +1 -0
  211. package/dist/chunk-47CKKLBE.js +34 -0
  212. package/dist/chunk-47CKKLBE.js.map +1 -0
  213. package/dist/chunk-4SQK27MR.js +202 -0
  214. package/dist/chunk-4SQK27MR.js.map +1 -0
  215. package/dist/chunk-5I7QGQVT.js +24 -0
  216. package/dist/chunk-5I7QGQVT.js.map +1 -0
  217. package/dist/chunk-6DFDTWGG.js +288 -0
  218. package/dist/chunk-6DFDTWGG.js.map +1 -0
  219. package/dist/chunk-7OKX3EF6.js +135 -0
  220. package/dist/chunk-7OKX3EF6.js.map +1 -0
  221. package/dist/chunk-AHEG27M7.js +66 -0
  222. package/dist/chunk-AHEG27M7.js.map +1 -0
  223. package/dist/chunk-AYUHMAI6.js +48 -0
  224. package/dist/chunk-AYUHMAI6.js.map +1 -0
  225. package/dist/chunk-B2ZMR7NY.js +85 -0
  226. package/dist/chunk-B2ZMR7NY.js.map +1 -0
  227. package/dist/chunk-BFPBS5Y4.js +250 -0
  228. package/dist/chunk-BFPBS5Y4.js.map +1 -0
  229. package/dist/chunk-DB5ADJKF.js +775 -0
  230. package/dist/chunk-DB5ADJKF.js.map +1 -0
  231. package/dist/chunk-DC6CN2DS.js +123 -0
  232. package/dist/chunk-DC6CN2DS.js.map +1 -0
  233. package/dist/chunk-DG6G5EPF.js +35 -0
  234. package/dist/chunk-DG6G5EPF.js.map +1 -0
  235. package/dist/{chunk-56RJXPHG.js → chunk-G4S2QU6V.js} +7 -4
  236. package/dist/chunk-G4S2QU6V.js.map +1 -0
  237. package/dist/chunk-GLDWRCAM.js +49 -0
  238. package/dist/chunk-GLDWRCAM.js.map +1 -0
  239. package/dist/chunk-I3Q7KKYM.js +33 -0
  240. package/dist/chunk-I3Q7KKYM.js.map +1 -0
  241. package/dist/chunk-IA7TMD4Y.js +288 -0
  242. package/dist/chunk-IA7TMD4Y.js.map +1 -0
  243. package/dist/chunk-J3KGJ6P6.js +135 -0
  244. package/dist/chunk-J3KGJ6P6.js.map +1 -0
  245. package/dist/chunk-K47P7QZC.js +17 -0
  246. package/dist/chunk-K47P7QZC.js.map +1 -0
  247. package/dist/chunk-K67Y2JNF.js +222 -0
  248. package/dist/chunk-K67Y2JNF.js.map +1 -0
  249. package/dist/chunk-KCCEH7RF.js +492 -0
  250. package/dist/chunk-KCCEH7RF.js.map +1 -0
  251. package/dist/chunk-KLJKU6ZL.js +109 -0
  252. package/dist/chunk-KLJKU6ZL.js.map +1 -0
  253. package/dist/chunk-KVBRMEPM.js +44 -0
  254. package/dist/chunk-KVBRMEPM.js.map +1 -0
  255. package/dist/chunk-M6DEEBEF.js +156 -0
  256. package/dist/chunk-M6DEEBEF.js.map +1 -0
  257. package/dist/chunk-MEY33VWB.js +44 -0
  258. package/dist/chunk-MEY33VWB.js.map +1 -0
  259. package/dist/chunk-MP2GDBQZ.js +50 -0
  260. package/dist/chunk-MP2GDBQZ.js.map +1 -0
  261. package/dist/chunk-NC4CFOID.js +188 -0
  262. package/dist/chunk-NC4CFOID.js.map +1 -0
  263. package/dist/chunk-NCSWXG7G.js +80 -0
  264. package/dist/chunk-NCSWXG7G.js.map +1 -0
  265. package/dist/chunk-NN6GYOA2.js +47 -0
  266. package/dist/chunk-NN6GYOA2.js.map +1 -0
  267. package/dist/chunk-OXO2QJWV.js +55 -0
  268. package/dist/chunk-OXO2QJWV.js.map +1 -0
  269. package/dist/chunk-P7D3EMXM.js +52 -0
  270. package/dist/chunk-P7D3EMXM.js.map +1 -0
  271. package/dist/chunk-PSHUSWQH.js +18 -0
  272. package/dist/chunk-PSHUSWQH.js.map +1 -0
  273. package/dist/chunk-Q6YU3BT7.js +138 -0
  274. package/dist/chunk-Q6YU3BT7.js.map +1 -0
  275. package/dist/chunk-QJ5VFCW3.js +131 -0
  276. package/dist/chunk-QJ5VFCW3.js.map +1 -0
  277. package/dist/chunk-RGS4WX2M.js +44 -0
  278. package/dist/chunk-RGS4WX2M.js.map +1 -0
  279. package/dist/chunk-RNQNEENY.js +146 -0
  280. package/dist/chunk-RNQNEENY.js.map +1 -0
  281. package/dist/chunk-RVERAFFY.js +291 -0
  282. package/dist/chunk-RVERAFFY.js.map +1 -0
  283. package/dist/chunk-SMZGAPCU.js +70 -0
  284. package/dist/chunk-SMZGAPCU.js.map +1 -0
  285. package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
  286. package/dist/chunk-SRSJO5QE.js.map +1 -0
  287. package/dist/chunk-T2E5WBCZ.js +482 -0
  288. package/dist/chunk-T2E5WBCZ.js.map +1 -0
  289. package/dist/chunk-TJK44RQC.js +452 -0
  290. package/dist/chunk-TJK44RQC.js.map +1 -0
  291. package/dist/chunk-UIDKY4UB.js +14 -0
  292. package/dist/chunk-UIDKY4UB.js.map +1 -0
  293. package/dist/chunk-V3DX3K65.js +43 -0
  294. package/dist/chunk-V3DX3K65.js.map +1 -0
  295. package/dist/chunk-VZOFZPSO.js +71 -0
  296. package/dist/chunk-VZOFZPSO.js.map +1 -0
  297. package/dist/chunk-W2AC6Q2A.js +83 -0
  298. package/dist/chunk-W2AC6Q2A.js.map +1 -0
  299. package/dist/chunk-WF75U3V4.js +33 -0
  300. package/dist/chunk-WF75U3V4.js.map +1 -0
  301. package/dist/chunk-WTSNV5RG.js +52 -0
  302. package/dist/chunk-WTSNV5RG.js.map +1 -0
  303. package/dist/{chunk-YGN7OMLT.js → chunk-X5QSICJ3.js} +8 -5
  304. package/dist/chunk-X5QSICJ3.js.map +1 -0
  305. package/dist/chunk-YDGNU2OD.js +61 -0
  306. package/dist/chunk-YDGNU2OD.js.map +1 -0
  307. package/dist/collapsible-panel.d.ts +133 -0
  308. package/dist/collapsible-panel.js +131 -0
  309. package/dist/collapsible-panel.js.map +1 -0
  310. package/dist/content-item.d.ts +81 -0
  311. package/dist/content-item.js +4 -0
  312. package/dist/content-item.js.map +1 -0
  313. package/dist/css-values.d.ts +107 -0
  314. package/dist/css-values.js +3 -0
  315. package/dist/css-values.js.map +1 -0
  316. package/dist/device-class.js +33 -5
  317. package/dist/device-class.js.map +1 -1
  318. package/dist/disclosure-arrow.d.ts +6 -1
  319. package/dist/disclosure-arrow.js +2 -1
  320. package/dist/empty-state.d.ts +5 -2
  321. package/dist/empty-state.js +2 -1
  322. package/dist/flex-alignment-4ms8ZbV8.d.ts +5 -0
  323. package/dist/floating-toolbar.d.ts +51 -0
  324. package/dist/floating-toolbar.js +3 -0
  325. package/dist/floating-toolbar.js.map +1 -0
  326. package/dist/grid.d.ts +50 -0
  327. package/dist/grid.js +5 -0
  328. package/dist/grid.js.map +1 -0
  329. package/dist/help-tags-register.d.ts +13 -0
  330. package/dist/help-tags-register.js +9 -0
  331. package/dist/help-tags-register.js.map +1 -0
  332. package/dist/index.d.ts +34 -14
  333. package/dist/index.js +43 -23
  334. package/dist/{menu-action-row.d.ts → list-action-row.d.ts} +21 -9
  335. package/dist/list-action-row.js +8 -0
  336. package/dist/list-action-row.js.map +1 -0
  337. package/dist/list-header.d.ts +99 -0
  338. package/dist/list-header.js +10 -0
  339. package/dist/list-header.js.map +1 -0
  340. package/dist/list-inset-control.d.ts +22 -0
  341. package/dist/list-inset-control.js +3 -0
  342. package/dist/list-inset-control.js.map +1 -0
  343. package/dist/list-inset-text.d.ts +30 -0
  344. package/dist/list-inset-text.js +4 -0
  345. package/dist/list-inset-text.js.map +1 -0
  346. package/dist/list-item.d.ts +62 -0
  347. package/dist/list-item.js +8 -0
  348. package/dist/list-item.js.map +1 -0
  349. package/dist/list.d.ts +63 -0
  350. package/dist/list.js +6 -0
  351. package/dist/list.js.map +1 -0
  352. package/dist/loading-spinner.d.ts +9 -2
  353. package/dist/loading-spinner.js +2 -1
  354. package/dist/lucide-icon.d.ts +9 -2
  355. package/dist/lucide-icon.js +2 -1
  356. package/dist/nav-stack.d.ts +66 -10
  357. package/dist/nav-stack.js +6 -1
  358. package/dist/pane.d.ts +108 -0
  359. package/dist/pane.js +4 -0
  360. package/dist/pane.js.map +1 -0
  361. package/dist/panel-toolbar-DDKh4uKd.d.ts +72 -0
  362. package/dist/popup-menu-register.d.ts +9 -0
  363. package/dist/popup-menu-register.js +244 -0
  364. package/dist/popup-menu-register.js.map +1 -0
  365. package/dist/popup-menu.d.ts +100 -0
  366. package/dist/popup-menu.js +3 -0
  367. package/dist/popup-menu.js.map +1 -0
  368. package/dist/resizable-region.d.ts +32 -3
  369. package/dist/resizable-region.js +1 -1
  370. package/dist/row.d.ts +48 -0
  371. package/dist/row.js +6 -0
  372. package/dist/row.js.map +1 -0
  373. package/dist/segmented-control.d.ts +12 -9
  374. package/dist/segmented-control.js +1 -2
  375. package/dist/select-register.d.ts +5 -1
  376. package/dist/select-register.js +243 -2
  377. package/dist/select-register.js.map +1 -1
  378. package/dist/select.d.ts +102 -8
  379. package/dist/select.js +3 -1
  380. package/dist/semantic-content-BbzjvSu9.d.ts +14 -0
  381. package/dist/sides-BPSWde0A.d.ts +4 -0
  382. package/dist/skeleton.d.ts +14 -7
  383. package/dist/skeleton.js +2 -1
  384. package/dist/spacer.d.ts +18 -0
  385. package/dist/spacer.js +4 -0
  386. package/dist/spacer.js.map +1 -0
  387. package/dist/split-view.d.ts +39 -7
  388. package/dist/split-view.js +120 -10
  389. package/dist/split-view.js.map +1 -1
  390. package/dist/state-banner.d.ts +18 -6
  391. package/dist/state-banner.js +3 -1
  392. package/dist/styles/app-tab.css +221 -0
  393. package/dist/styles/badge.css +118 -0
  394. package/dist/styles/catalog/components/catalog-example-stack.css +9 -0
  395. package/dist/styles/catalog/components/catalog-example.css +168 -0
  396. package/dist/styles/catalog/components/catalog-stage.css +55 -0
  397. package/dist/styles/catalog/components/catalog.css +12 -0
  398. package/dist/styles/catalog.css +5 -0
  399. package/dist/styles/chip.css +132 -0
  400. package/dist/styles/collapsible-panel.css +575 -0
  401. package/dist/styles/content-item.css +75 -0
  402. package/dist/styles/document.css +23 -0
  403. package/dist/styles/floating-toolbar.css +119 -0
  404. package/dist/styles/foundation.css +178 -40
  405. package/dist/styles/grid.css +35 -0
  406. package/dist/styles/layout.css +3 -41
  407. package/dist/styles/list-action-row.css +258 -0
  408. package/dist/styles/list-header.css +229 -0
  409. package/dist/styles/list-inset-control.css +30 -0
  410. package/dist/styles/list-inset-text.css +29 -0
  411. package/dist/styles/list-item.css +255 -0
  412. package/dist/styles/list.css +133 -0
  413. package/dist/styles/loading-spinner.css +4 -0
  414. package/dist/styles/lucide-icon.css +5 -0
  415. package/dist/styles/nav-stack.css +172 -47
  416. package/dist/styles/pane.css +263 -0
  417. package/dist/styles/popup-menu.css +285 -0
  418. package/dist/styles/resizable-region.css +438 -4
  419. package/dist/styles/row.css +111 -0
  420. package/dist/styles/segmented-control.css +36 -9
  421. package/dist/styles/select.css +337 -21
  422. package/dist/styles/skeleton.css +64 -3
  423. package/dist/styles/spacer.css +11 -0
  424. package/dist/styles/split-view.css +114 -3
  425. package/dist/styles/state-banner.css +94 -19
  426. package/dist/styles/styles.css +13 -4
  427. package/dist/styles/sunken-panel.css +29 -0
  428. package/dist/styles/surface-scaffold.css +56 -0
  429. package/dist/styles/tab-bar.css +147 -9
  430. package/dist/styles/tab-scaffold.css +126 -3
  431. package/dist/styles/text.css +112 -0
  432. package/dist/styles/token-search-field.css +155 -55
  433. package/dist/styles/toolbar-control-group.css +608 -29
  434. package/dist/styles/toolbar-text.css +101 -8
  435. package/dist/styles/toolbar.css +334 -12
  436. package/dist/styles/value-table.css +34 -4
  437. package/dist/styles/webawesome.css +365 -10
  438. package/dist/styles/workbench.css +980 -7
  439. package/dist/sunken-panel.d.ts +27 -0
  440. package/dist/sunken-panel.js +3 -0
  441. package/dist/sunken-panel.js.map +1 -0
  442. package/dist/surface-scaffold.d.ts +30 -0
  443. package/dist/surface-scaffold.js +3 -0
  444. package/dist/surface-scaffold.js.map +1 -0
  445. package/dist/tab-bar.d.ts +39 -6
  446. package/dist/tab-bar.js +1 -1
  447. package/dist/tab-scaffold.d.ts +57 -7
  448. package/dist/tab-scaffold.js +83 -9
  449. package/dist/tab-scaffold.js.map +1 -1
  450. package/dist/text.d.ts +56 -0
  451. package/dist/text.js +3 -0
  452. package/dist/text.js.map +1 -0
  453. package/dist/token-search-field-CVGwDn2y.d.ts +154 -0
  454. package/dist/token-search-field.d.ts +3 -43
  455. package/dist/token-search-field.js +2 -1
  456. package/dist/token-search-model.d.ts +3 -0
  457. package/dist/token-search-model.js +3 -0
  458. package/dist/token-search-model.js.map +1 -0
  459. package/dist/toolbar-control-group.d.ts +77 -7
  460. package/dist/toolbar-control-group.js +3 -1
  461. package/dist/toolbar-text.d.ts +35 -4
  462. package/dist/toolbar-text.js +2 -1
  463. package/dist/toolbar.d.ts +59 -7
  464. package/dist/toolbar.js +1 -1
  465. package/dist/types-BuHELdXR.d.ts +117 -0
  466. package/dist/value-table.d.ts +11 -3
  467. package/dist/value-table.js +2 -1
  468. package/dist/webawesome.d.ts +8 -1
  469. package/dist/wire-catalog.d.ts +82 -0
  470. package/dist/wire-catalog.js +327 -0
  471. package/dist/wire-catalog.js.map +1 -0
  472. package/dist/wire-content-items.d.ts +11 -0
  473. package/dist/wire-content-items.js +114 -0
  474. package/dist/wire-content-items.js.map +1 -0
  475. package/dist/wire-nav-stack.d.ts +4 -1
  476. package/dist/wire-nav-stack.js +147 -7
  477. package/dist/wire-nav-stack.js.map +1 -1
  478. package/dist/wire-resizable-regions.d.ts +2 -1
  479. package/dist/wire-resizable-regions.js +2 -1
  480. package/dist/wire-scroll-dividers.d.ts +72 -0
  481. package/dist/wire-scroll-dividers.js +3 -0
  482. package/dist/wire-scroll-dividers.js.map +1 -0
  483. package/dist/wire-sidebar.d.ts +63 -0
  484. package/dist/wire-sidebar.js +231 -0
  485. package/dist/wire-sidebar.js.map +1 -0
  486. package/dist/wire-tab-bars.d.ts +19 -2
  487. package/dist/wire-tab-bars.js +1 -1
  488. package/dist/wire-tab-scaffold.js +9 -4
  489. package/dist/wire-tab-scaffold.js.map +1 -1
  490. package/dist/wire-token-search-fields.d.ts +65 -3
  491. package/dist/wire-token-search-fields.js +2 -1
  492. package/dist/wire-workbench.d.ts +116 -0
  493. package/dist/wire-workbench.js +6 -0
  494. package/dist/wire-workbench.js.map +1 -0
  495. package/dist/workbench.d.ts +244 -9
  496. package/dist/workbench.js +17 -15
  497. package/dist/workbench.js.map +1 -1
  498. package/docs/accessibility.md +476 -24
  499. package/docs/app-layouts.md +106 -8
  500. package/docs/apple-hig.md +1 -0
  501. package/docs/catalog.md +483 -0
  502. package/docs/collapsible-panel.md +371 -0
  503. package/docs/component-contract.md +658 -56
  504. package/docs/component-integration.md +75 -0
  505. package/docs/component-selection.md +529 -90
  506. package/docs/design/templates/empty-state/filtered-dark.svg +1 -0
  507. package/docs/design/templates/empty-state/filtered.svg +1 -0
  508. package/docs/design/templates/empty-state/with-action-dark.svg +1 -0
  509. package/docs/design/templates/empty-state/with-action.svg +1 -0
  510. package/docs/design/templates/empty-state-dark.svg +1 -0
  511. package/docs/design/templates/empty-state.svg +1 -0
  512. package/docs/design/templates/list/compact-dark.svg +1 -0
  513. package/docs/design/templates/list/compact.svg +1 -0
  514. package/docs/design/templates/list/stack-dark.svg +1 -0
  515. package/docs/design/templates/list/stack.svg +1 -0
  516. package/docs/design/templates/list-action-row/default-dark.svg +1 -0
  517. package/docs/design/templates/list-action-row/default.svg +1 -0
  518. package/docs/design/templates/list-action-row/selected-dark.svg +1 -0
  519. package/docs/design/templates/list-action-row/selected.svg +1 -0
  520. package/docs/design/templates/list-action-row-dark.svg +1 -0
  521. package/docs/design/templates/list-action-row.svg +1 -0
  522. package/docs/design/templates/list-dark.svg +1 -0
  523. package/docs/design/templates/list-header/action-dark.svg +1 -0
  524. package/docs/design/templates/list-header/action.svg +1 -0
  525. package/docs/design/templates/list-header/count-dark.svg +1 -0
  526. package/docs/design/templates/list-header/count.svg +1 -0
  527. package/docs/design/templates/list-header/inline-action-dark.svg +1 -0
  528. package/docs/design/templates/list-header/inline-action.svg +1 -0
  529. package/docs/design/templates/list-header/toggle-collapsed-dark.svg +1 -0
  530. package/docs/design/templates/list-header/toggle-collapsed.svg +1 -0
  531. package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -0
  532. package/docs/design/templates/list-header/toggle-expanded.svg +1 -0
  533. package/docs/design/templates/list-header-dark.svg +1 -0
  534. package/docs/design/templates/list-header.svg +1 -0
  535. package/docs/design/templates/list-item/default-dark.svg +1 -0
  536. package/docs/design/templates/list-item/default.svg +1 -0
  537. package/docs/design/templates/list-item/multiline-dark.svg +1 -0
  538. package/docs/design/templates/list-item/multiline.svg +1 -0
  539. package/docs/design/templates/list-item/selected-dark.svg +1 -0
  540. package/docs/design/templates/list-item/selected.svg +1 -0
  541. package/docs/design/templates/list-item/trailing-dark.svg +1 -0
  542. package/docs/design/templates/list-item/trailing.svg +1 -0
  543. package/docs/design/templates/list-item-dark.svg +1 -0
  544. package/docs/design/templates/list-item.svg +1 -0
  545. package/docs/design/templates/list.svg +1 -0
  546. package/docs/design/templates/segmented-control/equal-dark.svg +1 -0
  547. package/docs/design/templates/segmented-control/equal.svg +1 -0
  548. package/docs/design/templates/segmented-control/pill-small-dark.svg +1 -0
  549. package/docs/design/templates/segmented-control/pill-small.svg +1 -0
  550. package/docs/design/templates/segmented-control-dark.svg +1 -0
  551. package/docs/design/templates/segmented-control.svg +1 -0
  552. package/docs/design/templates/skeleton/avatar-dark.svg +1 -0
  553. package/docs/design/templates/skeleton/avatar.svg +1 -0
  554. package/docs/design/templates/skeleton/block-dark.svg +1 -0
  555. package/docs/design/templates/skeleton/block.svg +1 -0
  556. package/docs/design/templates/skeleton/lines-dark.svg +1 -0
  557. package/docs/design/templates/skeleton/lines.svg +1 -0
  558. package/docs/design/templates/skeleton-dark.svg +1 -0
  559. package/docs/design/templates/skeleton.svg +1 -0
  560. package/docs/design/templates/state-banner/danger-dark.svg +1 -0
  561. package/docs/design/templates/state-banner/danger.svg +1 -0
  562. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -0
  563. package/docs/design/templates/state-banner/info-badge.svg +1 -0
  564. package/docs/design/templates/state-banner/info-dark.svg +1 -0
  565. package/docs/design/templates/state-banner/info.svg +1 -0
  566. package/docs/design/templates/state-banner/success-dark.svg +1 -0
  567. package/docs/design/templates/state-banner/success.svg +1 -0
  568. package/docs/design/templates/state-banner/warning-dark.svg +1 -0
  569. package/docs/design/templates/state-banner/warning.svg +1 -0
  570. package/docs/design/templates/state-banner-dark.svg +1 -0
  571. package/docs/design/templates/state-banner.svg +1 -0
  572. package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -0
  573. package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -0
  574. package/docs/design/templates/tab-bar-dark.svg +1 -0
  575. package/docs/design/templates/tab-bar.svg +1 -0
  576. package/docs/design/templates/token-search-field/empty-dark.svg +1 -0
  577. package/docs/design/templates/token-search-field/empty.svg +1 -0
  578. package/docs/design/templates/token-search-field/tokens-dark.svg +1 -0
  579. package/docs/design/templates/token-search-field/tokens.svg +1 -0
  580. package/docs/design/templates/token-search-field-dark.svg +1 -0
  581. package/docs/design/templates/token-search-field.svg +1 -0
  582. package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -0
  583. package/docs/design/templates/toolbar/title-and-actions.svg +1 -0
  584. package/docs/design/templates/toolbar-control-group/borderless-single-dark.svg +1 -0
  585. package/docs/design/templates/toolbar-control-group/borderless-single.svg +1 -0
  586. package/docs/design/templates/toolbar-control-group/icon-buttons-dark.svg +1 -0
  587. package/docs/design/templates/toolbar-control-group/icon-buttons.svg +1 -0
  588. package/docs/design/templates/toolbar-control-group/push-buttons-dark.svg +1 -0
  589. package/docs/design/templates/toolbar-control-group/push-buttons.svg +1 -0
  590. package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -0
  591. package/docs/design/templates/toolbar-control-group/with-text.svg +1 -0
  592. package/docs/design/templates/toolbar-control-group-dark.svg +1 -0
  593. package/docs/design/templates/toolbar-control-group.svg +1 -0
  594. package/docs/design/templates/toolbar-dark.svg +1 -0
  595. package/docs/design/templates/toolbar-text/default-dark.svg +1 -0
  596. package/docs/design/templates/toolbar-text/default.svg +1 -0
  597. package/docs/design/templates/toolbar-text/large-dark.svg +1 -0
  598. package/docs/design/templates/toolbar-text/large.svg +1 -0
  599. package/docs/design/templates/toolbar-text/small-dark.svg +1 -0
  600. package/docs/design/templates/toolbar-text/small.svg +1 -0
  601. package/docs/design/templates/toolbar-text-dark.svg +1 -0
  602. package/docs/design/templates/toolbar-text.svg +1 -0
  603. package/docs/design/templates/toolbar.svg +1 -0
  604. package/docs/design/templates/value-table/details-dark.svg +1 -0
  605. package/docs/design/templates/value-table/details.svg +1 -0
  606. package/docs/design/templates/value-table-dark.svg +1 -0
  607. package/docs/design/templates/value-table.svg +1 -0
  608. package/docs/design/templates.md +138 -0
  609. package/docs/design-philosophy.md +48 -20
  610. package/docs/device-class.md +10 -9
  611. package/docs/document-baseline.md +38 -0
  612. package/docs/examples/application-ui-profile.json +60 -0
  613. package/docs/examples/command-palette-adapter.tsx +69 -17
  614. package/docs/examples/component-catalog-extension.json +52 -0
  615. package/docs/examples/component-composition-extension.json +80 -0
  616. package/docs/layout.md +534 -59
  617. package/docs/nav-stack.md +138 -14
  618. package/docs/recipes.md +137 -54
  619. package/docs/split-view.md +74 -6
  620. package/docs/sunken-panel.md +87 -0
  621. package/docs/surface-scaffold.md +28 -0
  622. package/docs/tab-scaffold.md +99 -10
  623. package/docs/type-contracts.md +134 -0
  624. package/docs/ui-analyzer.md +347 -0
  625. package/docs/ui-doctor.md +128 -0
  626. package/docs/ui-evaluator.md +139 -0
  627. package/docs/ux-demo.md +41 -16
  628. package/docs/webawesome-theme.md +218 -16
  629. package/docs/workbench.md +608 -12
  630. package/doctor/cli.mjs +120 -0
  631. package/doctor/config.schema.json +72 -0
  632. package/doctor/eslint-diagnostics.d.mts +24 -0
  633. package/doctor/eslint-diagnostics.mjs +24 -0
  634. package/doctor/index.d.mts +121 -0
  635. package/doctor/index.mjs +1324 -0
  636. package/doctor/report.schema.json +118 -0
  637. package/evaluator/cli.mjs +89 -0
  638. package/evaluator/index.d.mts +90 -0
  639. package/evaluator/index.mjs +1203 -0
  640. package/evaluator/report.schema.json +152 -0
  641. package/llms.txt +445 -48
  642. package/package.json +249 -37
  643. package/scripts/component-catalog-extension-validation.mjs +28 -0
  644. package/traversal-exclusions.mjs +27 -0
  645. package/ux-demo/recipes/app-shell.tsx +205 -17
  646. package/ux-demo/recipes/collapsible-sidebar.tsx +260 -0
  647. package/ux-demo/recipes/compact-toolbar.tsx +135 -14
  648. package/ux-demo/recipes/composer-form.tsx +133 -21
  649. package/ux-demo/recipes/list-detail-dialog.tsx +282 -0
  650. package/ux-demo/recipes/list-workspace-states.tsx +183 -11
  651. package/ux-demo/recipes/loaders.ts +15 -5
  652. package/ux-demo/recipes/loading-inspector.tsx +204 -0
  653. package/ux-demo/recipes/mount-recipe.ts +28 -10
  654. package/ux-demo/recipes/navigation-sidebar.tsx +139 -13
  655. package/ux-demo/recipes/navigation-stack.tsx +79 -24
  656. package/ux-demo/recipes/types.ts +23 -2
  657. package/ux-demo/recipes/workspace-header.tsx +86 -5
  658. package/dist/browser/menu-action-row.js +0 -4
  659. package/dist/browser/menu-item.js +0 -4
  660. package/dist/chunk-2RJBFNB6.js +0 -172
  661. package/dist/chunk-2RJBFNB6.js.map +0 -1
  662. package/dist/chunk-2Z5TWHKQ.js +0 -34
  663. package/dist/chunk-2Z5TWHKQ.js.map +0 -1
  664. package/dist/chunk-3YD6ZNRA.js +0 -34
  665. package/dist/chunk-3YD6ZNRA.js.map +0 -1
  666. package/dist/chunk-55DATV3A.js +0 -10
  667. package/dist/chunk-55DATV3A.js.map +0 -1
  668. package/dist/chunk-56RJXPHG.js.map +0 -1
  669. package/dist/chunk-7BR3DO2A.js.map +0 -1
  670. package/dist/chunk-7LDCTU7D.js +0 -134
  671. package/dist/chunk-7LDCTU7D.js.map +0 -1
  672. package/dist/chunk-AQNKJRFH.js +0 -79
  673. package/dist/chunk-AQNKJRFH.js.map +0 -1
  674. package/dist/chunk-B24C4A6T.js +0 -22
  675. package/dist/chunk-B24C4A6T.js.map +0 -1
  676. package/dist/chunk-DAFFDO33.js +0 -14
  677. package/dist/chunk-DAFFDO33.js.map +0 -1
  678. package/dist/chunk-H6URQGJI.js +0 -42
  679. package/dist/chunk-H6URQGJI.js.map +0 -1
  680. package/dist/chunk-I7INRJO4.js +0 -17
  681. package/dist/chunk-I7INRJO4.js.map +0 -1
  682. package/dist/chunk-KJYXOTG3.js +0 -10
  683. package/dist/chunk-KJYXOTG3.js.map +0 -1
  684. package/dist/chunk-LC3YSAZC.js +0 -39
  685. package/dist/chunk-LC3YSAZC.js.map +0 -1
  686. package/dist/chunk-M5JRI6MN.js +0 -27
  687. package/dist/chunk-M5JRI6MN.js.map +0 -1
  688. package/dist/chunk-MBR3TYNL.js +0 -14
  689. package/dist/chunk-MBR3TYNL.js.map +0 -1
  690. package/dist/chunk-MFKMHK5W.js +0 -10
  691. package/dist/chunk-MFKMHK5W.js.map +0 -1
  692. package/dist/chunk-MQIZAD4A.js +0 -227
  693. package/dist/chunk-MQIZAD4A.js.map +0 -1
  694. package/dist/chunk-N3SUXLLS.js +0 -23
  695. package/dist/chunk-N3SUXLLS.js.map +0 -1
  696. package/dist/chunk-PONXLV5U.js +0 -19
  697. package/dist/chunk-PONXLV5U.js.map +0 -1
  698. package/dist/chunk-TZNCCM5H.js +0 -20
  699. package/dist/chunk-TZNCCM5H.js.map +0 -1
  700. package/dist/chunk-W2FK7ZNY.js +0 -26
  701. package/dist/chunk-W2FK7ZNY.js.map +0 -1
  702. package/dist/chunk-WVPYVDXY.js +0 -15
  703. package/dist/chunk-WVPYVDXY.js.map +0 -1
  704. package/dist/chunk-YGN7OMLT.js.map +0 -1
  705. package/dist/chunk-YKUUZPED.js +0 -24
  706. package/dist/chunk-YKUUZPED.js.map +0 -1
  707. package/dist/menu-action-row.js +0 -5
  708. package/dist/menu-action-row.js.map +0 -1
  709. package/dist/menu-header.d.ts +0 -43
  710. package/dist/menu-header.js +0 -7
  711. package/dist/menu-header.js.map +0 -1
  712. package/dist/menu-item.d.ts +0 -33
  713. package/dist/menu-item.js +0 -5
  714. package/dist/menu-item.js.map +0 -1
  715. package/dist/panel-header.d.ts +0 -28
  716. package/dist/panel-header.js +0 -7
  717. package/dist/panel-header.js.map +0 -1
  718. package/dist/styles/menu-action-row.css +0 -160
  719. package/dist/styles/menu-header.css +0 -160
  720. package/dist/styles/menu-item.css +0 -123
  721. package/dist/styles/panel-header.css +0 -64
  722. package/ux-demo/recipes/master-detail-dialog.tsx +0 -45
  723. package/ux-demo/recipes/recipes.css +0 -355
package/docs/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,147 @@ 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
+ Each view can also provide `header`, pinned below its top toolbar and above
61
+ that view's single scroll area. A fixed heading, notice, or section selector
62
+ can therefore change with the active screen without adding another scroller.
63
+ The back control appears automatically once the stack has more than one entry;
64
+ `wireNavStack`'s `onBack` is where the app pops its own signal.
65
+
66
+ Set a view's `appearance: "sunken"` to paint its scroll viewport with the
67
+ shared lowered-surface color, including space after short content. When the
68
+ view holds a `Pane` as its only child, set the appearance on the Pane instead
69
+ if its content owns scrolling. See [Lowered work surfaces](layout.md#lowered-work-surfaces).
70
+
71
+ ## The top toolbar
72
+
73
+ The top chrome is a real `Toolbar`, so it follows the same zone,
74
+ group, and responsive rules as every other toolbar. Its leading zone holds the
75
+ back control (a borderless `ToolbarControlGroup`, shown once the stack has
76
+ depth), then the active view's `leading` groups, then the view's `title` as a
77
+ `ToolbarText`. The view's `center` fills the center zone and its `toolbar`
78
+ fills the trailing zone. Give each zone `ToolbarControlGroup`s or `ToolbarText`,
79
+ as in any toolbar.
80
+
81
+ Configure the toolbar with `toolbarConfig` instead of styling it:
82
+
83
+ ```tsx
84
+ <NavStack
85
+ id="mail"
86
+ label="Mail"
87
+ views={views.value}
88
+ backText={previousTitle}
89
+ toolbarConfig={{
90
+ headingLevel: 1,
91
+ titleSize: "xlarge",
92
+ dividerSides: "b",
93
+ responsive: "wrap",
94
+ }}
95
+ />
96
+ ```
97
+
98
+ - `toolbarConfig` forwards the `Toolbar` configuration (`dividerSides`,
99
+ `centerAlign`, `responsive`, `responsiveAt`, `safeAreaEdges`) and adds
100
+ `label` (the toolbar's accessible name), `titleSize` (the title's
101
+ `ToolbarText` size, default `large`), and `headingLevel` (expose the title as
102
+ a heading; default a plain span). The defaults keep the stack's own chrome:
103
+ no divider, the standard Toolbar height (a 44px control band with 8px above and below), and the top and side safe-area edges
104
+ claimed.
105
+ - `backIcon` replaces the default chevron-left icon. `backText` adds visible
106
+ text beside it (for example, the previous view's title); visible text names
107
+ the control, so `backLabel` applies only to the icon-only control.
108
+
109
+ `panelToggle` supplies a persistent final group in the trailing zone of every
110
+ view's top toolbar. `Workbench` uses it for a navigation panel's standard
111
+ collapse toggle; the active view still owns the preceding toolbar groups.
112
+
113
+ The catalog's **Configured toolbar** example shows these together: a level-2
114
+ heading title over a bottom divider, leading and center groups on the root
115
+ view, a trailing group on the pushed view, and `backText` set to the previous
116
+ view's title.
117
+
118
+ Focus follows the controlled stack automatically. On push, `wireNavStack`
119
+ remembers the focused descendant of the departing view and moves focus into the
120
+ new top view. On pop it restores that exact descendant when it still exists. A
121
+ new view prefers a descendant marked `data-nav-focus`, then its first enabled
122
+ focusable descendant, and finally the view container itself. Use
123
+ `data-nav-focus` for a heading or primary control when DOM order is not the best
124
+ initial reading position; it may use `tabindex="-1"` for programmatic focus.
125
+ When a remembered control was removed during the controlled rerender, the same
126
+ fallback order applies. Disposing the helper stops future transitions and
127
+ cleans up any temporary fallback `tabindex` it added.
128
+
129
+ ## Scroll dividers
130
+
131
+ The stack draws no permanent line between its chrome and the view. With
132
+ `wireScrollDividers(appRoot)` installed (see
133
+ [Layout › Scroll dividers](layout.md#scroll-dividers)), the top chrome shows a
134
+ line along its bottom edge only while the active view's content is scrolled
135
+ beneath it, and the bottom toolbar a line along its top edge only while more
136
+ content lies below it — neither when the content fits. The line follows the
137
+ active view across a push or pop. The chrome's line is overlaid on its bottom
138
+ edge and the bottom toolbar's is its always-present 1px top border, colored
139
+ only while shown, so neither ever moves the chrome or the content. When the view's only child is a `Pane`,
140
+ the line keys on whichever actually scrolls — the view, or the Pane's content —
141
+ and a Pane header or footer draws its own boundary instead. An explicit
142
+ `toolbarConfig.dividerSides` still draws a permanent Toolbar edge.
143
+
144
+ `chromeDividers` configures both lines, with the same values as a `Pane`'s:
145
+ `scroll` (the default) follows the scroll state above and draws nothing until
146
+ the wiring runs; `always` keeps both lines, with or without the wiring; `none`
147
+ drops them even when the wiring reports scroll state. It does not change the
148
+ top Toolbar's own `dividerSides`.
149
+
150
+ ```tsx
151
+ <NavStack id="settings" label="Settings" views={views.value} chromeDividers="always" />
152
+ ```
153
+
154
+ ## Safe areas
155
+
156
+ The stack paints through a device's unsafe areas. Its chrome pads for the top
157
+ and side insets, its bottom toolbar for the bottom and side insets, and each
158
+ view pads the remaining edges inside its scroller, so content scrolls under the
159
+ unsafe area but can always be scrolled clear. A view whose only child is a
160
+ `Pane` or layout lets that child own the insets. See [Choosing an app layout › Safe areas](app-layouts.md#safe-areas).
40
161
 
41
162
  ## Transitions
42
163
 
43
164
  `wireNavStack(root, { onBack, duration? })` observes the rendered stack and
44
165
  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.
166
+ view slides back off it over the revealed view; and snapshots of the previous
167
+ top and bottom chrome cross-fade into the active view's chrome. Focus moves to
168
+ the new top view independently of animation duration. It returns a disposer.
169
+ The animation honors `prefers-reduced-motion` (transitions collapse to instant)
170
+ and `duration: 0` disables it. Applicable at every device size and inside
171
+ 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,36 @@
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
+
29
+ For a lowered list or detail background, render a `Pane` in that region with
30
+ `appearance="sunken"`. SplitView arranges regions but does not own their
31
+ vertical scroll; its compact NavStack form can use the view's or nested Pane's
32
+ appearance. See [Lowered work surfaces](layout.md#lowered-work-surfaces).
33
+
16
34
  ## Responsive by device class
17
35
 
18
36
  `SplitView` is declarative; the app derives `compact` from the device class and
@@ -45,5 +63,55 @@ const selected = signal<string | null>(null);
45
63
  app's selection). This is the portrait-tablet / handset presentation; as a
46
64
  dialog the compact form is a full-screen or large partial-cover modal.
47
65
 
66
+ ## Configuring the list region and the compact stack
67
+
68
+ `resizable` forwards the list's `ResizableRegion` configuration alongside
69
+ `size`, `min`, and `max`: `separator` (`"hidden"` keeps the resize hit target
70
+ but paints no line), `handleIcon`, `contentOverflow`, and collapse —
71
+ `collapsed`, `transitioning`, `collapseMotion`, `restoreControl`, and
72
+ `restorePosition`. A collapsed list snaps to zero width, renders `inert` and
73
+ `aria-hidden`, and the detail fills the split; the app owns the `collapsed`
74
+ flag and renders the restore control (usually a `FloatingToolbar`). Omitted
75
+ options keep the region's defaults.
76
+
77
+ ```tsx
78
+ resizable={{
79
+ size: listWidth.value,
80
+ min: 220,
81
+ max: 480,
82
+ collapsed: listCollapsed.value,
83
+ restoreControl: <ShowThreadsToolbar />,
84
+ }}
85
+ ```
86
+
87
+ `compactStack` configures the compact `NavStack`: `toolbarConfig`, `backIcon`,
88
+ `backText`, `hideToolbar`, the persistent `bottomToolbar`, and `chromeDividers`
89
+ forward to the stack, and `list` / `detail` give each view its own top-toolbar groups
90
+ (`leading`, `center`, trailing `toolbar`) and `bottomToolbar`:
91
+
92
+ ```tsx
93
+ compactStack={{
94
+ backText: "Threads",
95
+ toolbarConfig: { headingLevel: 1 },
96
+ list: { toolbar: <ComposeGroup /> },
97
+ detail: { toolbar: <ReplyGroup />, bottomToolbar: <MessageActions /> },
98
+ }}
99
+ ```
100
+
101
+ The catalog's **Interactive compact drill-down** example exercises this exact
102
+ controlled flow: a list action sets the selected message, `detailActive` pushes
103
+ its detail, and the wired Back action clears the selection to reveal the
104
+ preserved list. It also forwards `compactStack`: a level-2 heading title over
105
+ a bottom divider, a Compose group on the list view, and a Reply group plus a
106
+ bottom toolbar on the detail. Use the same structure in application demos so
107
+ compact examples show the interaction rather than rendering a disconnected
108
+ detail state.
109
+
110
+ The catalog's **Resizable, collapsible list** example forwards `resizable`: a
111
+ hidden separator that still resizes the list (its committed width comes back
112
+ through `wireResizableRegions`' `onCommit` into the app's size signal), a Hide
113
+ control in the list's own toolbar, and a `FloatingToolbar` restore control in
114
+ the split's bottom-start corner.
115
+
48
116
  Compose the interactive wiring from the existing helpers — `SplitView` adds no
49
117
  wire of its own.
@@ -0,0 +1,87 @@
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
+ ## Filling a work area
27
+
28
+ Set `fill` when the panel is the direct layout root of a parent with a definite
29
+ height. Inside a flex column, use `flex` so it takes the remaining space and
30
+ can shrink with its parent. Like `Grid`, `flex` accepts `true` (equivalent to
31
+ `1 1 auto`), a CSS flex keyword, or a typed `CssFlex` value. The panel keeps
32
+ `min-height: 0`, allowing its parent to own scrolling.
33
+
34
+ ```tsx
35
+ <List fill>
36
+ <Toolbar label="Work area" />
37
+ <SunkenPanel flex>
38
+ <WorkArea />
39
+ </SunkenPanel>
40
+ </List>
41
+ ```
42
+
43
+ Inside a `Pane`, the Pane's content remains the scroll owner. Place a
44
+ `SunkenPanel fill` in a definite-height Pane content region when the surface
45
+ itself needs to cover empty space, or use `flex` when a flex parent allocates
46
+ the remaining space. The panel does not add another scroller.
47
+
48
+ ## Ownership
49
+
50
+ The root owns its lowered background, 8px padding, and 8px vertical gap.
51
+ Children own their borders and internal geometry. The application owns child
52
+ order, responsive placement, and scrolling; `SunkenPanel` deliberately does not
53
+ create another scroll container.
54
+
55
+ Use `ariaLabel` only when the surface is a distinct region people need to find
56
+ by name. With a label, the root receives `role="region"`; without one it remains
57
+ a non-landmark grouping.
58
+
59
+ Do not use `SunkenPanel` merely to add padding, as a substitute for pane
60
+ header/content/footer anatomy, or around a child that already owns the same
61
+ outer surface.
62
+
63
+ For a lowered scrolling work area with Pane chrome, use
64
+ [`Pane appearance="sunken"`](layout.md#lowered-work-surfaces). It paints the
65
+ scroll viewport and empty space without adding a second scroller.
66
+
67
+ ## Public styling boundary
68
+
69
+ Override the public properties at the composition boundary:
70
+
71
+ - `--kui-sunken-panel-background`
72
+ - `--kui-sunken-panel-foreground`
73
+ - `--kui-sunken-panel-padding`
74
+ - `--kui-sunken-panel-gap`
75
+ - `--kui-sunken-panel-radius`
76
+
77
+ `--kui-sunken-panel-background` can be overridden for a known backdrop. Keep
78
+ the default lowered surface opaque; a translucent override compounds when
79
+ sunken panels nest. See [Contextual transparency](./webawesome-theme.md#contextual-transparency)
80
+ for the color and contrast evaluation and its opt-in bounded prototype. The
81
+ prototype also compares Pane and Web Awesome sunken surfaces. Assign its
82
+ first, second, and transparent deeper tints on application-owned wrappers;
83
+ a single translucent override on every nested surface has no depth cap.
84
+
85
+ The public root class is `.kui-sunken-panel`. Prefer the properties above over
86
+ styling descendants. The `square` shape deliberately overrides the radius
87
+ property with zero; use `rounded` when customizing the radius token.