@kerfjs/ui 5.0.0-beta.54 → 5.0.0-beta.56

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 (274) hide show
  1. package/README.md +14 -11
  2. package/ai/compile-time-contracts-v1.json +2 -2
  3. package/ai/component-catalog-v2.json +206 -39
  4. package/ai/component-catalog.json +306 -58
  5. package/ai/public-api-signatures-v1.md +671 -92
  6. package/ai/skill.md +43 -38
  7. package/ai/webawesome-jsx-signatures-v1.md +8 -2
  8. package/dist/app-tab.js +1 -1
  9. package/dist/badge.d.ts +35 -7
  10. package/dist/badge.js +1 -1
  11. package/dist/browser/content-item.js +3 -0
  12. package/dist/browser/popup-menu.js +3 -0
  13. package/dist/browser/select.js +1 -0
  14. package/dist/catalog-resources.d.ts +12 -1
  15. package/dist/catalog.d.ts +21 -4
  16. package/dist/catalog.js +260 -308
  17. package/dist/catalog.js.map +1 -1
  18. package/dist/{chunk-7IUSV4XG.js → chunk-24PHKUR3.js} +2 -2
  19. package/dist/chunk-24PHKUR3.js.map +1 -0
  20. package/dist/{chunk-WZ2GLEY4.js → chunk-2G2ZJQYK.js} +2 -14
  21. package/dist/chunk-2G2ZJQYK.js.map +1 -0
  22. package/dist/{chunk-D7GWXIAS.js → chunk-5I7QGQVT.js} +1 -1
  23. package/dist/chunk-5I7QGQVT.js.map +1 -0
  24. package/dist/{chunk-HJKRCKDR.js → chunk-63ZWBGE3.js} +6 -3
  25. package/dist/chunk-63ZWBGE3.js.map +1 -0
  26. package/dist/{chunk-44IG7PFV.js → chunk-6CINWX2E.js} +3 -3
  27. package/dist/{chunk-44IG7PFV.js.map → chunk-6CINWX2E.js.map} +1 -1
  28. package/dist/{chunk-C2FAYFDE.js → chunk-AGXQQFKZ.js} +2 -2
  29. package/dist/{chunk-C2FAYFDE.js.map → chunk-AGXQQFKZ.js.map} +1 -1
  30. package/dist/{chunk-ATHXW6RP.js → chunk-AHEG27M7.js} +2 -2
  31. package/dist/{chunk-ATHXW6RP.js.map → chunk-AHEG27M7.js.map} +1 -1
  32. package/dist/{chunk-7GUQYHKA.js → chunk-AK67F6QN.js} +4 -1
  33. package/dist/chunk-AK67F6QN.js.map +1 -0
  34. package/dist/chunk-BFPBS5Y4.js +250 -0
  35. package/dist/chunk-BFPBS5Y4.js.map +1 -0
  36. package/dist/chunk-DG6G5EPF.js +35 -0
  37. package/dist/chunk-DG6G5EPF.js.map +1 -0
  38. package/dist/{chunk-MTM43SJO.js → chunk-G33XC2NB.js} +1 -1
  39. package/dist/chunk-G33XC2NB.js.map +1 -0
  40. package/dist/{chunk-TZ5IHWB2.js → chunk-K6UNVKDK.js} +3 -3
  41. package/dist/{chunk-TZ5IHWB2.js.map → chunk-K6UNVKDK.js.map} +1 -1
  42. package/dist/chunk-KH6VUGHU.js +399 -0
  43. package/dist/chunk-KH6VUGHU.js.map +1 -0
  44. package/dist/{chunk-HMQ2ZDGG.js → chunk-KROD7KZK.js} +3 -2
  45. package/dist/chunk-KROD7KZK.js.map +1 -0
  46. package/dist/{chunk-5NDQABWK.js → chunk-M7QV3IHH.js} +3 -1
  47. package/dist/chunk-M7QV3IHH.js.map +1 -0
  48. package/dist/{chunk-RNZAKSME.js → chunk-MA6Z6EIM.js} +3 -3
  49. package/dist/{chunk-RNZAKSME.js.map → chunk-MA6Z6EIM.js.map} +1 -1
  50. package/dist/chunk-MA73TA6D.js +42 -0
  51. package/dist/chunk-MA73TA6D.js.map +1 -0
  52. package/dist/{chunk-ZMBU522F.js → chunk-MEY33VWB.js} +2 -2
  53. package/dist/{chunk-ZMBU522F.js.map → chunk-MEY33VWB.js.map} +1 -1
  54. package/dist/{chunk-T22EM4ET.js → chunk-MOBRFZH3.js} +81 -31
  55. package/dist/chunk-MOBRFZH3.js.map +1 -0
  56. package/dist/chunk-MP2GDBQZ.js +50 -0
  57. package/dist/chunk-MP2GDBQZ.js.map +1 -0
  58. package/dist/{chunk-3NBL3OUQ.js → chunk-NAPE7WUS.js} +2 -2
  59. package/dist/chunk-NAPE7WUS.js.map +1 -0
  60. package/dist/{chunk-CMUIXJZM.js → chunk-NBYTIVHS.js} +2 -2
  61. package/dist/{chunk-CMUIXJZM.js.map → chunk-NBYTIVHS.js.map} +1 -1
  62. package/dist/chunk-O3EXIBEZ.js +114 -0
  63. package/dist/chunk-O3EXIBEZ.js.map +1 -0
  64. package/dist/{chunk-KPNTVB7A.js → chunk-PK4N5QTO.js} +8 -7
  65. package/dist/chunk-PK4N5QTO.js.map +1 -0
  66. package/dist/chunk-QQOTQTDD.js +415 -0
  67. package/dist/chunk-QQOTQTDD.js.map +1 -0
  68. package/dist/{chunk-BJJKFVWW.js → chunk-T4UZTNZ4.js} +5 -5
  69. package/dist/chunk-T4UZTNZ4.js.map +1 -0
  70. package/dist/chunk-V65EOWNF.js +83 -0
  71. package/dist/chunk-V65EOWNF.js.map +1 -0
  72. package/dist/{chunk-GUIHMIT2.js → chunk-VNPQDCQZ.js} +3 -3
  73. package/dist/{chunk-GUIHMIT2.js.map → chunk-VNPQDCQZ.js.map} +1 -1
  74. package/dist/{chunk-5I22LMCV.js → chunk-VZOFZPSO.js} +2 -2
  75. package/dist/chunk-VZOFZPSO.js.map +1 -0
  76. package/dist/chunk-WLG6SSNT.js +94 -0
  77. package/dist/chunk-WLG6SSNT.js.map +1 -0
  78. package/dist/{chunk-NE5JAOQS.js → chunk-WOUF7YXM.js} +3 -3
  79. package/dist/{chunk-NE5JAOQS.js.map → chunk-WOUF7YXM.js.map} +1 -1
  80. package/dist/collapsible-panel.d.ts +51 -13
  81. package/dist/collapsible-panel.js +38 -10
  82. package/dist/collapsible-panel.js.map +1 -1
  83. package/dist/content-item.d.ts +46 -0
  84. package/dist/content-item.js +4 -0
  85. package/dist/content-item.js.map +1 -0
  86. package/dist/css-values.d.ts +5 -11
  87. package/dist/css-values.js +1 -1
  88. package/dist/disclosure-arrow.d.ts +4 -1
  89. package/dist/disclosure-arrow.js +1 -1
  90. package/dist/floating-toolbar.d.ts +17 -6
  91. package/dist/floating-toolbar.js +1 -1
  92. package/dist/grid.js +1 -1
  93. package/dist/help-tags-register.d.ts +13 -0
  94. package/dist/help-tags-register.js +9 -0
  95. package/dist/help-tags-register.js.map +1 -0
  96. package/dist/index.d.ts +7 -5
  97. package/dist/index.js +31 -29
  98. package/dist/list-action-row.js +1 -1
  99. package/dist/list-header.d.ts +14 -1
  100. package/dist/list-header.js +1 -1
  101. package/dist/list-inset-control.d.ts +1 -1
  102. package/dist/list-inset-control.js +1 -1
  103. package/dist/list-inset-text.d.ts +9 -10
  104. package/dist/list-inset-text.js +2 -1
  105. package/dist/list-item.js +1 -1
  106. package/dist/list.d.ts +10 -3
  107. package/dist/list.js +1 -1
  108. package/dist/nav-stack.d.ts +38 -5
  109. package/dist/nav-stack.js +4 -1
  110. package/dist/pane.d.ts +20 -2
  111. package/dist/pane.js +1 -1
  112. package/dist/panel-toolbar-C8sF-YZC.d.ts +63 -0
  113. package/dist/popup-menu-register.d.ts +9 -0
  114. package/dist/popup-menu-register.js +31 -0
  115. package/dist/popup-menu-register.js.map +1 -0
  116. package/dist/popup-menu.d.ts +71 -0
  117. package/dist/popup-menu.js +3 -0
  118. package/dist/popup-menu.js.map +1 -0
  119. package/dist/row.d.ts +1 -1
  120. package/dist/row.js +1 -1
  121. package/dist/select-register.js +70 -3
  122. package/dist/select-register.js.map +1 -1
  123. package/dist/select.d.ts +46 -8
  124. package/dist/select.js +2 -1
  125. package/dist/{divider-sides-BzB6rphT.d.ts → sides-BPSWde0A.d.ts} +1 -3
  126. package/dist/skeleton.js +1 -1
  127. package/dist/spacer.js +1 -1
  128. package/dist/split-view.d.ts +31 -3
  129. package/dist/split-view.js +33 -5
  130. package/dist/split-view.js.map +1 -1
  131. package/dist/state-banner.js +1 -1
  132. package/dist/styles/badge.css +13 -0
  133. package/dist/styles/catalog/components/catalog-example.css +1 -17
  134. package/dist/styles/catalog/components/catalog-stage.css +9 -14
  135. package/dist/styles/catalog/components/catalog.css +8 -18
  136. package/dist/styles/catalog.css +0 -5
  137. package/dist/styles/collapsible-panel.css +192 -39
  138. package/dist/styles/content-item.css +30 -0
  139. package/dist/styles/floating-toolbar.css +5 -0
  140. package/dist/styles/foundation.css +28 -19
  141. package/dist/styles/layout.css +1 -21
  142. package/dist/styles/list-action-row.css +13 -1
  143. package/dist/styles/list-inset-text.css +1 -2
  144. package/dist/styles/list-item.css +14 -1
  145. package/dist/styles/list.css +1 -1
  146. package/dist/styles/nav-stack.css +29 -64
  147. package/dist/styles/pane.css +33 -1
  148. package/dist/styles/popup-menu.css +90 -0
  149. package/dist/styles/resizable-region.css +53 -10
  150. package/dist/styles/select.css +39 -12
  151. package/dist/styles/split-view.css +21 -25
  152. package/dist/styles/state-banner.css +13 -4
  153. package/dist/styles/styles.css +1 -0
  154. package/dist/styles/tab-bar.css +31 -3
  155. package/dist/styles/tab-scaffold.css +36 -14
  156. package/dist/styles/text.css +1 -1
  157. package/dist/styles/token-search-field.css +4 -4
  158. package/dist/styles/toolbar-control-group.css +44 -12
  159. package/dist/styles/toolbar.css +57 -7
  160. package/dist/styles/value-table.css +19 -2
  161. package/dist/styles/webawesome.css +3 -1
  162. package/dist/styles/workbench.css +165 -31
  163. package/dist/tab-scaffold.d.ts +35 -1
  164. package/dist/tab-scaffold.js +50 -16
  165. package/dist/tab-scaffold.js.map +1 -1
  166. package/dist/text.js +1 -1
  167. package/dist/token-search-field.d.ts +13 -2
  168. package/dist/token-search-field.js +1 -1
  169. package/dist/toolbar-text.js +1 -1
  170. package/dist/toolbar.d.ts +12 -4
  171. package/dist/toolbar.js +1 -1
  172. package/dist/{types-CEsieBZi.d.ts → types-DXAGogOS.d.ts} +48 -0
  173. package/dist/value-table.js +1 -1
  174. package/dist/webawesome.d.ts +7 -1
  175. package/dist/wire-catalog.d.ts +24 -1
  176. package/dist/wire-catalog.js +26 -3
  177. package/dist/wire-catalog.js.map +1 -1
  178. package/dist/wire-sidebar.js +6 -3
  179. package/dist/wire-sidebar.js.map +1 -1
  180. package/dist/wire-token-search-fields.js +1 -1
  181. package/dist/wire-workbench.js +1 -350
  182. package/dist/wire-workbench.js.map +1 -1
  183. package/dist/workbench.d.ts +144 -6
  184. package/dist/workbench.js +11 -208
  185. package/dist/workbench.js.map +1 -1
  186. package/docs/accessibility.md +126 -6
  187. package/docs/app-layouts.md +9 -7
  188. package/docs/catalog.md +41 -9
  189. package/docs/collapsible-panel.md +79 -5
  190. package/docs/component-contract.md +38 -12
  191. package/docs/component-selection.md +64 -55
  192. package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
  193. package/docs/design/templates/empty-state/with-action.svg +1 -1
  194. package/docs/design/templates/empty-state-dark.svg +1 -1
  195. package/docs/design/templates/empty-state.svg +1 -1
  196. package/docs/design/templates/list/compact-dark.svg +1 -1
  197. package/docs/design/templates/list/compact.svg +1 -1
  198. package/docs/design/templates/list/stack-dark.svg +1 -1
  199. package/docs/design/templates/list/stack.svg +1 -1
  200. package/docs/design/templates/list-action-row/default-dark.svg +1 -1
  201. package/docs/design/templates/list-action-row/default.svg +1 -1
  202. package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
  203. package/docs/design/templates/list-action-row/selected.svg +1 -1
  204. package/docs/design/templates/list-action-row-dark.svg +1 -1
  205. package/docs/design/templates/list-action-row.svg +1 -1
  206. package/docs/design/templates/list-dark.svg +1 -1
  207. package/docs/design/templates/list-item/default-dark.svg +1 -1
  208. package/docs/design/templates/list-item/default.svg +1 -1
  209. package/docs/design/templates/list-item/selected-dark.svg +1 -1
  210. package/docs/design/templates/list-item/selected.svg +1 -1
  211. package/docs/design/templates/list-item/trailing-dark.svg +1 -1
  212. package/docs/design/templates/list-item/trailing.svg +1 -1
  213. package/docs/design/templates/list-item-dark.svg +1 -1
  214. package/docs/design/templates/list-item.svg +1 -1
  215. package/docs/design/templates/list.svg +1 -1
  216. package/docs/design/templates/state-banner/danger-dark.svg +1 -1
  217. package/docs/design/templates/state-banner/danger.svg +1 -1
  218. package/docs/design/templates/state-banner/info-dark.svg +1 -1
  219. package/docs/design/templates/state-banner/info.svg +1 -1
  220. package/docs/design/templates/state-banner/success-dark.svg +1 -1
  221. package/docs/design/templates/state-banner/success.svg +1 -1
  222. package/docs/design/templates/state-banner/warning-dark.svg +1 -1
  223. package/docs/design/templates/state-banner/warning.svg +1 -1
  224. package/docs/design/templates/state-banner-dark.svg +1 -1
  225. package/docs/design/templates/state-banner.svg +1 -1
  226. package/docs/design/templates/value-table/details-dark.svg +1 -1
  227. package/docs/design/templates/value-table/details.svg +1 -1
  228. package/docs/design/templates/value-table-dark.svg +1 -1
  229. package/docs/design/templates/value-table.svg +1 -1
  230. package/docs/design-philosophy.md +1 -1
  231. package/docs/examples/command-palette-adapter.tsx +3 -2
  232. package/docs/layout.md +74 -29
  233. package/docs/nav-stack.md +45 -1
  234. package/docs/recipes.md +48 -40
  235. package/docs/split-view.md +46 -2
  236. package/docs/surface-scaffold.md +1 -1
  237. package/docs/tab-scaffold.md +50 -1
  238. package/docs/type-contracts.md +17 -17
  239. package/docs/ux-demo.md +8 -4
  240. package/docs/webawesome-theme.md +1 -2
  241. package/docs/workbench.md +131 -10
  242. package/llms.txt +38 -9
  243. package/package.json +24 -2
  244. package/ux-demo/recipes/app-shell.tsx +141 -223
  245. package/ux-demo/recipes/collapsible-sidebar.tsx +47 -77
  246. package/ux-demo/recipes/list-detail-dialog.tsx +150 -54
  247. package/ux-demo/recipes/mount-recipe.ts +0 -5
  248. package/ux-demo/recipes/navigation-sidebar.tsx +3 -2
  249. package/ux-demo/recipes/navigation-stack.tsx +3 -2
  250. package/ux-demo/recipes/types.ts +0 -1
  251. package/dist/chunk-3NBL3OUQ.js.map +0 -1
  252. package/dist/chunk-5I22LMCV.js.map +0 -1
  253. package/dist/chunk-5NDQABWK.js.map +0 -1
  254. package/dist/chunk-7GUQYHKA.js.map +0 -1
  255. package/dist/chunk-7IUSV4XG.js.map +0 -1
  256. package/dist/chunk-BJJKFVWW.js.map +0 -1
  257. package/dist/chunk-D7GWXIAS.js.map +0 -1
  258. package/dist/chunk-DQA5FMOX.js +0 -85
  259. package/dist/chunk-DQA5FMOX.js.map +0 -1
  260. package/dist/chunk-HJKRCKDR.js.map +0 -1
  261. package/dist/chunk-HMQ2ZDGG.js.map +0 -1
  262. package/dist/chunk-KPNTVB7A.js.map +0 -1
  263. package/dist/chunk-MTM43SJO.js.map +0 -1
  264. package/dist/chunk-T22EM4ET.js.map +0 -1
  265. package/dist/chunk-WZ2GLEY4.js.map +0 -1
  266. package/dist/chunk-XD7DWYXG.js +0 -34
  267. package/dist/chunk-XD7DWYXG.js.map +0 -1
  268. package/dist/chunk-ZK5EGVFP.js +0 -27
  269. package/dist/chunk-ZK5EGVFP.js.map +0 -1
  270. package/dist/styles/catalog/components/catalog-detail.css +0 -35
  271. package/dist/styles/catalog/components/catalog-resource-footer.css +0 -37
  272. package/dist/styles/catalog/components/catalog-secondary-sections.css +0 -38
  273. package/dist/styles/catalog/components/catalog-section-list.css +0 -22
  274. package/dist/styles/catalog/components/catalog-sidebar.css +0 -82
