@kerfjs/ui 5.0.0-beta.23 → 5.0.0-beta.25

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 (288) hide show
  1. package/README.md +45 -23
  2. package/ai/application-ui-diagnostic-ids-v1.json +3 -0
  3. package/ai/application-ui-profile.defaults.json +1 -1
  4. package/ai/compile-time-contracts-v1.json +5 -12
  5. package/ai/component-catalog-v2-overrides.json +12 -49
  6. package/ai/component-catalog-v2.d.ts +1 -0
  7. package/ai/component-catalog-v2.json +458 -123
  8. package/ai/component-catalog-v2.schema.json +2 -1
  9. package/ai/component-catalog.json +658 -195
  10. package/ai/public-api-signatures-v1.md +160 -80
  11. package/ai/skill.md +22 -22
  12. package/ai/webawesome-jsx-signatures-v1.md +2 -1
  13. package/analyzer/cli.mjs +5 -2
  14. package/analyzer/index.d.mts +1 -0
  15. package/analyzer/index.mjs +117 -10
  16. package/dist/app-tab.d.ts +10 -2
  17. package/dist/app-tab.js +1 -1
  18. package/dist/browser/list-action-row.js +1 -0
  19. package/dist/browser/list-item.js +1 -0
  20. package/dist/browser/list.js +3 -0
  21. package/dist/browser/surface-scaffold.js +3 -0
  22. package/dist/catalog.d.ts +8 -4
  23. package/dist/catalog.js +21 -11
  24. package/dist/catalog.js.map +1 -1
  25. package/dist/{chunk-ELSJX4W7.js → chunk-4EF2CMYS.js} +25 -6
  26. package/dist/chunk-4EF2CMYS.js.map +1 -0
  27. package/dist/{chunk-OHU6CI22.js → chunk-B3A3IVO5.js} +2 -2
  28. package/dist/{chunk-OHU6CI22.js.map → chunk-B3A3IVO5.js.map} +1 -1
  29. package/dist/{chunk-K57KRAOV.js → chunk-FRVS5RFM.js} +24 -6
  30. package/dist/chunk-FRVS5RFM.js.map +1 -0
  31. package/dist/{chunk-DSNIYOZ3.js → chunk-GWEAPEZI.js} +16 -3
  32. package/dist/chunk-GWEAPEZI.js.map +1 -0
  33. package/dist/chunk-HP2B2L26.js +102 -0
  34. package/dist/chunk-HP2B2L26.js.map +1 -0
  35. package/dist/{chunk-OZWU5ZPZ.js → chunk-IJBSZ4NX.js} +2 -2
  36. package/dist/{chunk-OZWU5ZPZ.js.map → chunk-IJBSZ4NX.js.map} +1 -1
  37. package/dist/chunk-J5BFYY7Q.js +35 -0
  38. package/dist/chunk-J5BFYY7Q.js.map +1 -0
  39. package/dist/{chunk-GP5DP5DL.js → chunk-JFGXQBIP.js} +85 -24
  40. package/dist/chunk-JFGXQBIP.js.map +1 -0
  41. package/dist/{chunk-QQFJMRIB.js → chunk-KWWR5VMS.js} +2 -2
  42. package/dist/{chunk-QQFJMRIB.js.map → chunk-KWWR5VMS.js.map} +1 -1
  43. package/dist/chunk-OBLTAKSX.js +43 -0
  44. package/dist/chunk-OBLTAKSX.js.map +1 -0
  45. package/dist/{chunk-PIDTEQ3U.js → chunk-OT6RPYAP.js} +17 -3
  46. package/dist/chunk-OT6RPYAP.js.map +1 -0
  47. package/dist/{chunk-W7YD6E4N.js → chunk-R7ZWUN64.js} +2 -2
  48. package/dist/{chunk-W7YD6E4N.js.map → chunk-R7ZWUN64.js.map} +1 -1
  49. package/dist/{chunk-PZQVSDLH.js → chunk-RKVQEH4J.js} +1 -1
  50. package/dist/chunk-RKVQEH4J.js.map +1 -0
  51. package/dist/{chunk-7L6EHUMV.js → chunk-SYDMYBPG.js} +3 -3
  52. package/dist/chunk-SYDMYBPG.js.map +1 -0
  53. package/dist/{chunk-W4CXQYSG.js → chunk-TB6DY7H5.js} +3 -1
  54. package/dist/chunk-TB6DY7H5.js.map +1 -0
  55. package/dist/{chunk-AASLYRGE.js → chunk-UKKSMZYT.js} +18 -7
  56. package/dist/chunk-UKKSMZYT.js.map +1 -0
  57. package/dist/{chunk-BBRXX6PF.js → chunk-VCE4MPVE.js} +26 -4
  58. package/dist/chunk-VCE4MPVE.js.map +1 -0
  59. package/dist/{chunk-VLYV65LK.js → chunk-W5L2JSBY.js} +5 -3
  60. package/dist/chunk-W5L2JSBY.js.map +1 -0
  61. package/dist/{chunk-5VTB2BKP.js → chunk-WNWD54GR.js} +16 -2
  62. package/dist/chunk-WNWD54GR.js.map +1 -0
  63. package/dist/{chunk-M7JBER5U.js → chunk-X2U3QJCJ.js} +8 -2
  64. package/dist/chunk-X2U3QJCJ.js.map +1 -0
  65. package/dist/{chunk-DPDBVKNA.js → chunk-YMKH5XTF.js} +5 -3
  66. package/dist/chunk-YMKH5XTF.js.map +1 -0
  67. package/dist/collapsible-panel.d.ts +9 -1
  68. package/dist/collapsible-panel.js +36 -15
  69. package/dist/collapsible-panel.js.map +1 -1
  70. package/dist/divider-sides-267FA7sY.d.ts +4 -0
  71. package/dist/index.d.ts +5 -3
  72. package/dist/index.js +20 -19
  73. package/dist/list-action-row.d.ts +11 -1
  74. package/dist/list-action-row.js +2 -1
  75. package/dist/list-header.d.ts +15 -2
  76. package/dist/list-header.js +1 -1
  77. package/dist/list-item.d.ts +12 -1
  78. package/dist/list-item.js +2 -1
  79. package/dist/list.d.ts +19 -0
  80. package/dist/list.js +3 -0
  81. package/dist/list.js.map +1 -0
  82. package/dist/nav-stack.js +1 -1
  83. package/dist/resizable-region.d.ts +19 -2
  84. package/dist/resizable-region.js +1 -1
  85. package/dist/segmented-control.js +1 -1
  86. package/dist/select.d.ts +12 -1
  87. package/dist/select.js +1 -1
  88. package/dist/skeleton.d.ts +1 -1
  89. package/dist/skeleton.js +1 -1
  90. package/dist/split-view.js +2 -2
  91. package/dist/state-banner.d.ts +4 -2
  92. package/dist/state-banner.js +1 -1
  93. package/dist/styles/app-tab.css +26 -0
  94. package/dist/styles/catalog.css +8 -2
  95. package/dist/styles/collapsible-panel.css +66 -4
  96. package/dist/styles/list-action-row.css +64 -0
  97. package/dist/styles/list-header.css +32 -0
  98. package/dist/styles/list-item.css +45 -6
  99. package/dist/styles/list.css +43 -0
  100. package/dist/styles/resizable-region.css +132 -0
  101. package/dist/styles/select.css +68 -0
  102. package/dist/styles/state-banner.css +32 -1
  103. package/dist/styles/styles.css +2 -1
  104. package/dist/styles/sunken-panel.css +4 -0
  105. package/dist/styles/surface-scaffold.css +51 -0
  106. package/dist/styles/tab-bar.css +24 -0
  107. package/dist/styles/toolbar-control-group.css +73 -1
  108. package/dist/styles/toolbar-text.css +1 -1
  109. package/dist/styles/toolbar.css +38 -2
  110. package/dist/styles/webawesome.css +12 -0
  111. package/dist/styles/workbench.css +89 -0
  112. package/dist/sunken-panel.d.ts +5 -2
  113. package/dist/sunken-panel.js +1 -1
  114. package/dist/surface-scaffold.d.ts +25 -0
  115. package/dist/surface-scaffold.js +3 -0
  116. package/dist/surface-scaffold.js.map +1 -0
  117. package/dist/tab-bar.d.ts +11 -2
  118. package/dist/tab-bar.js +1 -1
  119. package/dist/toolbar-control-group.d.ts +16 -2
  120. package/dist/toolbar-control-group.js +1 -1
  121. package/dist/toolbar-text.js +1 -1
  122. package/dist/toolbar.d.ts +5 -3
  123. package/dist/toolbar.js +1 -1
  124. package/dist/value-table.js +1 -1
  125. package/dist/webawesome.d.ts +1 -0
  126. package/dist/wire-catalog.d.ts +4 -2
  127. package/dist/wire-catalog.js +95 -36
  128. package/dist/wire-catalog.js.map +1 -1
  129. package/dist/wire-resizable-regions.js +1 -1
  130. package/dist/wire-sidebar.d.ts +6 -1
  131. package/dist/wire-sidebar.js +27 -8
  132. package/dist/wire-sidebar.js.map +1 -1
  133. package/dist/wire-tab-bars.js +1 -1
  134. package/dist/wire-token-search-fields.d.ts +1 -1
  135. package/dist/wire-token-search-fields.js +1 -1
  136. package/dist/workbench.d.ts +8 -0
  137. package/dist/workbench.js +42 -0
  138. package/dist/workbench.js.map +1 -1
  139. package/docs/accessibility.md +67 -15
  140. package/docs/catalog.md +17 -12
  141. package/docs/collapsible-panel.md +7 -0
  142. package/docs/component-contract.md +19 -9
  143. package/docs/component-selection.md +65 -31
  144. package/docs/design/templates/empty-state/filtered-dark.svg +1 -1
  145. package/docs/design/templates/empty-state/filtered.svg +1 -1
  146. package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
  147. package/docs/design/templates/empty-state/with-action.svg +1 -1
  148. package/docs/design/templates/empty-state-dark.svg +1 -7
  149. package/docs/design/templates/empty-state.svg +1 -7
  150. package/docs/design/templates/list/compact-dark.svg +1 -0
  151. package/docs/design/templates/list/compact.svg +1 -0
  152. package/docs/design/templates/list/stack-dark.svg +1 -0
  153. package/docs/design/templates/list/stack.svg +1 -0
  154. package/docs/design/templates/list-action-row/default-dark.svg +1 -1
  155. package/docs/design/templates/list-action-row/default.svg +1 -1
  156. package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
  157. package/docs/design/templates/list-action-row/selected.svg +1 -1
  158. package/docs/design/templates/list-action-row-dark.svg +1 -7
  159. package/docs/design/templates/list-action-row.svg +1 -7
  160. package/docs/design/templates/list-dark.svg +1 -0
  161. package/docs/design/templates/list-header/action-dark.svg +1 -1
  162. package/docs/design/templates/list-header/action.svg +1 -1
  163. package/docs/design/templates/list-header/toggle-collapsed-dark.svg +1 -1
  164. package/docs/design/templates/list-header/toggle-collapsed.svg +1 -1
  165. package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -1
  166. package/docs/design/templates/list-header/toggle-expanded.svg +1 -1
  167. package/docs/design/templates/list-header-dark.svg +1 -11
  168. package/docs/design/templates/list-header.svg +1 -11
  169. package/docs/design/templates/list-item/default-dark.svg +1 -1
  170. package/docs/design/templates/list-item/default.svg +1 -1
  171. package/docs/design/templates/list-item/multiline-dark.svg +1 -1
  172. package/docs/design/templates/list-item/multiline.svg +1 -1
  173. package/docs/design/templates/list-item/selected-dark.svg +1 -1
  174. package/docs/design/templates/list-item/selected.svg +1 -1
  175. package/docs/design/templates/list-item/trailing-dark.svg +1 -1
  176. package/docs/design/templates/list-item/trailing.svg +1 -1
  177. package/docs/design/templates/list-item-dark.svg +1 -11
  178. package/docs/design/templates/list-item.svg +1 -11
  179. package/docs/design/templates/list.svg +1 -0
  180. package/docs/design/templates/segmented-control-dark.svg +1 -7
  181. package/docs/design/templates/segmented-control.svg +1 -7
  182. package/docs/design/templates/skeleton-dark.svg +1 -9
  183. package/docs/design/templates/skeleton.svg +1 -9
  184. package/docs/design/templates/state-banner/danger-dark.svg +1 -1
  185. package/docs/design/templates/state-banner/danger.svg +1 -1
  186. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -0
  187. package/docs/design/templates/state-banner/info-badge.svg +1 -0
  188. package/docs/design/templates/state-banner/info-dark.svg +1 -1
  189. package/docs/design/templates/state-banner/info.svg +1 -1
  190. package/docs/design/templates/state-banner/success-dark.svg +1 -1
  191. package/docs/design/templates/state-banner/success.svg +1 -1
  192. package/docs/design/templates/state-banner/warning-dark.svg +1 -1
  193. package/docs/design/templates/state-banner/warning.svg +1 -1
  194. package/docs/design/templates/state-banner-dark.svg +1 -11
  195. package/docs/design/templates/state-banner.svg +1 -11
  196. package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -1
  197. package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -1
  198. package/docs/design/templates/tab-bar-dark.svg +1 -5
  199. package/docs/design/templates/tab-bar.svg +1 -5
  200. package/docs/design/templates/token-search-field/empty-dark.svg +1 -1
  201. package/docs/design/templates/token-search-field/empty.svg +1 -1
  202. package/docs/design/templates/token-search-field/tokens-dark.svg +1 -1
  203. package/docs/design/templates/token-search-field/tokens.svg +1 -1
  204. package/docs/design/templates/token-search-field-dark.svg +1 -7
  205. package/docs/design/templates/token-search-field.svg +1 -7
  206. package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -1
  207. package/docs/design/templates/toolbar/title-and-actions.svg +1 -1
  208. package/docs/design/templates/toolbar-control-group/borderless-single-dark.svg +1 -1
  209. package/docs/design/templates/toolbar-control-group/borderless-single.svg +1 -1
  210. package/docs/design/templates/toolbar-control-group/icon-buttons-dark.svg +1 -1
  211. package/docs/design/templates/toolbar-control-group/icon-buttons.svg +1 -1
  212. package/docs/design/templates/toolbar-control-group/push-buttons-dark.svg +1 -1
  213. package/docs/design/templates/toolbar-control-group/push-buttons.svg +1 -1
  214. package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -1
  215. package/docs/design/templates/toolbar-control-group/with-text.svg +1 -1
  216. package/docs/design/templates/toolbar-control-group-dark.svg +1 -11
  217. package/docs/design/templates/toolbar-control-group.svg +1 -11
  218. package/docs/design/templates/toolbar-dark.svg +1 -5
  219. package/docs/design/templates/toolbar-text-dark.svg +1 -9
  220. package/docs/design/templates/toolbar-text.svg +1 -9
  221. package/docs/design/templates/toolbar.svg +1 -5
  222. package/docs/design/templates/value-table/details-dark.svg +1 -1
  223. package/docs/design/templates/value-table/details.svg +1 -1
  224. package/docs/design/templates/value-table-dark.svg +1 -5
  225. package/docs/design/templates/value-table.svg +1 -5
  226. package/docs/design/templates.md +29 -20
  227. package/docs/examples/component-catalog-extension-v2.json +3 -6
  228. package/docs/examples/component-catalog-extension.json +1 -1
  229. package/docs/layout.md +7 -9
  230. package/docs/recipes.md +8 -7
  231. package/docs/sunken-panel.md +11 -1
  232. package/docs/surface-scaffold.md +17 -0
  233. package/docs/type-contracts.md +11 -10
  234. package/docs/ui-analyzer.md +19 -1
  235. package/docs/ui-doctor.md +7 -5
  236. package/docs/ux-demo.md +6 -3
  237. package/docs/webawesome-theme.md +4 -1
  238. package/docs/workbench.md +49 -2
  239. package/doctor/eslint-diagnostics.d.mts +16 -0
  240. package/doctor/eslint-diagnostics.mjs +17 -0
  241. package/doctor/index.mjs +21 -3
  242. package/llms.txt +33 -11
  243. package/package.json +14 -8
  244. package/traversal-exclusions.mjs +7 -1
  245. package/ux-demo/recipes/app-shell.tsx +36 -23
  246. package/ux-demo/recipes/collapsible-sidebar.tsx +23 -17
  247. package/ux-demo/recipes/composer-form.tsx +15 -6
  248. package/ux-demo/recipes/list-detail-dialog.tsx +31 -15
  249. package/ux-demo/recipes/list-workspace-states.tsx +16 -7
  250. package/ux-demo/recipes/loading-inspector.tsx +39 -18
  251. package/ux-demo/recipes/navigation-sidebar.tsx +1 -1
  252. package/ux-demo/recipes/recipes.css +7 -2
  253. package/ux-demo/recipes/workspace-header.tsx +17 -7
  254. package/dist/browser/panel-header.js +0 -7
  255. package/dist/chunk-5VTB2BKP.js.map +0 -1
  256. package/dist/chunk-7L6EHUMV.js.map +0 -1
  257. package/dist/chunk-AASLYRGE.js.map +0 -1
  258. package/dist/chunk-BBRXX6PF.js.map +0 -1
  259. package/dist/chunk-DPDBVKNA.js.map +0 -1
  260. package/dist/chunk-DSNIYOZ3.js.map +0 -1
  261. package/dist/chunk-ELSJX4W7.js.map +0 -1
  262. package/dist/chunk-GP5DP5DL.js.map +0 -1
  263. package/dist/chunk-K57KRAOV.js.map +0 -1
  264. package/dist/chunk-M7JBER5U.js.map +0 -1
  265. package/dist/chunk-NENBUYX5.js +0 -79
  266. package/dist/chunk-NENBUYX5.js.map +0 -1
  267. package/dist/chunk-PIDTEQ3U.js.map +0 -1
  268. package/dist/chunk-PZQVSDLH.js.map +0 -1
  269. package/dist/chunk-RYRIFZCT.js +0 -58
  270. package/dist/chunk-RYRIFZCT.js.map +0 -1
  271. package/dist/chunk-VLYV65LK.js.map +0 -1
  272. package/dist/chunk-W4CXQYSG.js.map +0 -1
  273. package/dist/panel-header.d.ts +0 -42
  274. package/dist/panel-header.js +0 -7
  275. package/dist/panel-header.js.map +0 -1
  276. package/dist/styles/panel-header.css +0 -64
  277. package/docs/design/templates/panel-header/icon-actions-dark.svg +0 -1
  278. package/docs/design/templates/panel-header/icon-actions.svg +0 -1
  279. package/docs/design/templates/panel-header/icon-summary-actions-dark.svg +0 -1
  280. package/docs/design/templates/panel-header/icon-summary-actions.svg +0 -1
  281. package/docs/design/templates/panel-header/no-icon-dark.svg +0 -1
  282. package/docs/design/templates/panel-header/no-icon.svg +0 -1
  283. package/docs/design/templates/panel-header/page-heading-dark.svg +0 -1
  284. package/docs/design/templates/panel-header/page-heading.svg +0 -1
  285. package/docs/design/templates/panel-header/title-only-dark.svg +0 -1
  286. package/docs/design/templates/panel-header/title-only.svg +0 -1
  287. package/docs/design/templates/panel-header-dark.svg +0 -13
  288. package/docs/design/templates/panel-header.svg +0 -13