@@ -79,13 +79,15 @@ nothing routes that edge, while the bar's surface and divider still reach the
79
79
  screen edge. A claimed toolbar inside a `Pane` header or footer adds nothing
80
80
  extra, because the pane already owns those edges.
81
81
 
82
- Pass `safeAreaEdges={[]}` for a pane that never sits at a screen edge. For a
83
- region you own, set `--kui-edge-inset-block-start`, `--kui-edge-inset-block-end`,
84
- `--kui-edge-inset-inline-start`, or `--kui-edge-inset-inline-end` to `0px` on the
85
- region for each edge it does not reach, and kerf descendants follow. A
86
- `CollapsiblePanel` does this for its direct flex siblings automatically. A
87
- panel wrapped in your own grid cell cannot see its siblings, so route those
88
- edges yourself.
82
+ Pass `safeAreaEdges={[]}` for a pane that never sits at a screen edge. In an
83
+ arrangement you own, give each `Pane` (and each edge-claiming `Toolbar`)
84
+ `safeAreaEdges` listing only the sides its region reaches. The toolbar
85
+ configurations layouts accept (a Workbench `mainToolbar` / `mainBottomToolbar`,
86
+ and a Workbench panel's or `CollapsiblePanel`'s `toolbar`) forward
87
+ `safeAreaEdges` to their `Toolbar` the same way.
88
+ A `CollapsiblePanel` clears the edge it covers for its direct flex siblings
89
+ automatically; a panel wrapped in your own grid cell cannot see its siblings,
90
+ so pass the neighboring panes' `safeAreaEdges` yourself.
89
91
 
90
92
  The device insets come from `--kui-safe-area-block-start`, `-block-end`,
91
93
  `-inline-start`, and `-inline-end`, which default to `env(safe-area-inset-*)`.
package/docs/catalog.md CHANGED
@@ -6,6 +6,15 @@ footer that the kerf UI catalog itself uses. Point it at your own components and
6
6
  you get the same shell without rebuilding it. Like the app layouts, it is a
7
7
  subpath-only, tree-shakeable module that adds nothing to the main barrel.
8
8
 
9
+ The shell is a [`Workbench`](workbench.md) built entirely from `@kerfjs/ui`
10
+ components: the sidebar is its left rail and the active entry its work area. So
11
+ the sidebar behaves like any Workbench rail — its standard toggle moves into the
12
+ entry toolbar while it is collapsed, and on a small screen (a Workbench narrower
13
+ than 704px) it overlays the stage, one tap from the entry toolbar, filling the
14
+ width less a 44px strip that closes it, instead of squeezing the stage. Pass the
15
+ app's `collapsed` signal to `wireCatalog` so that overlay closes on Escape, on a
16
+ press outside, and when an entry is chosen from it.
17
+
9
18
  ```bash
10
19
  npm install @kerfjs/ui # kerfjs is a peer; @kerfjs/ui/select/register is needed only if entries use `related`
11
20
  ```