@@ -1,5 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="492" height="274" viewBox="0 0 492 274">
2
- <rect width="492" height="274" fill="#1c1c1e"/>
3
- <text x="16" y="30" font-family="system-ui, sans-serif" font-size="12" font-weight="600" fill="#aeaeb2">Key/value detail rows</text>
4
- <svg x="16" y="38" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 460 220" width="460" height="220"><defs><clipPath id="v0-cp0"><rect x="28" y="20" width="404" height="165.2"/></clipPath><clipPath id="v0-ov1"><rect x="29" y="21" width="402" height="163.2" rx="11"/></clipPath><clipPath id="v0-ct2"><rect x="37" y="32.4" width="46.5" height="18"/></clipPath><clipPath id="v0-ct3"><rect x="141" y="32.4" width="282" height="18"/></clipPath><clipPath id="v0-cp4"><rect x="37" y="70" width="24" height="24.2"/></clipPath><clipPath id="v0-ct5"><rect x="69" y="73.2" width="90.6" height="18"/></clipPath><clipPath id="v0-ct6"><rect x="167.6" y="73.2" width="255.4" height="18"/></clipPath><clipPath id="v0-ct7"><rect x="37" y="114" width="50" height="18"/></clipPath><clipPath id="v0-ct8"><rect x="141" y="114" width="282" height="18"/></clipPath><clipPath id="v0-ct9"><rect x="37" y="154.8" width="83.7" height="18"/></clipPath><clipPath id="v0-ct10"><rect x="141" y="154.8" width="282" height="18"/></clipPath></defs><g clip-path="url(#v0-cp0)"><rect x="28" y="20" width="404" height="165.2" rx="12" fill="rgb(17,17,19)"/><rect x="28.5" y="20.5" width="403" height="164" rx="11.5" fill="none" stroke="rgb(72,72,74)" stroke-width="1"/></g><g clip-path="url(#v0-ov1)"><text x="37" y="47.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" fill="rgb(174,174,178)">Status</text><text x="391.91" y="47.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" font-weight="650" fill="rgb(245,245,247)">Live</text></g><g clip-path="url(#v0-ov1)"><g clip-path="url(#v0-cp4)"><g transform="translate(37 70.2)" color="rgb(174, 174, 178)"><svg data-lucide="rocket" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" font-family="system-ui, -apple-system, sans-serif" style="overflow:hidden" width="24" height="24"><path d="M12 15v5s3-.6 4-2c1-1.6 0-5 0-5" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M4.5 16.5c-1.5 1.3-2 5-2 5s3.7-.5 5-2c.7-.8.7-2.1 0-3a2 2 0 0 0-3 0" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M9 12a22 22 0 0 1 2-4 13 13 0 0 1 11-6c0 2.7-.8 7.5-6 11a22 22 0 0 1-4 2Z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M9 12H4s.5-3 2-4c1.6-1 5 0 5 0" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></svg></g></g><text x="69" y="88.19" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" fill="rgb(174,174,178)">Environment</text><text x="338.63" y="88.19" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" font-weight="650" fill="rgb(245,245,247)">Production</text><g data-domotion-pseudo-source="blink-pseudo-fragment-v1" data-domotion-pseudo="::before" data-domotion-pseudo-owner="source-fragments"><g><line x1="69" y1="62.5" x2="423" y2="62.5" stroke="rgb(72, 72, 74)" stroke-width="1"/></g></g></g><g clip-path="url(#v0-ov1)"><text x="37" y="128.98" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" fill="rgb(174,174,178)">Region</text><text x="349.39" y="128.98" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" font-weight="650" fill="rgb(245,245,247)">us-east-1</text><g data-domotion-pseudo-source="blink-pseudo-fragment-v1" data-domotion-pseudo="::before" data-domotion-pseudo-owner="source-fragments"><g><line x1="37" y1="103.5" x2="423" y2="103.5" stroke="rgb(72, 72, 74)" stroke-width="1"/></g></g></g><g clip-path="url(#v0-ov1)"><text x="37" y="169.78" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" fill="rgb(174,174,178)">Last deploy</text><text x="333.14" y="169.78" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" font-weight="650" fill="rgb(245,245,247)">2 hours ago</text><g data-domotion-pseudo-source="blink-pseudo-fragment-v1" data-domotion-pseudo="::before" data-domotion-pseudo-owner="source-fragments"><g><line x1="37" y1="143.5" x2="423" y2="143.5" stroke="rgb(72, 72, 74)" stroke-width="1"/></g></g></g></svg>
5
- </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 492 274" width="492" height="274"><defs><clipPath id="cp0"><rect x="16" y="38" width="460" height="220"/></clipPath><clipPath id="ct1"><rect x="16" y="16" width="460" height="22"/></clipPath><clipPath id="irc2"><rect x="16" y="38" width="460" height="220" rx="0"/></clipPath></defs><rect x="0" y="0" width="492" height="274" rx="0" fill="rgb(28,28,30)"/><text x="16" y="28" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="600" fill="rgb(174,174,178)">Key/value detail rows</text><g clip-path="url(#cp0)"><g clip-path="url(#irc2)"><clipPath id="svgimg3vclip"><rect x="16" y="38" width="460" height="220"/></clipPath><g clip-path="url(#svgimg3vclip)"><g transform="translate(16 38)"><defs><clipPath id="svgimg3cp0"><rect x="28" y="20" width="404" height="165.2"/></clipPath><clipPath id="svgimg3ov1"><rect x="29" y="21" width="402" height="163.2" rx="11"/></clipPath><clipPath id="svgimg3ct2"><rect x="37" y="32.4" width="46.5" height="18"/></clipPath><clipPath id="svgimg3ct3"><rect x="141" y="32.4" width="282" height="18"/></clipPath><clipPath id="svgimg3cp4"><rect x="37" y="70" width="24" height="24.2"/></clipPath><clipPath id="svgimg3ct6"><rect x="69" y="73.2" width="90.6" height="18"/></clipPath><clipPath id="svgimg3ct7"><rect x="167.6" y="73.2" width="255.4" height="18"/></clipPath><clipPath id="svgimg3ct8"><rect x="37" y="114" width="50" height="18"/></clipPath><clipPath id="svgimg3ct9"><rect x="141" y="114" width="282" height="18"/></clipPath><clipPath id="svgimg3ct10"><rect x="37" y="154.8" width="83.7" height="18"/></clipPath><clipPath id="svgimg3ct11"><rect x="141" y="154.8" width="282" height="18"/></clipPath></defs><g clip-path="url(#svgimg3cp0)"><rect x="28" y="20" width="404" height="165.2" rx="12" fill="rgb(17,17,19)"/><rect x="28.5" y="20.5" width="403" height="164" rx="11.5" fill="none" stroke="rgb(72,72,74)" stroke-width="1"/></g><g clip-path="url(#svgimg3ov1)"><text x="37" y="47.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" fill="rgb(174,174,178)">Status</text><text x="391.91" y="47.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" font-weight="650" fill="rgb(245,245,247)">Live</text></g><g clip-path="url(#svgimg3ov1)"><g clip-path="url(#svgimg3cp4)"><g color="rgb(174, 174, 178)"><clipPath id="svgimg3svgic5"><rect x="37" y="70.2" width="24" height="24"/></clipPath><g clip-path="url(#svgimg3svgic5)"><g transform="translate(37 70.188)"><path d="M12 15v5s3-.6 4-2c1-1.6 0-5 0-5" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M4.5 16.5c-1.5 1.3-2 5-2 5s3.7-.5 5-2c.7-.8.7-2.1 0-3a2 2 0 0 0-3 0" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M9 12a22 22 0 0 1 2-4 13 13 0 0 1 11-6c0 2.7-.8 7.5-6 11a22 22 0 0 1-4 2Z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M9 12H4s.5-3 2-4c1.6-1 5 0 5 0" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="69" y="88.19" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" fill="rgb(174,174,178)">Environment</text><text x="338.63" y="88.19" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" font-weight="650" fill="rgb(245,245,247)">Production</text><g data-domotion-pseudo-source="blink-pseudo-fragment-v1" data-domotion-pseudo="::before" data-domotion-pseudo-owner="source-fragments"><g><line x1="69" y1="62.5" x2="423" y2="62.5" stroke="rgb(72, 72, 74)" stroke-width="1"/></g></g></g><g clip-path="url(#svgimg3ov1)"><text x="37" y="128.98" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" fill="rgb(174,174,178)">Region</text><text x="349.39" y="128.98" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" font-weight="650" fill="rgb(245,245,247)">us-east-1</text><g data-domotion-pseudo-source="blink-pseudo-fragment-v1" data-domotion-pseudo="::before" data-domotion-pseudo-owner="source-fragments"><g><line x1="37" y1="103.5" x2="423" y2="103.5" stroke="rgb(72, 72, 74)" stroke-width="1"/></g></g></g><g clip-path="url(#svgimg3ov1)"><text x="37" y="169.78" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" fill="rgb(174,174,178)">Last deploy</text><text x="333.14" y="169.78" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" font-weight="650" fill="rgb(245,245,247)">2 hours ago</text><g data-domotion-pseudo-source="blink-pseudo-fragment-v1" data-domotion-pseudo="::before" data-domotion-pseudo-owner="source-fragments"><g><line x1="37" y1="143.5" x2="423" y2="143.5" stroke="rgb(72, 72, 74)" stroke-width="1"/></g></g></g></g></g></g></g></svg>
@@ -1,5 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="492" height="274" viewBox="0 0 492 274">
2
- <rect width="492" height="274" fill="#ffffff"/>
3
- <text x="16" y="30" font-family="system-ui, sans-serif" font-size="12" font-weight="600" fill="#6e6e73">Key/value detail rows</text>
4
- <svg x="16" y="38" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 460 220" width="460" height="220"><defs><clipPath id="v0-cp0"><rect x="28" y="20" width="404" height="165.2"/></clipPath><clipPath id="v0-ov1"><rect x="29" y="21" width="402" height="163.2" rx="11"/></clipPath><clipPath id="v0-ct2"><rect x="37" y="32.4" width="46.5" height="18"/></clipPath><clipPath id="v0-ct3"><rect x="141" y="32.4" width="282" height="18"/></clipPath><clipPath id="v0-cp4"><rect x="37" y="70" width="24" height="24.2"/></clipPath><clipPath id="v0-ct5"><rect x="69" y="73.2" width="90.6" height="18"/></clipPath><clipPath id="v0-ct6"><rect x="167.6" y="73.2" width="255.4" height="18"/></clipPath><clipPath id="v0-ct7"><rect x="37" y="114" width="50" height="18"/></clipPath><clipPath id="v0-ct8"><rect x="141" y="114" width="282" height="18"/></clipPath><clipPath id="v0-ct9"><rect x="37" y="154.8" width="83.7" height="18"/></clipPath><clipPath id="v0-ct10"><rect x="141" y="154.8" width="282" height="18"/></clipPath></defs><g clip-path="url(#v0-cp0)"><rect x="28" y="20" width="404" height="165.2" rx="12" fill="rgb(242,242,247)"/><rect x="28.5" y="20.5" width="403" height="164" rx="11.5" fill="none" stroke="rgb(209,209,214)" stroke-width="1"/></g><g clip-path="url(#v0-ov1)"><text x="37" y="47.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" fill="rgb(110,110,115)">Status</text><text x="391.91" y="47.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" font-weight="650" fill="rgb(29,29,31)">Live</text></g><g clip-path="url(#v0-ov1)"><g clip-path="url(#v0-cp4)"><g transform="translate(37 70.2)" color="rgb(110, 110, 115)"><svg data-lucide="rocket" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" font-family="system-ui, -apple-system, sans-serif" style="overflow:hidden" width="24" height="24"><path d="M12 15v5s3-.6 4-2c1-1.6 0-5 0-5" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M4.5 16.5c-1.5 1.3-2 5-2 5s3.7-.5 5-2c.7-.8.7-2.1 0-3a2 2 0 0 0-3 0" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M9 12a22 22 0 0 1 2-4 13 13 0 0 1 11-6c0 2.7-.8 7.5-6 11a22 22 0 0 1-4 2Z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M9 12H4s.5-3 2-4c1.6-1 5 0 5 0" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></svg></g></g><text x="69" y="88.19" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" fill="rgb(110,110,115)">Environment</text><text x="338.63" y="88.19" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" font-weight="650" fill="rgb(29,29,31)">Production</text><g data-domotion-pseudo-source="blink-pseudo-fragment-v1" data-domotion-pseudo="::before" data-domotion-pseudo-owner="source-fragments"><g><line x1="69" y1="62.5" x2="423" y2="62.5" stroke="rgb(209, 209, 214)" stroke-width="1"/></g></g></g><g clip-path="url(#v0-ov1)"><text x="37" y="128.98" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" fill="rgb(110,110,115)">Region</text><text x="349.39" y="128.98" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" font-weight="650" fill="rgb(29,29,31)">us-east-1</text><g data-domotion-pseudo-source="blink-pseudo-fragment-v1" data-domotion-pseudo="::before" data-domotion-pseudo-owner="source-fragments"><g><line x1="37" y1="103.5" x2="423" y2="103.5" stroke="rgb(209, 209, 214)" stroke-width="1"/></g></g></g><g clip-path="url(#v0-ov1)"><text x="37" y="169.78" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" fill="rgb(110,110,115)">Last deploy</text><text x="333.14" y="169.78" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" font-weight="650" fill="rgb(29,29,31)">2 hours ago</text><g data-domotion-pseudo-source="blink-pseudo-fragment-v1" data-domotion-pseudo="::before" data-domotion-pseudo-owner="source-fragments"><g><line x1="37" y1="143.5" x2="423" y2="143.5" stroke="rgb(209, 209, 214)" stroke-width="1"/></g></g></g></svg>
5
- </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 492 274" width="492" height="274"><defs><clipPath id="cp0"><rect x="16" y="38" width="460" height="220"/></clipPath><clipPath id="ct1"><rect x="16" y="16" width="460" height="22"/></clipPath><clipPath id="irc2"><rect x="16" y="38" width="460" height="220" rx="0"/></clipPath></defs><rect x="0" y="0" width="492" height="274" rx="0" fill="rgb(255,255,255)"/><text x="16" y="28" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="600" fill="rgb(110,110,115)">Key/value detail rows</text><g clip-path="url(#cp0)"><g clip-path="url(#irc2)"><clipPath id="svgimg3vclip"><rect x="16" y="38" width="460" height="220"/></clipPath><g clip-path="url(#svgimg3vclip)"><g transform="translate(16 38)"><defs><clipPath id="svgimg3cp0"><rect x="28" y="20" width="404" height="165.2"/></clipPath><clipPath id="svgimg3ov1"><rect x="29" y="21" width="402" height="163.2" rx="11"/></clipPath><clipPath id="svgimg3ct2"><rect x="37" y="32.4" width="46.5" height="18"/></clipPath><clipPath id="svgimg3ct3"><rect x="141" y="32.4" width="282" height="18"/></clipPath><clipPath id="svgimg3cp4"><rect x="37" y="70" width="24" height="24.2"/></clipPath><clipPath id="svgimg3ct6"><rect x="69" y="73.2" width="90.6" height="18"/></clipPath><clipPath id="svgimg3ct7"><rect x="167.6" y="73.2" width="255.4" height="18"/></clipPath><clipPath id="svgimg3ct8"><rect x="37" y="114" width="50" height="18"/></clipPath><clipPath id="svgimg3ct9"><rect x="141" y="114" width="282" height="18"/></clipPath><clipPath id="svgimg3ct10"><rect x="37" y="154.8" width="83.7" height="18"/></clipPath><clipPath id="svgimg3ct11"><rect x="141" y="154.8" width="282" height="18"/></clipPath></defs><g clip-path="url(#svgimg3cp0)"><rect x="28" y="20" width="404" height="165.2" rx="12" fill="rgb(242,242,247)"/><rect x="28.5" y="20.5" width="403" height="164" rx="11.5" fill="none" stroke="rgb(209,209,214)" stroke-width="1"/></g><g clip-path="url(#svgimg3ov1)"><text x="37" y="47.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" fill="rgb(110,110,115)">Status</text><text x="391.91" y="47.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" font-weight="650" fill="rgb(29,29,31)">Live</text></g><g clip-path="url(#svgimg3ov1)"><g clip-path="url(#svgimg3cp4)"><g color="rgb(110, 110, 115)"><clipPath id="svgimg3svgic5"><rect x="37" y="70.2" width="24" height="24"/></clipPath><g clip-path="url(#svgimg3svgic5)"><g transform="translate(37 70.188)"><path d="M12 15v5s3-.6 4-2c1-1.6 0-5 0-5" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M4.5 16.5c-1.5 1.3-2 5-2 5s3.7-.5 5-2c.7-.8.7-2.1 0-3a2 2 0 0 0-3 0" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M9 12a22 22 0 0 1 2-4 13 13 0 0 1 11-6c0 2.7-.8 7.5-6 11a22 22 0 0 1-4 2Z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M9 12H4s.5-3 2-4c1.6-1 5 0 5 0" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><text x="69" y="88.19" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" fill="rgb(110,110,115)">Environment</text><text x="338.63" y="88.19" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" font-weight="650" fill="rgb(29,29,31)">Production</text><g data-domotion-pseudo-source="blink-pseudo-fragment-v1" data-domotion-pseudo="::before" data-domotion-pseudo-owner="source-fragments"><g><line x1="69" y1="62.5" x2="423" y2="62.5" stroke="rgb(209, 209, 214)" stroke-width="1"/></g></g></g><g clip-path="url(#svgimg3ov1)"><text x="37" y="128.98" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" fill="rgb(110,110,115)">Region</text><text x="349.39" y="128.98" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" font-weight="650" fill="rgb(29,29,31)">us-east-1</text><g data-domotion-pseudo-source="blink-pseudo-fragment-v1" data-domotion-pseudo="::before" data-domotion-pseudo-owner="source-fragments"><g><line x1="37" y1="103.5" x2="423" y2="103.5" stroke="rgb(209, 209, 214)" stroke-width="1"/></g></g></g><g clip-path="url(#svgimg3ov1)"><text x="37" y="169.78" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" fill="rgb(110,110,115)">Last deploy</text><text x="333.14" y="169.78" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="16" font-weight="650" fill="rgb(29,29,31)">2 hours ago</text><g data-domotion-pseudo-source="blink-pseudo-fragment-v1" data-domotion-pseudo="::before" data-domotion-pseudo-owner="source-fragments"><g><line x1="37" y1="143.5" x2="423" y2="143.5" stroke="rgb(209, 209, 214)" stroke-width="1"/></g></g></g></g></g></g></g></svg>
@@ -9,8 +9,8 @@ component picture without running the app.
9
9
 
10
10
  ## Coverage
11
11
 
12
- Templated components (each with light + dark variants): `PanelHeader`,
13
- `ToolbarControlGroup`, `Toolbar`, `ToolbarText`, `ListItem`, `ListHeader`,
12
+ Templated components (each with light + dark variants):
13
+ `ToolbarControlGroup`, `Toolbar`, `ToolbarText`, `List`, `ListItem`, `ListHeader`,
14
14
  `ListActionRow`, `ValueTable`, `StateBanner`, `EmptyState`, `Skeleton`,
15
15
  `SegmentedControl`, `TabBar`/`AppTab`, and `TokenSearchField`.
16
16
 
@@ -27,11 +27,9 @@ catalog and the app-layouts docs cover those.
27
27
 
28
28
  ```
29
29
  docs/design/templates/
30
- panel-header.svg ← library: every variant, inlined (light)
31
- panel-header-dark.svg ← library: dark theme
32
- panel-header/
33
- icon-summary-actions.svg ← one self-contained variant (light)
34
- icon-summary-actions-dark.svg ← the same variant, dark theme
30
+ toolbar.svg ← library: every variant, composed (light)
31
+ toolbar-dark.svg ← library: dark theme
32
+ toolbar/
35
33
  icon-actions.svg
36
34
  icon-actions-dark.svg
37
35
 
@@ -50,13 +48,12 @@ docs/design/templates/
50
48
  kerf UI design font stack is system-based, so the picture matches; a viewer
51
49
  without those fonts falls back to its own.
52
50
  - The **library** files (`<component>.svg` light, `<component>-dark.svg` dark) lay
53
- the variants out with captions and embed an inline **copy** of each variant as a
54
- positioned nested `<svg>`. Each is fully self-contained and renders everywhere
55
- a browser, an `<img>`, GitHub, or a static rasterizer. (External
56
- `<use href="…#id">` and `<image href="…">` references render blank in many SVG
57
- viewers, so the library inlines copies instead. Each copy's local ids and
58
- domotion font-family names are namespaced so the inlined variants don't collide
59
- in the one document; the individual variant files stay individually reusable.)
51
+ the variants out with captions. The generator writes a temporary HTML page whose
52
+ `<img>` elements reference the individual variant SVGs, then captures that page
53
+ with domotion and `--flatten-nested-svg`. The final library is self-contained,
54
+ contains positioned groups rather than nested `<svg>` elements, and remains
55
+ reliable in design tools such as Sketch. The individual variant files stay
56
+ independently reusable.
60
57
 
61
58
  ## Building
62
59
 
@@ -67,19 +64,24 @@ npm run design-templates:build
67
64
  This renders each component's real `SafeHtml` (with its CSS subpaths + `foundation.css`
68
65
  tokens and representative sample data) into a standalone page and captures it with
69
66
  [`domotion-svg`](https://github.com/brianwestphal/domotion)'s `domotion capture`.
67
+ The capture command uses `--flatten-nested-svg`, which converts safely flattenable
68
+ inline SVGs (including component icons) to groups so design tools such as Sketch do
69
+ not have to interpret nested `<svg>` elements.
70
70
  `domotion` must be reachable: it resolves `DOMOTION_BIN`, then a local
71
71
  `node_modules/.bin/domotion`, then a sibling `../domotion` checkout.
72
72
 
73
73
  **Keep the templates current as components change.** The variants live in the
74
74
  `COMPONENTS` manifest in `scripts/build-design-templates.mjs` — when a component
75
- gains or changes a presentation combination (e.g. a new `PanelHeader` slot), add
75
+ gains or changes a presentation combination (e.g. a new `Toolbar` slot), add
76
76
  or adjust its variant there and re-run the build. Cover the common cases: if a
77
77
  component can render with or without an icon, include both.
78
78
 
79
79
  `npm run check:design-templates` (part of `npm run check`) is an offline gate
80
80
  that verifies every component + variant in the manifest has its committed output —
81
81
  a light and dark SVG per variant plus the two per-component library files — and
82
- that no stray template files linger for a removed component. It does **not**
82
+ that no stray template files linger for a removed component. It also rejects any
83
+ variant or library capture that still contains nested `<svg>` elements, guarding
84
+ the Sketch compatibility contract. It does **not**
83
85
  re-render (that needs domotion + a browser), so it catches a manifest entry whose
84
86
  templates were never generated or a half-regenerated set.
85
87
 
@@ -109,11 +111,18 @@ starting point and:
109
111
  tokens and `layout.css`), and any of your own component CSS.
110
112
  3. Enumerate the presentation combinations in the per-component manifest.
111
113
  4. Capture each variant with `domotion capture <page.html> --selector <css>
112
- --text-mode system-font -o <variant>.svg`, once per theme with
114
+ --text-mode system-font --flatten-nested-svg -o <variant>.svg`, once per theme with
113
115
  `--color-scheme light` / `--color-scheme dark` (if your components theme with
114
- `light-dark()`), then write a light and a dark library file that each embed an
115
- inline copy of every variant (namespacing each copy's ids/font-family names so
116
- they don't collide) rather than referencing them, so they render everywhere.
116
+ `light-dark()`).
117
+ 5. Build a light and dark HTML library page that references the generated variants
118
+ with `<img src="./component/variant.svg">`, and capture each page with the same
119
+ domotion options, including `--flatten-nested-svg`. Let domotion own embedding,
120
+ id isolation, and flattening instead of hand-assembling SVG markup.
117
121
 
118
122
  Maintaining these next to the components — and reviewing the captured SVGs on
119
123
  every component change — keeps the design source of truth honest.
124
+
125
+ ListItem templates retain the shared 18px leading icon and 44px row target;
126
+ regenerate both themes and library sheets when that geometry changes. The browser
127
+ pane/sidebar geometry checks cover the resulting 43px icon-label offset from the
128
+ section edge (17px content inset + 18px icon + 8px gap).
@@ -19,7 +19,7 @@
19
19
  "zones": [
20
20
  {
21
21
  "id": "header",
22
- "accepts": ["@kerfjs/ui:panel-header"],
22
+ "accepts": ["@kerfjs/ui:toolbar"],
23
23
  "cardinality": { "min": 1, "max": 1 },
24
24
  "exclusiveWith": []
25
25
  },
@@ -32,11 +32,8 @@
32
32
  ],
33
33
  "children": {
34
34
  "mode": "listed",
35
- "concepts": ["@kerfjs/ui:panel-header", "@kerfjs/ui:value-table"],
36
- "requiredConcepts": [
37
- "@kerfjs/ui:panel-header",
38
- "@kerfjs/ui:value-table"
39
- ]
35
+ "concepts": ["@kerfjs/ui:toolbar", "@kerfjs/ui:value-table"],
36
+ "requiredConcepts": ["@kerfjs/ui:toolbar", "@kerfjs/ui:value-table"]
40
37
  },
41
38
  "state": [
42
39
  { "id": "selected-record", "owner": "application", "required": true }
@@ -36,7 +36,7 @@
36
36
  "border": "child",
37
37
  "padding": "child",
38
38
  "notes": [
39
- "The embedding pane positions the inspector; PanelHeader, ValueTable, and action groups retain their own geometry."
39
+ "The embedding pane positions the inspector; Toolbar, ValueTable, and action groups retain their own geometry."
40
40
  ]
41
41
  },
42
42
  "documentation": "docs/inspector.md"
package/docs/layout.md CHANGED
@@ -56,7 +56,7 @@ control border and 1px control padding, so its default rounded-rectangle radius
56
56
  is 10px inside the control's 12px radius.
57
57
 
58
58
  A visible parent surface does not make every child another visible card. The
59
- composer recipe keeps its form as the single surface, uses `PanelHeader` for
59
+ composer recipe keeps its form as the single surface, uses a heading `Toolbar` for
60
60
  its task hierarchy, and places field and action control edges on the shared 8px
61
61
  inline gutter instead of nesting them inside another padded content item. A
62
62
  conditional `StateBanner` remains visibly distinct because it communicates
@@ -77,7 +77,7 @@ semantic status.
77
77
  | Explicit scroll owner outside a pane | `.kui-scroll-owner` | `overflow: auto` |
78
78
 
79
79
  The component layer applies the same contract to `Toolbar`, `ListHeader`,
80
- `ListItem`, `PanelHeader`, `StateBanner`, `ValueTable`,
80
+ `ListItem`, `Toolbar`, `StateBanner`, `ValueTable`,
81
81
  `ValueTableRow`, tabs, and form controls. A value-table row separator starts at
82
82
  the row's 8px content inset, or at 40px when the row contains its 24px leading
83
83
  icon and 8px gap, and always ends 8px from the right edge. Each value-table row
@@ -85,13 +85,11 @@ also keeps 8px of root-scaled block padding independently of its semantic inline
85
85
  inset. Most interactive rows and toolbar groups are 44px tall.
86
86
  Toolbar groups reserve a real 1px outer border around a 42px inner area, even
87
87
  when their border and background are transparent.
88
- `PanelHeader` is a plain top `Toolbar` used as a panel, dialog, or page heading
89
- and overrides no Toolbar styles. The leading zone holds the optional icon (a
90
- normal bordered `ToolbarControlGroup` given a brand fill with a matching border,
91
- a 22px glyph) and the title as extra-large `ToolbarText`; the app's trailing
92
- controls go straight into the trailing zone, and the icon group is omitted when
93
- no icon is passed. The optional subtitle is a separate row below the toolbar, its
94
- text left-aligned with the title text.
88
+ Panel, dialog, and page headings are plain `Toolbar` compositions. The leading
89
+ zone holds an optional icon `ToolbarControlGroup` and a direct extra-large
90
+ `ToolbarText`; actions belong in a trailing group. Omit empty groups. Supporting
91
+ copy is app-owned content below the toolbar and aligns with the intended content
92
+ edge.
95
93
 
96
94
  ## Spacing scale
97
95
 
package/docs/recipes.md CHANGED
@@ -56,7 +56,7 @@ no custom `actionIcon` is needed; ordinary navigation rows stay chevron-free.
56
56
 
57
57
  [Open the recipe](../ux-demo/?component=recipe-workspace-header) · [TSX source](../ux-demo/recipes/workspace-header.tsx)
58
58
 
59
- `PanelHeader` owns the page heading while one control cluster holds secondary,
59
+ The page heading is a direct `Toolbar`/`ToolbarText` composition while one control cluster holds secondary,
60
60
  overflow, and primary actions. The app owns authorization and command policy;
61
61
  controls relocate without changing focus order.
62
62
 
@@ -66,10 +66,10 @@ controls relocate without changing focus order.
66
66
 
67
67
  The production Web Awesome dialog owns modal focus and Escape; the thin recipe
68
68
  adapter restores the invoking control consistently after the hide event.
69
- `PanelHeader`, `ListHeader`, `ListItem`, and `ValueTable` own their included
69
+ `Toolbar`, `ListHeader`, `ListItem`, and `ValueTable` own their included
70
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.
71
+ record actions. A `ToolbarControlGroup` places the app's trailing controls in
72
+ the top toolbar's trailing zone.
73
73
  The header sits on the dialog edge while retaining its internal control inset;
74
74
  the selected title receives the full content gutter, the metadata table fills
75
75
  the available detail width between the usual outer margins, and the action
@@ -80,8 +80,9 @@ Do not rebuild the dialog or reach into private shadow parts.
80
80
 
81
81
  [Open the recipe](../ux-demo/?component=recipe-composer-form) · [TSX source](../ux-demo/recipes/composer-form.tsx)
82
82
 
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
83
+ A direct `ToolbarText` supplies the task title, with app-owned supporting copy
84
+ below; their ids are referenced by the form. Production fields own labels, help,
85
+ and native focus. The field
85
86
  and footer control edges sit directly on the shared 8px inline gutter rather
86
87
  than acquiring a second content-item padding inset; major children remain 24px
87
88
  apart and related controls use 8px gaps. The app owns
@@ -126,7 +127,7 @@ settles the chrome (reduced motion collapses the slide to instant). A live
126
127
  [Open the recipe](../ux-demo/?component=recipe-loading-inspector) · [TSX source](../ux-demo/recipes/loading-inspector.tsx)
127
128
 
128
129
  A record inspector whose per-record values load asynchronously. Every
129
- value-bearing component (`PanelHeader`, `ValueTable`/`ValueTableRow`, `Select`,
130
+ value-bearing component (`ToolbarText`, `ValueTable`/`ValueTableRow`, `Select`,
130
131
  `SegmentedControl`, `ListItem`, `StateBanner`) takes its `placeholder` from one
131
132
  loading flag, so the same real chrome renders a faithful loading state and then
132
133
  the populated record — no separate skeleton markup. The composition is the point;
@@ -14,6 +14,15 @@ import { SunkenPanel } from '@kerfjs/ui/sunken-panel';
14
14
  </SunkenPanel>;
15
15
  ```
16
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
+
17
26
  ## Ownership
18
27
 
19
28
  The root owns its lowered background, 8px padding, and 8px vertical gap.
@@ -40,4 +49,5 @@ Override the public properties at the composition boundary:
40
49
  - `--kui-sunken-panel-radius`
41
50
 
42
51
  The public root class is `.kui-sunken-panel`. Prefer the properties above over
43
- styling descendants.
52
+ styling descendants. The `square` shape deliberately overrides the radius
53
+ property with zero; use `rounded` when customizing the radius token.
@@ -0,0 +1,17 @@
1
+ # Dialog and popup surface scaffolds
2
+
3
+ `DialogSurface` and `PopupSurface` configure recurring Web Awesome surface
4
+ geometry without application `::part()` overrides. They do not replace Web
5
+ Awesome behavior: the application still owns open state, focus lifecycle,
6
+ dismissal policy, ids, labels, and content.
7
+
8
+ Wrap one `wa-dialog` with `DialogSurface`. Choose `size` (`small`, `medium`, or
9
+ `large`), `presentation` (`modal`, `side-sheet`, or `fullscreen`), and independent
10
+ `bodyInset` / `footerInset` (`none`, `compact`, or `comfortable`). The defaults
11
+ match Kerf's medium modal, 8px body, and 16px footer rhythm.
12
+
13
+ Wrap one `wa-dropdown` with `PopupSurface`. `inset="list-zero"` removes menu
14
+ padding for a child that already owns row insets, `compact` uses 4px, and
15
+ `standard` uses the shared 8px surface inset. Keep the dropdown trigger named and
16
+ preserve `data-morph-skip-children` when its upgraded light-DOM items must retain
17
+ identity across Kerf rerenders.
@@ -19,11 +19,10 @@ public-signature artifact.
19
19
  | `KUI-T004` | A literal `SegmentedControl.value` belongs to its literal `choices`. |
20
20
  | `KUI-T005` | `expanded`, `expandAction`, and `expandLabel` exist only on `TokenSearchField({ collapsible: true })`. |
21
21
  | `KUI-T006` | `TokenSearchEditorAttributes` accepts application `data-*` metadata but rejects component-owned identity, morph, count, and placeholder attributes. |
22
- | `KUI-T007` | `PanelHeader.summaryId` cannot exist without rendered `summary` content. |
23
- | `KUI-T008` | `ToolbarText.maxLines` requires `wrap: true`; it is never silently ignored in typed code. |
24
- | `KUI-T009` | A literal `TabScaffold.active` id belongs to its literal `tabs`. |
25
- | `KUI-T010` | Adjacent-token keyboard removal requires `onRemoveToken`; disabling removal rejects the now-meaningless callback. |
26
- | `KUI-T011` | Finite public variants have named exported union types, including tab activation, banner urgency, and all ToolbarControlGroup presentation axes. |
22
+ | `KUI-T007` | `ToolbarText.maxLines` requires `wrap: true`; it is never silently ignored in typed code. |
23
+ | `KUI-T008` | A literal `TabScaffold.active` id belongs to its literal `tabs`. |
24
+ | `KUI-T009` | Adjacent-token keyboard removal requires `onRemoveToken`; disabling removal rejects the now-meaningless callback. |
25
+ | `KUI-T010` | Finite public variants have named exported union types, including divider sides, tab activation, banner urgency, and all ToolbarControlGroup presentation axes. |
27
26
 
28
27
  Literal identity inference is intentionally additive for dynamic applications.
29
28
  When choices or ids arrive at runtime and the state signal is correctly typed as
@@ -45,10 +44,10 @@ ordinary source/type gates:
45
44
 
46
45
  - required identity or accessible-name inputs on `AppTab`, `FloatingToolbar`,
47
46
  `NavStack`, `SplitView`, `Workbench`, `TabBar`, `ResizableRegion`,
48
- `SegmentedControl`, `TokenSearchField`, `PanelHeader`, and `ValueTable`;
47
+ `SegmentedControl`, `TokenSearchField`, and `ValueTable`;
49
48
  - finite variants exported or represented as literal props on `DisclosureArrow`,
50
49
  `FloatingToolbar`, `Pane`, `ResizableRegion`, `SegmentedControl`, `StateBanner`,
51
- `ToolbarText`, `CollapsiblePanel`, `Catalog`, and the wire helpers;
50
+ `SunkenPanel`, `ToolbarText`, `CollapsiblePanel`, `Catalog`, and the wire helpers;
52
51
  - required controlled-state callbacks on `wireResizableRegions`, `wireTabBars`,
53
52
  and `wireTabScaffold`;
54
53
  - mutually exclusive count/badge metadata on `ListHeader`; and
@@ -58,7 +57,7 @@ ordinary source/type gates:
58
57
 
59
58
  The remaining components (`LucideIcon`, `DisclosureArrow`, `Toolbar`,
60
59
  `ToolbarControlGroup`, `ListInsetControl`, `ListInsetText`, `LoadingSpinner`,
61
- `Skeleton`, `SunkenPanel`, `EmptyState`, `StateBanner`, `ValueTableRow`, and the
60
+ `Skeleton`, `EmptyState`, `StateBanner`, `ValueTableRow`, and the
62
61
  pure helpers) have independent props with no further conditional invalid state
63
62
  that TypeScript can truthfully remove. Optional labels on decorative icons and
64
63
  unnamed non-landmark surfaces are intentional variants, not missing contracts.
@@ -92,8 +91,10 @@ move errors into casts without making the integration safer.
92
91
  `{ keyboard: { onRemoveToken } }` or
93
92
  `{ keyboard: { removeAdjacentToken: false } }` when only caret navigation is
94
93
  wanted.
95
- - Remove orphaned `summaryId`, or render the matching `summary`; add
96
- `wrap: true` anywhere `ToolbarText.maxLines` is used.
94
+ - Add `wrap: true` anywhere `ToolbarText.maxLines` is used.
95
+ - Replace `Toolbar({ divider: false })` with `dividerSides: ''`; the default
96
+ remains a bottom divider, while canonical combinations such as `tr` and
97
+ `trbl` select more physical edges.
97
98
 
98
99
  JavaScript runtime behavior remains defensive for previously emitted calls, but
99
100
  new TypeScript builds report these invalid or ignored combinations.
@@ -46,6 +46,9 @@ policy, or analysis inputs to the containing application.
46
46
  | `KUI-L007` | error | A declared scroll owner is nested inside another scroll owner. |
47
47
  | `KUI-L008` | review | A dynamic class expression cannot be classified soundly. |
48
48
  | `KUI-L009` | error | A stylesheet cannot be parsed. |
49
+ | `KUI-L010` | error | A selector reaches a private Kerf descendant from a public root. |
50
+ | `KUI-L011` | error | A `::part()` target is not cataloged as a public extension point. |
51
+ | `KUI-L012` | error | CSS assigns a Kerf token without a public configuration contract. |
49
52
 
50
53
  Errors are provable contract violations and make the command exit 1. Review
51
54
  findings are deliberately heuristic and do not fail by default; pass
@@ -53,6 +56,20 @@ findings are deliberately heuristic and do not fail by default; pass
53
56
  gate CI. Text, versioned JSON, and SARIF carry the same stable rule ids,
54
57
  source locations, evidence, and ownership chain.
55
58
 
59
+ For staged adoption, pass `--adoption`. Ownership-boundary diagnostics are
60
+ reported as review findings so a team can inventory and migrate its baseline;
61
+ combine it with the exact file-and-rule exceptions below for intentional legacy
62
+ integrations. Remove `--adoption` to make unsupported overrides blocking.
63
+
64
+ Catalog `boundaries.publicClasses` and `boundaries.publicTokens` are explicit
65
+ CSS extension points. A component catalog may additionally list shadow-part
66
+ names in `boundaries.publicParts`; all other `::part()` targets are private.
67
+ Part names are scoped to that entry's `boundaries.rootClass`, so an extension
68
+ point on one component does not authorize the same-named part on another.
69
+ Parent-owned placement and selectors for application-owned content remain
70
+ allowed because the analyzer only reserves `.kui-*`, `--kui-*`, and cataloged
71
+ shadow boundaries.
72
+
56
73
  The JSON report schema is exported as
57
74
  `@kerfjs/ui/analyzer/report.schema.json`.
58
75
 
@@ -82,5 +99,6 @@ validator.
82
99
  ```
83
100
 
84
101
  Review findings remain visible until explicitly suppressed. Avoid suppressing
85
- `KUI-L001`, `KUI-L002`, `KUI-L003`, `KUI-L007`, or `KUI-L009`: those indicate a
102
+ `KUI-L001`, `KUI-L002`, `KUI-L003`, `KUI-L007`, `KUI-L009`, `KUI-L010`,
103
+ `KUI-L011`, or `KUI-L012`: those indicate a
86
104
  definite boundary or parsing failure rather than an aesthetic judgment.
package/docs/ui-doctor.md CHANGED
@@ -15,7 +15,7 @@ The default terminal output is short and repair-oriented. `--format json` emits
15
15
 
16
16
  The catalog stage discovers the package-default application UI profile and workspace/root-to-leaf directory layers. It validates referenced selection/composition catalogs and, when a workspace declares `package.json#kerfComponentCatalog`, invokes the installed `create-kerf-component` catalog checker to validate metadata, source exports, schema conformance, and generated-output drift. This checker reads source text; it does not import application modules.
17
17
 
18
- TypeScript uses the compiler API with `noEmit`. ESLint loads the installed `eslint-plugin-kerfjs` `recommended-ui` preset (`--eslint strict-ui` opts into advisory rules as errors). This is deliberately an isolated Kerf lint pass rather than the consumer's complete ESLint configuration. Inline directives for consumer-owned plugins, such as `@typescript-eslint`, therefore do not produce false "rule definition not found" diagnostics; the consumer's normal ESLint command remains authoritative for those rules. Unknown `kerfjs/*` directives still fail the doctor pass. Stable KUI identifiers come from the packaged `application-ui-diagnostic-ids-v1.json` registry; the doctor also reads installed ESLint message metadata for semantic conflict detection instead of duplicating rule definitions. The analyzer calls the public `@kerfjs/ui/analyzer` contract. None of these stages executes generated application code.
18
+ TypeScript uses the compiler API with `noEmit`. ESLint loads the installed `eslint-plugin-kerfjs` `recommended-ui` preset (`--eslint strict-ui` opts into advisory rules as errors). This is deliberately an isolated Kerf lint pass rather than the consumer's complete ESLint configuration. For each file, the doctor projects the applicable core ESLint rules and `linterOptions` from the consumer configuration so core-rule suppression directives retain the same used/unused semantics as the application's normal lint command. Consumer plugin rules are not executed, and inline directives for plugins such as `@typescript-eslint` therefore do not produce false "rule definition not found" diagnostics; the consumer's normal ESLint command remains authoritative for those rules. Unknown `kerfjs/*` directives still fail the doctor pass. Stable KUI identifiers come from the packaged `application-ui-diagnostic-ids-v1.json` registry; the doctor also reads installed ESLint message metadata for semantic conflict detection instead of duplicating rule definitions. The analyzer calls the public `@kerfjs/ui/analyzer` contract. None of these stages executes generated application code.
19
19
 
20
20
  The browser evaluator is different: it runs the application and is disabled by default. It only runs when configuration supplies `browser.url` or the command receives `--browser-url`. Start and authorize the target application separately.
21
21
 
@@ -25,10 +25,12 @@ An unavailable or failed stage does not prevent independent stages from reportin
25
25
 
26
26
  `--full` is the default and analyzes the selected package. `--changed` reads tracked and untracked paths from Git unless one or more `--path` values are supplied. An empty changed set is a configuration error instead of a false-clean success. With `--package`, workspace-relative Git paths are converted to package-relative paths before TypeScript, ESLint, and analyzer selection; paths outside the selected package are ignored.
27
27
 
28
- Full traversal treats nested `.claude/worktrees` checkouts as tool-owned
29
- repositories rather than application source. Their files are excluded
30
- consistently from TypeScript, ESLint, analyzer discovery, and cache inputs, even
31
- when the nested checkout lives below another application directory.
28
+ Full traversal treats generated/tool-owned directories (`dist`, `coverage`,
29
+ `node_modules`, `.git`, `.kerf-cache`, `kerf-ui-evidence`, and nested
30
+ `.claude/worktrees` checkouts) as outside application source. Their files are
31
+ excluded consistently from TypeScript, the isolated ESLint pass, analyzer
32
+ discovery, and cache inputs, even when one lives below another application
33
+ directory.
32
34
 
33
35
  TypeScript constructs the selected package's program so compiler options retain their real meaning, while its root inputs are narrowed to changed source files. Use `--full` for release gates.
34
36
 
package/docs/ux-demo.md CHANGED
@@ -13,15 +13,18 @@ deterministic state, and semantic layout owners from the [recipe guide](./recipe
13
13
  - `ai/component-catalog.json` is the canonical catalog metadata. A deterministic checked-in projection supplies the demo's unique id, category, kind (`component`, `composition`, or `recipe`), source (`kerf` or `webawesome`), name, description, recommendation, direct `uses` dependencies, existing documentation path, and demo-source path; first-party, recipe, and Web Awesome renderer maps are exhaustively typed against its generated id unions. Non-supported Web Awesome recommendations project to a visible `Discouraged` sidebar tag, with Popup as the deliberate conditional exception. Demo paths resolve to the matching `ui/ux-demo/demos/<id>.tsx` or `ui/ux-demo/recipes/*.tsx` file, or to `ui/ux-demo/webawesome-demos.tsx` for Web Awesome entries. `ui/ux-demo/main.tsx` owns only the catalog shell, shared state, routing, and interaction wiring. First-party component entries additionally derive `ui/src/<public-subpath>.tsx` from their canonical `delivery.browserImport` or opt-in `delivery.moduleImport`.
14
14
  - Every detail footer groups compact `Demo source` and `Guidance` actions; first-party component details also expose `Component source`. Web Awesome details say `Integration guidance` to distinguish the local integration contract from the upstream component implementation. Each button retains its repository-relative path in the DOM for verification and uses a deploy-safe absolute GitHub blob URL with a contextual new-tab name; the demo does not depend on a local source server or add a package runtime export. At phone widths, the resource group and related-component selector stack as full-width rows, with any resource overflow contained locally so labels cannot overlap the selector or widen the document.
15
15
  - The master/detail shell groups first-party routes by category with production `ListHeader` and `ListItem` components. Catalog entries can supply short reusable trailing tags; the Web Awesome projection uses them to label exactly the 15 discouraged choices. The 70 ecosystem components live in a separate `Web Awesome` disclosure with seven subgroups, so they remain discoverable without being presented as first-class `@kerfjs/ui` exports. Direct Web Awesome routes open the disclosure and reveal the selected row at wide sizes; narrow layouts keep the expanded list in document flow rather than introducing a competing nested scroller.
16
- - The shell itself uses `@kerfjs/ui/layout.css`: sidebars, details, previews, dialogs, and resize specimens share unpadded panes plus self-contained content items. Its sidebar identity uses the Kerf logo beside a vertically centered title, with the subtitle in its own aligned row like `PanelHeader`; the current-view heading is also a toolbar. Collapsing the catalog removes the pane completely and moves its restore action to the main toolbar's leading edge instead of leaving an icon-only rail. The selected view description remains inset below the page toolbar. The checkerboard belongs to the complete scrollable preview region rather than a nested card. A lightly separated footer keeps live status above compact source, guidance, and relationship groups. The focused `ResizableRegion` specimen stretches its surface through the available stage height and reports committed width in that shared status footer; narrow layouts retain local horizontal access when the pane is resized wider than the stage, and the split remains readable at 200% root scaling. Geometry coverage checks wide, intermediate, narrow, and 200% zoom layouts.
17
- - The composer-form recipe demonstrates one coherent visible form surface with `PanelHeader` title/summary hierarchy, fields and actions on the shared 8px control gutter, and 24px major rhythm. Its conditional error or success `StateBanner` is the only nested semantic surface. Reset synchronizes the upgraded Web Awesome fields' live value properties with their empty controlled attributes and announces `Draft reset`; browser coverage preserves behavior and verifies wide, narrow, dark, validation, success, reset, 200% zoom, and forced-colors states.
16
+ - The shell itself uses `@kerfjs/ui/layout.css`: sidebars, details, previews, dialogs, and resize specimens share unpadded panes plus self-contained content items. Its sidebar identity uses the Kerf logo beside a vertically centered title, with supporting copy in its own aligned row; the current-view heading is also a toolbar. Collapsing the catalog removes the pane completely and moves its restore action to the main toolbar's leading edge instead of leaving an icon-only rail. The selected view description remains inset below the page toolbar. The checkerboard belongs to the complete scrollable preview region rather than a nested card. A lightly separated footer keeps live status above compact source, guidance, and relationship groups. The focused `ResizableRegion` specimen stretches its surface through the available stage height and reports committed width in that shared status footer; narrow layouts retain local horizontal access when the pane is resized wider than the stage, and the split remains readable at 200% root scaling. Geometry coverage checks wide, intermediate, narrow, and 200% zoom layouts.
17
+ - The composer-form recipe demonstrates one coherent visible form surface with toolbar title/supporting-copy hierarchy, fields and actions on the shared 8px control gutter, and 24px major rhythm. Its conditional error or success `StateBanner` is the only nested semantic surface. Reset synchronizes the upgraded Web Awesome fields' live value properties with their empty controlled attributes and announces `Draft reset`; browser coverage preserves behavior and verifies wide, narrow, dark, validation, success, reset, 200% zoom, and forced-colors states.
18
18
  - The list-detail dialog recipe places its header directly on the dialog edge while preserving the header's internal inset, gives the selected project title the complete outer-plus-inner content gutter, lets the value table fill the available detail column between the shared outer margins, and keeps record actions on one outer gutter without an extra content-item inset. Browser geometry coverage protects those relationships at wide and narrow widths.
19
19
  - Catalog-only brand marks, preview dimensions, checkerboard tiles, and the compound display-settings control retain local geometry because they are specimen chrome or intrinsic control anatomy rather than reusable application spacing roles.
20
20
  - The menu composition route demonstrates toolbar/content/footer anatomy, 24px major gaps, 8/1/8 child geometry, the full-width `ListHeader` count-or-badge/action split, logical-end 44px action targets with 18px visuals, and 44px row/header/toolbar targets. Its one chevron is a production 18px `DisclosureArrow` inside a controlled Tools header that actually reveals and hides content; ordinary Projects navigation has no false disclosure affordance. Browser assertions cover stable naming, expanded/content transitions, visual rotation, node identity, reduced motion, RTL alignment and containment, and wide, narrow, dark, and 200% layouts. The focused ListHeader route separately shows the shared neutral count pill for Attachments, Notes (including zero), and Duplicates plus a non-count legacy badge, full-width logical-end actions, and no disclosure without content.
21
21
  - The `DisclosureArrow` route renders the production 18px root-scaled default without a catalog-only size override. Its two native buttons independently control the default right-to-down chevron and a recognizable right-facing replacement arrow with left-to-up custom directions; both use shortest-path rotation and their names stay stable while `aria-expanded` communicates state. Browser coverage verifies the custom clockwise path, pointer and native keyboard activation, focus, narrow and 200%-zoom stacking with contained labels, consumer sizing, and the independent `.5` Web Awesome glyph scale retained by Kerf `Select`.
22
22
  - A detail with relationships renders one grouped footer selector: `Uses` links to direct dependencies and `Used by` links to reverse dependents. Choosing either navigates to that component's demo. The relationship group is absent when both sets are empty; no duplicate summary is rendered.
23
23
  - Demo-only CSS supplies only the catalog shell and stages; component appearance stays in package CSS. Decorative chrome and Web Awesome controls share the same semantic system palette instead of carrying a separate demo identity.
24
- - Scenarios use deterministic data and cover real variants, long content, disabled state, selection, progress, feedback, overlays, media, helpers, and stateful interactions. The Web Awesome theme route remains the broad system view, while individual action, form, layout, navigation, feedback, media, and helper routes provide focused specimens; ListItem and ListHeader demonstrate typed domain metadata, protected native button/disclosure semantics, and a native popover trigger relationship without product props; PanelHeader demonstrates its plain top-toolbar identity, extra-large title, optional subtitle row, and bordered brand-filled icon group; the Select route verifies that option icons survive unrelated Kerf rerenders and selected slot content follows value changes; the Animation route exposes preset, easing, duration, playback-rate, and transport controls with live lifecycle status; observer routes provide user-driven intersection, mutation, and resize events with live results; ToolbarControlGroup exposes all eight Hot Sheet 2 variants, loads the Web Awesome registrations needed by its popup specimen, and preserves the upgraded dropdown's managed light-DOM children across Kerf rerenders; the Toolbar route composes a collapsible TokenSearchField inside a group, animates between the empty iconic and complete field states, stays open while populated, and focuses the revealed editor; SegmentedControl covers toolbar, rounded-rectangle, pill, equal-width, and disabled presentations; TokenSearchField covers editable ordered chips, pointer and keyboard removal, caret-preserving controlled deletion, editing, clearing, free text, disabled state, and fixed first-line alignment while content wraps; StateBanner exposes every built-in tone plus a scoped override; TabBar demonstrates overflow, edge autoscroll, and controlled pointer/keyboard reordering.
24
+ - Scenarios use deterministic data and cover real variants, long content, disabled state, selection, progress, feedback, overlays, media, helpers, and stateful interactions. The Web Awesome theme route remains the broad system view, while individual action, form, layout, navigation, feedback, media, and helper routes provide focused specimens; ListItem and ListHeader demonstrate typed domain metadata, protected native button/disclosure semantics, and a native popover trigger relationship without product props; the Headers composition demonstrates direct toolbar headings with an extra-large title, optional supporting copy, and grouped icon/actions; the Select route verifies that option icons survive unrelated Kerf rerenders and selected slot content follows value changes; the Animation route exposes preset, easing, duration, playback-rate, and transport controls with live lifecycle status; observer routes provide user-driven intersection, mutation, and resize events with live results; ToolbarControlGroup exposes all eight Hot Sheet 2 variants, loads the Web Awesome registrations needed by its popup specimen, and preserves the upgraded dropdown's managed light-DOM children across Kerf rerenders; the Toolbar route composes a collapsible TokenSearchField inside a group, animates between the empty iconic and complete field states, stays open while populated, and focuses the revealed editor; SegmentedControl covers toolbar, rounded-rectangle, pill, equal-width, and disabled presentations; TokenSearchField covers editable ordered chips, pointer and keyboard removal, caret-preserving controlled deletion, editing, clearing, free text, disabled state, and fixed first-line alignment while content wraps; StateBanner exposes every built-in tone with tone-tinted badges plus a scoped override; TabBar demonstrates overflow, edge autoscroll, and controlled pointer/keyboard reordering.
25
+ - The ToolbarControlGroup route also demonstrates the public compact/tight,
26
+ mixed-content, filled-selection, nested-dropdown, and avatar/scrim contracts
27
+ added for consumers that previously restyled group descendants.
25
28
  - Recipe ownership notes are hidden by default. A page-toolbar toggle reveals them as floating warning-toned notes with a folded corner, keeping instructional copy visually distinct and removable from the specimen flow.
26
29
  - Settings exercise light/dark, increased contrast, and reduced motion without changing component code. The theme action starts from the operating system's effective color scheme, always names the appearance it will switch to, and installs an explicit light or dark override when activated; contrast and reduced motion expose their independent preferences through `aria-pressed`.
27
30
  - The footer action log is an `aria-live` region, making interactions visible to both people and browser tests.
@@ -98,7 +98,10 @@ tiers:
98
98
  once to the group rather than separating connected items; Card's header,
99
99
  body, and footer all receive the full inset.
100
100
  - `--kui-wa-container-inset` defaults to the 16px homogeneous-group step. Tab
101
- Panel retains this roomier tier for unframed panel content.
101
+ Panel retains this roomier tier for unframed panel content. Dialog body uses
102
+ the 8px surface inset, while its footer uses the 16px container inset so
103
+ content stays compact and the action group has a clearer boundary. These two
104
+ parts do not inherit the dialog's shared `--spacing` value.
102
105
 
103
106
  Badge remains intentionally compact at Web Awesome's intrinsic `0.375em` block /
104
107
  `0.625em` inline padding (4.5px / 7.5px at its default 12px text size): it is a
package/docs/workbench.md CHANGED
@@ -47,7 +47,54 @@ const navCollapsed = signal(false);
47
47
  Each `WorkbenchPanel` takes `content`, an optional `collapsed`, an optional
48
48
  `size` (rail width or drawer height in px, overriding the CSS default —
49
49
  `--kui-workbench-rail-width` 280px, `--kui-workbench-drawer-height` 220px), and
50
- an optional `label`.
50
+ an optional `label`. Common shell behavior is configured rather than restyled:
51
+
52
+ - `separator: "auto" | "hidden"` controls the owned dock-edge separator;
53
+ - `collapseMotion: "slide" | "fade-slide" | "none"` keeps the track change
54
+ instant while choosing composited content motion;
55
+ - `contentOverflow: "clip" | "auto" | "visible"` lets a drawer temporarily
56
+ expose an open popup without a descendant override;
57
+ - `presentation: "inline" | "overlay" | "hidden"` supports compact overlays
58
+ or a responsive replacement;
59
+ - `restoreControl` places an application-owned restore affordance in a
60
+ safe-area-aware viewport corner (`restorePosition` chooses the corner).
61
+
62
+ The same policy props are available on `ResizableRegion` and
63
+ `CollapsiblePanel`, so a resizable application shell does not need to reach
64
+ into `.kui-resizable-region__content`.
65
+
66
+ ## Resizable application-shell migration
67
+
68
+ An application such as Hot Sheet can replace its shell descendant overrides
69
+ with state-derived props:
70
+
71
+ ```tsx
72
+ <ResizableRegion
73
+ id="terminal-drawer"
74
+ label="Terminal drawer"
75
+ axis="vertical"
76
+ edge="start"
77
+ size={drawerSize.value}
78
+ min={180}
79
+ max={520}
80
+ collapsed={!drawerVisible.value}
81
+ separator={magnified.value ? "hidden" : "auto"}
82
+ collapseMotion="fade-slide"
83
+ contentOverflow={createMenuOpen.value ? "visible" : "clip"}
84
+ presentation={mobile.value ? "overlay" : "inline"}
85
+ restoreControl={<button data-action="show-drawer">Show terminals</button>}
86
+ >
87
+ <TerminalDrawer />
88
+ </ResizableRegion>
89
+ ```
90
+
91
+ `wireResizableRegions` marks the active region with `data-resizing` and the
92
+ package CSS suppresses content motion during pointer resize. A collapsed,
93
+ overlay, or hidden region is not resizeable. Together these policies replace
94
+ app CSS for separator suppression, instant-track/composited-content collapse,
95
+ popup overflow, mobile overlay/hidden replacement, resize-transition guards,
96
+ and safe-area restore placement. The app still owns the signals and decides
97
+ when each policy applies.
51
98
 
52
99
  ## Public styling boundary
53
100
 
@@ -57,7 +104,7 @@ Workbench instance. The supported composition classes are `.kui-workbench`,
57
104
  `.kui-workbench__rail`, `.kui-workbench__rail--left`,
58
105
  `.kui-workbench__rail--right`, `.kui-workbench__center`,
59
106
  `.kui-workbench__main`, `.kui-workbench__drawer`, and
60
- `.kui-workbench__panel-content`; these exact hooks are cataloged for tools that
107
+ `.kui-workbench__panel-content`, and `.kui-workbench__restore`; these exact hooks are cataloged for tools that
61
108
  must classify public application selectors. Prefer the component props and two
62
109
  size tokens before selecting internal anatomy, and do not target its data
63
110
  attributes or descendant tags as styling contracts.
@@ -6,3 +6,19 @@ export interface EslintDiagnosticLike {
6
6
  export function isForeignRuleDefinitionDiagnostic(
7
7
  item: EslintDiagnosticLike,
8
8
  ): boolean;
9
+
10
+ export interface ConsumerEslintConfigLike {
11
+ rules?: Record<string, unknown>;
12
+ linterOptions?: Record<string, unknown>;
13
+ }
14
+
15
+ export interface ProjectedConsumerCoreConfig {
16
+ files: string[];
17
+ rules?: Record<string, unknown>;
18
+ linterOptions?: Record<string, unknown>;
19
+ }
20
+
21
+ export function projectConsumerCoreConfig(
22
+ config: ConsumerEslintConfigLike | undefined,
23
+ file: string,
24
+ ): ProjectedConsumerCoreConfig | undefined;