@@ -36,9 +45,9 @@ expanded? }`. When `collapsible`, the label is a disclosure toggle controlling
36
45
  sidebar content), and `status` (a footer status line).
37
46
 
38
47
  Per-entry `resources` render as "open in new tab" links in the footer, and
39
- `related` renders a "Related entries" popup menu — a `single` `ToolbarControlGroup`
40
- around a `wa-dropdown` (grouped by each entry's `group`), so register its elements
41
- with `@kerfjs/ui/select/register` when you use it.
48
+ `related` renders a "Related entries" `PopupMenu` in a `single`
49
+ `ToolbarControlGroup` (grouped by each entry's `group`), so register its elements
50
+ with `@kerfjs/ui/popup-menu/register` when you use it.
42
51
 
43
52
  ## Catalog demo authoring contract
44
53
 
@@ -249,8 +258,8 @@ Set `revealSelection: true` on `wireCatalog` for a long desktop sidebar. After
249
258
  `onSelect` updates controlled state, the helper waits one animation frame, finds
250
259
  the exact matching `data-item-id`, and scrolls it into view without changing
251
260
  focus. A newer selection or disposal cancels the pending reveal. The default
252
- media guard is the Catalog desktop layout (`min-width: 52.01rem`), so compact
253
- layouts keep their existing scroll position.
261
+ media guard follows the Workbench's inline sidebar (`min-width: 44.01rem`), so a
262
+ closed phone overlay is never scrolled behind the user's back.
254
263
 
255
264
  Pass an options object instead of `true` to customize `block`, `inline`,
256
265
  `behavior`, or `media`; `media: false` deliberately enables the behavior at all
@@ -384,6 +393,26 @@ revealCatalogEntry(app, initial, { block: "center" });
384
393
  - **`active`** is domain state (which entry is shown) — the app's signal, updated in
385
394
  `onSelect`, read to compute `content`.
386
395
  - **`collapsed`** is transient UI — the app's signal, flipped in `onToggleSidebar`.
396
+ Pass the same signal as `wireCatalog`'s `collapsed` option so the sidebar is
397
+ wired as a Workbench rail (transient on small screens, focus handed to the
398
+ relocated toggle).
399
+ - **`headerPlacement` / `footerPlacement`** choose whether the entry toolbar and
400
+ description, and the status + resource footer, stay pinned (`fixed`), scroll with
401
+ the preview (`scroll`), or stay pinned while the entry pane is tall enough and
402
+ scroll with the preview when it is short (`auto`, the default) — so a short
403
+ window or large text never squeezes the preview out.
404
+ - **`sidebar`** configures the sidebar rail — it forwards to the Workbench's left
405
+ rail: `size` (default 288px), `resizable` (`true` or `{ min, max }`),
406
+ `separator`, `collapseMotion`, `presentation`, `responsiveOverlayAt` (default
407
+ `narrow`), `compactOverlay` (default `inset`), and `toolbar` (the sidebar
408
+ header's `ToolbarConfig`). A resizable sidebar's width is app state like
409
+ `collapsed`: render your size signal as `sidebar.size` and pass the same signal
410
+ as `wireCatalog`'s `sidebarSize` (plus `sidebarStorageKey` to remember it).
411
+ - **`mainToolbar` / `footerToolbar`** take the entry toolbar's and the resource
412
+ footer toolbar's `ToolbarConfig` (`dividerSides`, `centerAlign`, `responsive`,
413
+ `responsiveAt`, `safeAreaEdges`). The defaults are a wrapping entry toolbar
414
+ and a divider-free footer toolbar that stacks at `narrow`; an omitted or
415
+ `undefined` field keeps them. Configure these instead of styling the shell.
387
416
  - **`theme`** is a global preference — the app's signal; `wireCatalog` only reports
388
417
  the toggle, the app applies the theme (the shell reads `theme` to show the toggle's
389
418
  opposite-state label). Omit `theme` to hide the toggle entirely.
@@ -397,7 +426,10 @@ matching options on `wireCatalog`) if they collide with your own action table.
397
426
 
398
427
  ## CSS
399
428
 
400
- `Catalog` composes public primitives (`Toolbar`, `ListHeader`, `ListItem`, `Select`,
401
- …). Import `@kerfjs/ui/styles.css` for the whole layer, or `@kerfjs/ui/catalog.css`
402
- plus each composed primitive's CSS. The shell is theme-aware and responsive: it
403
- stacks the sidebar above the detail below ~832px and hides it when collapsed.
429
+ `Catalog` composes public components (`Workbench`, `Pane`, `Toolbar`, `List`,
430
+ `ListHeader`, `ListItem`, `ListInsetText`, `Text`, …) and owns only the preview stage
431
+ (the checkerboard and centered canvas), the geometry overlay, the example viewport
432
+ options, and the brand mark's size. Import `@kerfjs/ui/styles.css` for the whole
433
+ layer, or `@kerfjs/ui/catalog.css` plus `@kerfjs/ui/workbench.css` and each composed
434
+ primitive's CSS. Like any Workbench it needs a definite containing height — the
435
+ `@kerfjs/ui/document.css` baseline's `.kui-app-root`.
@@ -57,7 +57,15 @@ Import the panel CSS (`@kerfjs/ui/collapsible-panel.css`) alongside `foundation.
57
57
  the rest of the page, including under the compact overlay's backdrop. The
58
58
  control takes `--kui-collapsible-panel-restore-z`, which defaults to two less
59
59
  than `--kui-collapsible-panel-overlay-z` (38); the backdrop defaults to one
60
- less (39), so moving the overlay z-index moves both. Escape, a backdrop
60
+ less (39), so moving the overlay z-index moves both. While a left or right
61
+ overlay is open (the `wireSidebar` compact overlay, or
62
+ `presentation="overlay"`), the content's floating controls — restore
63
+ corners and any `FloatingToolbar` — are also hidden outright (out of the
64
+ tab order and the accessibility tree), so they never paint over the overlay
65
+ whatever stacking context the app creates; they return as it closes. The
66
+ overlay's own floating controls stay, and a bottom overlay hides nothing. A
67
+ horizontal `presentation="overlay"` `ResizableRegion` does the same for its
68
+ siblings. Escape, a backdrop
61
69
  press, or the panel's own close control reveals the control again, and a
62
70
  collapsed overlay leaves it clickable. `ResizableRegion`'s `restoreControl`
63
71
  follows the same rules, two below `--kui-resizable-region-overlay-z` (39).
@@ -112,6 +120,72 @@ Import the panel CSS (`@kerfjs/ui/collapsible-panel.css`) alongside `foundation.
112
120
 
113
121
  Returns a disposer. Retain it and call it on teardown.
114
122
 
123
+ ## Panel toolbars and relocated controls
124
+
125
+ Give a panel a `toolbar` (the same roles as a
126
+ [Workbench panel toolbar](workbench.md#panel-toolbars)) and it composes its own
127
+ top toolbar over a `Pane`, with an optional `footer` below its content:
128
+
129
+ - `title` and `panelOnly` groups lead it and are available only while it is open,
130
+ as is optional `center` content;
131
+ - `constant` groups and the standard `toggle: { action, name, showLabel?,
132
+ hideLabel? }` trail it.
133
+
134
+ The toolbar also takes the `Toolbar`'s configuration (`dividerSides`,
135
+ `centerAlign`, `responsive`, `responsiveAt`, `safeAreaEdges`); it keeps its
136
+ bottom divider unless `dividerSides` says otherwise. The `Pane` under it takes
137
+ the panel's `pane` (`PaneConfig`: `contentElement`, `contentLabel`,
138
+ `separators`, `safeAreaEdges`) — for example `{ contentElement: "nav",
139
+ contentLabel: "Sections" }` for a navigation rail. An omitted or `undefined`
140
+ field keeps the `Pane` default; without a `toolbar` there is no `Pane`, so
141
+ `pane` is ignored.
142
+
143
+ A standalone panel does not own the rest of the screen, so the app places a
144
+ `CollapsiblePanelRelocated` in its own work-area toolbar: it renders the panel's
145
+ `constant` groups and toggle while the panel is collapsed, and nothing while it
146
+ is open. Put it first in the leading zone for a left rail, last in the trailing
147
+ zone for a right rail, and last in a bottom toolbar for a bottom drawer. With no
148
+ bottom toolbar, pass it inside a `FloatingToolbar` as the drawer's
149
+ `restoreControl`.
150
+
151
+ ```tsx
152
+ const toolbar: CollapsiblePanelToolbar = {
153
+ label: "Navigator",
154
+ panelOnly: <NewFileGroup />,
155
+ constant: <SearchGroup />,
156
+ toggle: { action: "toggle-nav", name: "navigator" },
157
+ };
158
+
159
+ <Row fill gap="none">
160
+ <CollapsiblePanel id="nav" side="left" collapsed={navCollapsed.value} toolbar={toolbar}>
161
+ <Files />
162
+ </CollapsiblePanel>
163
+ <List flex>
164
+ <Pane
165
+ header={
166
+ <Toolbar
167
+ label="Editor"
168
+ leading={
169
+ <>
170
+ <CollapsiblePanelRelocated panelId="nav" side="left" collapsed={navCollapsed.value} toolbar={toolbar} />
171
+ <ToolbarText text="Editor" size="xlarge" />
172
+ </>
173
+ }
174
+ />
175
+ }
176
+ >
177
+ <Editor />
178
+ </Pane>
179
+ </List>
180
+ </Row>;
181
+ ```
182
+
183
+ Wire it with `wireSidebar` (`toggleAction` is the toggle's `action`): closing the
184
+ panel from its own toggle hands focus to the relocated toggle, even when the app
185
+ renders it a frame later, and opening it moves focus into the panel. Each toggle
186
+ carries a stable `data-key`, so the morph never reuses a focused toggle's button
187
+ for another control as it moves.
188
+
115
189
  ## Compact initial state
116
190
 
117
191
  A compact overlay is transient chrome the user summons, like a slide-over
@@ -234,10 +308,10 @@ panel to the compact overlay (`wireSidebar`) where the viewport cannot hold it.
234
308
 
235
309
  A panel grows by the unsafe inset of the edge it docks to and pads its content
236
310
  for every edge it touches except its interior edge. While expanded inline, it
237
- also clears that edge for its direct flex siblings, so a neighboring pane gains
238
- the inset when the panel collapses. When you wrap the panel in your own grid
239
- cell, set `--kui-edge-inset-*: 0px` on the sibling regions yourself (or pass
240
- `safeAreaEdges` to a sibling `Pane`). See [Choosing an app layout › Safe areas](app-layouts.md#safe-areas).
311
+ also clears that edge for every other direct child of its container, so a
312
+ neighboring pane gains the inset when the panel collapses. When you wrap the panel in your own grid
313
+ cell, pass each sibling `Pane` a `safeAreaEdges` that omits the edge the panel
314
+ covers. See [Choosing an app layout › Safe areas](app-layouts.md#safe-areas).
241
315
 
242
316
  ## When to use which
243
317
 
@@ -258,11 +258,15 @@ rows align that 18px visual with the first inherited text line. The row clips
258
258
  descendant painting to its rounded root so labels, status, and dormant trailing
259
259
  content cannot escape its visible boundary. Rows with descriptions grow enough
260
260
  to keep their owned two-line label stack readable; use `multiline` when the
261
- primary label should wrap rather than truncate.
262
-
263
- `DisclosureArrow` uses an 18px root-scaled visual by default. Override
264
- `--kui-disclosure-arrow-size` on the component or its containing scope when a
265
- consumer needs another size. Kerf `Select` uses a separate Web Awesome expand
261
+ primary label should wrap rather than truncate. A single-line row ends its
262
+ primary label and description with an ellipsis before the trailing status
263
+ slot, even when the label is one long word; a `multiline` row wraps instead,
264
+ breaking a word wider than the label column (a long component or file name)
265
+ rather than letting it run under the trailing slot. `ListActionRow` labels
266
+ follow the same single-line and `multiline` rules before the trailing action.
267
+
268
+ `DisclosureArrow` uses an 18px root-scaled visual by default. Pass its typed
269
+ `size` prop when a consumer needs another size. Kerf `Select` uses a separate Web Awesome expand
266
270
  glyph contract, `--kui-disclosure-icon-scale: .5`; changing one contract does
267
271
  not implicitly change the other. Direction changes take the shortest rotation
268
272
  path; a 180-degree closed-to-open tie uses counterclockwise rotation.
@@ -341,9 +345,10 @@ and do not type-check there. Never exchange these property grammars. List rows e
341
345
  `className`, public tokens, and semantic props instead of unrestricted `style`
342
346
  declarations.
343
347
  `.kui-content` gives major children 24px vertical separation.
344
- `.kui-content-item` gives one child 8px inline margin, a real 1px border,
345
- 8px padding, and 12px corners; border and background may be transparent without
346
- changing geometry. `.kui-content-item--pill` selects the 22px radius.
348
+ `ContentItem` (`@kerfjs/ui/content-item`, rendering `.kui-content-item`) gives
349
+ one child 8px inline margin, a real 1px border, 8px padding, and 12px corners;
350
+ the border stays transparent unless `frame="framed"`, so framing never changes
351
+ geometry. `shape="pill"` selects the 22px radius.
347
352
 
348
353
  `ToolbarControlGroup` is the unit of toolbar organization, even for dormant
349
354
  text. Each group reserves `calc(2px + remify(42px))`, or 44px, with 8px between
@@ -356,14 +361,20 @@ stay inside the available toolbar width. Set `visibility="compact-only"` for a
356
361
  group that replaces wider toolbar controls below the Toolbar's compact container
357
362
  breakpoint; do not hide the group with an application class. Reach for
358
363
  `wa-button` only when you need
359
- a Web Awesome feature, chiefly the `slot="trigger"` button of a `wa-dropdown`
360
- popup menu. For a compact mixed-content group, set `nestedDropdown`; a
364
+ a Web Awesome feature; a popup menu is a `PopupMenu`, which renders its own
365
+ trigger. For a compact mixed-content group, set `nestedDropdown`; a
361
366
  text-and-caret trigger grows to its intrinsic width while an icon-only trigger
362
367
  can remain square. A compact icon `<button>` is a 32px circle, so a selected
363
368
  compact segment never becomes an oval. An icon-only `Select` joins a group as
364
369
  one more segment with its siblings' inset, radius, hover, and focus ring; only a
365
370
  lone Select grows the group to its icon-and-caret pill. Set `menuInset` to configure the dropdown menu surface
366
- without application `::part(menu)` CSS. Compact mixed controls retain the standard
371
+ without application `::part(menu)` CSS; the default `standard` keeps each menu's
372
+ own inset (8px for a raw `wa-dropdown`, the Select listbox's 4px for a
373
+ `PopupMenu`), while `compact` and `list-zero` apply to every nested menu. A
374
+ `PopupMenu` and a `Select` draw one popup: the same caret that turns to face the
375
+ open popup, fade-in surface, surface inset, row height and padding, reserved
376
+ check column, current-row fill, and group titles, all read from one private
377
+ popup-choice contract in `foundation.css`. Compact mixed controls retain the standard
367
378
  item padding, omit an internal separator, and let the raised selected item paint
368
379
  over the outer border instead of shrinking to an inset highlight. The Web
369
380
  Awesome trigger's shadow base owns max-content sizing, so icons, localized text,
@@ -374,7 +385,12 @@ choose `responsive="stack"` with `responsiveAt="compact" | "narrow"`,
374
385
  `responsive="wrap"` for a heading whose title must stay whole, or
375
386
  `responsive="center-priority"` instead of selecting its zone classes from a
376
387
  parent stylesheet. No policy clips an action: the trailing zone, and a stacked
377
- center zone, wrap whole groups onto another row.
388
+ center zone, wrap whole groups onto another row. The center zone never
389
+ compresses below its content width, so when the leading identity, center, and
390
+ trailing zones share a row that is too narrow, the leading title is what gives
391
+ way: it truncates with an ellipsis (as a platform toolbar's title does) instead
392
+ of the center group painting over it. When everything fits, the center group
393
+ keeps its place, centered in the track between the leading and trailing zones.
378
394
  `ListHeader` similarly separates its dormant title and
379
395
  optional count or badge from its optional 44px action. Use the mutually
380
396
  exclusive `count`/`countLabel` pair for non-negative safe-integer section
@@ -400,6 +416,16 @@ padding + 24px icon + 8px gap) and 8px from the right edge for an icon-bearing
400
416
  row. Applications own the values, formatting, and whether an icon is decorative
401
417
  or meaningfully labeled.
402
418
 
419
+ A row follows the settings-style key/value priority: the value keeps its
420
+ content and the label gives way. The label and value are two content-sized
421
+ columns that share the row's free space equally, each stopping once its content
422
+ fits. A short value therefore stays whole on one line beside any label, and a
423
+ long label takes the remaining width, wrapping at its spaces and ending a word
424
+ wider than its column (a long component or file name) in an ellipsis before the
425
+ value rather than running under it. A short label keeps its width beside a
426
+ long value, which wraps; when both are long they split the row, so neither is
427
+ starved.
428
+
403
429
  ## Imports and side effects
404
430
 
405
431
  Every component has an explicit JS and CSS subpath. In CSS-aware browser builds,