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

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 (109) hide show
  1. package/README.md +3 -2
  2. package/ai/component-catalog-v2.json +58 -1
  3. package/ai/component-catalog.json +105 -8
  4. package/ai/public-api-signatures-v1.md +265 -28
  5. package/ai/skill.md +6 -4
  6. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  7. package/dist/browser/popup-menu.js +3 -0
  8. package/dist/catalog-resources.d.ts +1 -1
  9. package/dist/catalog.d.ts +10 -4
  10. package/dist/catalog.js +243 -300
  11. package/dist/catalog.js.map +1 -1
  12. package/dist/{chunk-7IUSV4XG.js → chunk-24PHKUR3.js} +2 -2
  13. package/dist/chunk-24PHKUR3.js.map +1 -0
  14. package/dist/chunk-4BIMLITI.js +92 -0
  15. package/dist/chunk-4BIMLITI.js.map +1 -0
  16. package/dist/{chunk-ZK5EGVFP.js → chunk-5OLVUEND.js} +12 -2
  17. package/dist/chunk-5OLVUEND.js.map +1 -0
  18. package/dist/{chunk-CMUIXJZM.js → chunk-BSKEH3UC.js} +2 -2
  19. package/dist/{chunk-CMUIXJZM.js.map → chunk-BSKEH3UC.js.map} +1 -1
  20. package/dist/chunk-EAX2GSS4.js +384 -0
  21. package/dist/chunk-EAX2GSS4.js.map +1 -0
  22. package/dist/chunk-KH6VUGHU.js +399 -0
  23. package/dist/chunk-KH6VUGHU.js.map +1 -0
  24. package/dist/{chunk-BJJKFVWW.js → chunk-LZXQVUGN.js} +2 -2
  25. package/dist/chunk-LZXQVUGN.js.map +1 -0
  26. package/dist/chunk-N7FHFNT6.js +55 -0
  27. package/dist/chunk-N7FHFNT6.js.map +1 -0
  28. package/dist/{chunk-KPNTVB7A.js → chunk-R754MHXX.js} +3 -3
  29. package/dist/{chunk-KPNTVB7A.js.map → chunk-R754MHXX.js.map} +1 -1
  30. package/dist/{chunk-HJKRCKDR.js → chunk-RNRUVPJ3.js} +4 -2
  31. package/dist/chunk-RNRUVPJ3.js.map +1 -0
  32. package/dist/collapsible-panel.d.ts +40 -13
  33. package/dist/collapsible-panel.js +41 -10
  34. package/dist/collapsible-panel.js.map +1 -1
  35. package/dist/index.d.ts +1 -0
  36. package/dist/index.js +17 -16
  37. package/dist/list-header.js +1 -1
  38. package/dist/list-inset-text.d.ts +7 -1
  39. package/dist/list-inset-text.js +2 -1
  40. package/dist/panel-toolbar-BFQxFITu.d.ts +52 -0
  41. package/dist/popup-menu-register.d.ts +9 -0
  42. package/dist/popup-menu-register.js +30 -0
  43. package/dist/popup-menu-register.js.map +1 -0
  44. package/dist/popup-menu.d.ts +71 -0
  45. package/dist/popup-menu.js +3 -0
  46. package/dist/popup-menu.js.map +1 -0
  47. package/dist/state-banner.js +1 -1
  48. package/dist/styles/catalog/components/catalog-example.css +0 -16
  49. package/dist/styles/catalog/components/catalog-stage.css +8 -13
  50. package/dist/styles/catalog/components/catalog.css +8 -18
  51. package/dist/styles/catalog.css +0 -5
  52. package/dist/styles/popup-menu.css +12 -0
  53. package/dist/styles/state-banner.css +13 -4
  54. package/dist/styles/styles.css +1 -0
  55. package/dist/styles/tab-bar.css +31 -3
  56. package/dist/styles/toolbar-control-group.css +13 -0
  57. package/dist/styles/toolbar.css +43 -2
  58. package/dist/styles/workbench.css +31 -0
  59. package/dist/text.js +1 -1
  60. package/dist/token-search-field.d.ts +10 -1
  61. package/dist/token-search-field.js +1 -1
  62. package/dist/{types-CEsieBZi.d.ts → types-D6vzj-VT.d.ts} +15 -0
  63. package/dist/wire-catalog.d.ts +13 -1
  64. package/dist/wire-catalog.js +18 -3
  65. package/dist/wire-catalog.js.map +1 -1
  66. package/dist/wire-sidebar.js +6 -3
  67. package/dist/wire-sidebar.js.map +1 -1
  68. package/dist/wire-token-search-fields.js +1 -1
  69. package/dist/wire-workbench.js +1 -350
  70. package/dist/wire-workbench.js.map +1 -1
  71. package/dist/workbench.d.ts +107 -6
  72. package/dist/workbench.js +11 -208
  73. package/dist/workbench.js.map +1 -1
  74. package/docs/accessibility.md +12 -1
  75. package/docs/catalog.md +27 -9
  76. package/docs/collapsible-panel.md +55 -0
  77. package/docs/component-contract.md +2 -2
  78. package/docs/component-selection.md +25 -17
  79. package/docs/design/templates/state-banner/danger-dark.svg +1 -1
  80. package/docs/design/templates/state-banner/danger.svg +1 -1
  81. package/docs/design/templates/state-banner/info-dark.svg +1 -1
  82. package/docs/design/templates/state-banner/info.svg +1 -1
  83. package/docs/design/templates/state-banner/success-dark.svg +1 -1
  84. package/docs/design/templates/state-banner/success.svg +1 -1
  85. package/docs/design/templates/state-banner/warning-dark.svg +1 -1
  86. package/docs/design/templates/state-banner/warning.svg +1 -1
  87. package/docs/design/templates/state-banner-dark.svg +1 -1
  88. package/docs/design/templates/state-banner.svg +1 -1
  89. package/docs/layout.md +5 -0
  90. package/docs/recipes.md +44 -37
  91. package/docs/surface-scaffold.md +1 -1
  92. package/docs/ux-demo.md +6 -2
  93. package/docs/workbench.md +92 -7
  94. package/llms.txt +6 -5
  95. package/package.json +13 -2
  96. package/ux-demo/recipes/app-shell.tsx +141 -223
  97. package/ux-demo/recipes/collapsible-sidebar.tsx +44 -75
  98. package/ux-demo/recipes/list-detail-dialog.tsx +150 -54
  99. package/ux-demo/recipes/mount-recipe.ts +0 -5
  100. package/ux-demo/recipes/types.ts +0 -1
  101. package/dist/chunk-7IUSV4XG.js.map +0 -1
  102. package/dist/chunk-BJJKFVWW.js.map +0 -1
  103. package/dist/chunk-HJKRCKDR.js.map +0 -1
  104. package/dist/chunk-ZK5EGVFP.js.map +0 -1
  105. package/dist/styles/catalog/components/catalog-detail.css +0 -35
  106. package/dist/styles/catalog/components/catalog-resource-footer.css +0 -37
  107. package/dist/styles/catalog/components/catalog-secondary-sections.css +0 -38
  108. package/dist/styles/catalog/components/catalog-section-list.css +0 -22
  109. package/dist/styles/catalog/components/catalog-sidebar.css +0 -82
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 592 786" width="592" height="786"><defs><clipPath id="cp0"><rect x="16" y="38" width="560" height="116"/></clipPath><clipPath id="cp1"><rect x="16" y="192" width="560" height="116"/></clipPath><clipPath id="cp2"><rect x="16" y="346" width="560" height="116"/></clipPath><clipPath id="cp3"><rect x="16" y="500" width="560" height="116"/></clipPath><clipPath id="cp4"><rect x="16" y="654" width="560" height="116"/></clipPath><clipPath id="ct5"><rect x="16" y="16" width="560" height="22"/></clipPath><clipPath id="irc6"><rect x="16" y="38" width="560" height="116" rx="0"/></clipPath><clipPath id="ct8"><rect x="16" y="170" width="560" height="22"/></clipPath><clipPath id="irc9"><rect x="16" y="192" width="560" height="116" rx="0"/></clipPath><clipPath id="ct11"><rect x="16" y="324" width="560" height="22"/></clipPath><clipPath id="irc12"><rect x="16" y="346" width="560" height="116" rx="0"/></clipPath><clipPath id="ct14"><rect x="16" y="478" width="560" height="22"/></clipPath><clipPath id="irc15"><rect x="16" y="500" width="560" height="116" rx="0"/></clipPath><clipPath id="ct17"><rect x="16" y="632" width="560" height="22"/></clipPath><clipPath id="irc18"><rect x="16" y="654" width="560" height="116" rx="0"/></clipPath></defs><rect x="0" y="0" width="592" height="786" 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)">Info</text><g clip-path="url(#cp0)"><g clip-path="url(#irc6)"><clipPath id="svgimg7vclip"><rect x="16" y="38" width="560" height="116"/></clipPath><g clip-path="url(#svgimg7vclip)"><g transform="translate(16 38)"><defs><clipPath id="svgimg7cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="svgimg7cp2"><rect x="61" y="44.4" width="368.6" height="13"/></clipPath><clipPath id="svgimg7ct3"><rect x="61" y="29.4" width="116.7" height="15"/></clipPath><clipPath id="svgimg7ct4"><rect x="61" y="44.4" width="368.6" height="13"/></clipPath><clipPath id="svgimg7ct5"><rect x="437.6" y="29" width="65.4" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(235,244,252)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(166,207,242)" stroke-width="1"/><g clip-path="url(#svgimg7cp0)"><g color="rgb(26, 93, 207)"><clipPath id="svgimg7svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgimg7svgic1)"><g transform="translate(37 35.39)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12" y1="8" y2="12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12.01" y1="16" y2="16" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" 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="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(26,93,207)">Draft not published</text><g clip-path="url(#svgimg7cp2)"><g clip-path="url(#svgimg7ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(26,93,207)">Changes are saved but only visible to your team.</text></g></g><rect x="437.6" y="29" width="65.4" height="28.8" rx="14.4" fill="rgba(255,255,255,0.52)"/><rect x="438.5" y="29.5" width="64" height="28" rx="13.9" fill="none" stroke="rgb(26,93,207)" stroke-width="1"/><text x="449.83" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(26,93,207)">Publish</text></g></g></g></g><text x="16" y="182" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="600" fill="rgb(110,110,115)">Info with badge</text><g clip-path="url(#cp1)"><g clip-path="url(#irc9)"><clipPath id="svgimg10vclip"><rect x="16" y="192" width="560" height="116"/></clipPath><g clip-path="url(#svgimg10vclip)"><g transform="translate(16 192)"><defs><clipPath id="svgimg10cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="svgimg10ct2"><rect x="61" y="35.9" width="137.6" height="15"/></clipPath><clipPath id="svgimg10ct3"><rect x="206.6" y="33.4" width="20" height="20"/></clipPath><clipPath id="svgimg10ct4"><rect x="437.3" y="29" width="65.7" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(235,244,252)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(166,207,242)" stroke-width="1"/><g clip-path="url(#svgimg10cp0)"><g color="rgb(26, 93, 207)"><clipPath id="svgimg10svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgimg10svgic1)"><g transform="translate(37 35.39)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12" y1="8" y2="12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12.01" y1="16" y2="16" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" 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="61" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(26,93,207)">Unanswered questions</text><rect x="206.6" y="33.4" width="20" height="20" rx="10" fill="rgb(26,93,207)"/><rect x="207.5" y="33.5" width="19" height="19" rx="9.5" fill="none" stroke="rgba(0,0,0,0)" stroke-width="1"/><text x="213.83" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(255,255,255)">1</text><rect x="437.3" y="29" width="65.7" height="28.8" rx="14.4" fill="rgba(255,255,255,0.52)"/><rect x="437.5" y="29.5" width="65" height="28" rx="13.9" fill="none" stroke="rgb(26,93,207)" stroke-width="1"/><text x="449.47" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(26,93,207)">Answer</text></g></g></g></g><text x="16" y="336" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="600" fill="rgb(110,110,115)">Success</text><g clip-path="url(#cp2)"><g clip-path="url(#irc12)"><clipPath id="svgimg13vclip"><rect x="16" y="346" width="560" height="116"/></clipPath><g clip-path="url(#svgimg13vclip)"><g transform="translate(16 346)"><defs><clipPath id="svgimg13cp0"><rect x="37" y="35" width="16" height="16"/></clipPath><clipPath id="svgimg13cp2"><rect x="61" y="44" width="434" height="13"/></clipPath><clipPath id="svgimg13ct3"><rect x="61" y="29" width="132.1" height="15"/></clipPath><clipPath id="svgimg13ct4"><rect x="61" y="44" width="434" height="13"/></clipPath></defs><rect x="28" y="20" width="484" height="46" rx="12" fill="rgb(227,247,232)"/><rect x="28.5" y="20.5" width="483" height="45" rx="11.5" fill="none" stroke="rgb(154,227,172)" stroke-width="1"/><g clip-path="url(#svgimg13cp0)"><g color="rgb(0, 121, 44)"><clipPath id="svgimg13svgic1"><rect x="37" y="35" width="16" height="16"/></clipPath><g clip-path="url(#svgimg13svgic1)"><g transform="translate(37 35)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(0, 121, 44)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="m16 9-5.5 5.5L8 12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(0, 121, 44)" 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="61" y="41" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(0,121,44)">Deployment complete</text><g clip-path="url(#svgimg13cp2)"><g clip-path="url(#svgimg13ct4)"><text x="61" y="55" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(0,121,44)">production.example.com is serving the new build.</text></g></g></g></g></g></g><text x="16" y="490" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="600" fill="rgb(110,110,115)">Warning</text><g clip-path="url(#cp3)"><g clip-path="url(#irc15)"><clipPath id="svgimg16vclip"><rect x="16" y="500" width="560" height="116"/></clipPath><g clip-path="url(#svgimg16vclip)"><g transform="translate(16 500)"><defs><clipPath id="svgimg16cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="svgimg16cp2"><rect x="61" y="44.4" width="362.1" height="13"/></clipPath><clipPath id="svgimg16ct3"><rect x="61" y="29.4" width="166.1" height="15"/></clipPath><clipPath id="svgimg16ct4"><rect x="61" y="44.4" width="362.1" height="13"/></clipPath><clipPath id="svgimg16ct5"><rect x="431.1" y="29" width="71.9" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(255,250,232)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(160,131,13)" stroke-width="1"/><g clip-path="url(#svgimg16cp0)"><g color="rgb(143, 94, 0)"><clipPath id="svgimg16svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgimg16svgic1)"><g transform="translate(37 35.39)scale(.66667)"><path d="m21.7 18-8-14a2 2 0 0 0-3.4 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(143, 94, 0)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M12 9v4" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(143, 94, 0)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M12 17z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(143, 94, 0)" 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="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(143,94,0)">Approaching your plan limit</text><g clip-path="url(#svgimg16cp2)"><g clip-path="url(#svgimg16ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(143,94,0)">You have used 92% of this month’s build minutes.</text></g></g><rect x="431.1" y="29" width="71.9" height="28.8" rx="14.4" fill="rgba(255,255,255,0.52)"/><rect x="431.5" y="29.5" width="71" height="28" rx="13.9" fill="none" stroke="rgb(143,94,0)" stroke-width="1"/><text x="443.28" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(143,94,0)">Upgrade</text></g></g></g></g><text x="16" y="644" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="600" fill="rgb(110,110,115)">Danger (alert)</text><g clip-path="url(#cp4)"><g clip-path="url(#irc18)"><clipPath id="svgimg19vclip"><rect x="16" y="654" width="560" height="116"/></clipPath><g clip-path="url(#svgimg19vclip)"><g transform="translate(16 654)"><defs><clipPath id="svgimg19cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="svgimg19cp2"><rect x="61" y="44.4" width="362.7" height="13"/></clipPath><clipPath id="svgimg19ct3"><rect x="61" y="29.4" width="67.5" height="15"/></clipPath><clipPath id="svgimg19ct4"><rect x="61" y="44.4" width="362.7" height="13"/></clipPath><clipPath id="svgimg19ct5"><rect x="431.7" y="29" width="71.3" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(254,237,238)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(249,173,175)" stroke-width="1"/><g clip-path="url(#svgimg19cp0)"><g color="rgb(194, 11, 32)"><clipPath id="svgimg19svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgimg19svgic1)"><g transform="translate(37 35.39)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(194, 11, 32)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12" y1="8" y2="12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(194, 11, 32)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12.01" y1="16" y2="16" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(194, 11, 32)" 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="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(194,11,32)">Build failed</text><g clip-path="url(#svgimg19cp2)"><g clip-path="url(#svgimg19ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(194,11,32)">Step “test” exited with code 1.</text></g></g><rect x="431.7" y="29" width="71.3" height="28.8" rx="14.4" fill="rgba(255,255,255,0.52)"/><rect x="432.5" y="29.5" width="70" height="28" rx="13.9" fill="none" stroke="rgb(194,11,32)" stroke-width="1"/><text x="443.88" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(194,11,32)">View log</text></g></g></g></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 592 786" width="592" height="786"><defs><clipPath id="cp0"><rect x="16" y="38" width="560" height="116"/></clipPath><clipPath id="cp1"><rect x="16" y="192" width="560" height="116"/></clipPath><clipPath id="cp2"><rect x="16" y="346" width="560" height="116"/></clipPath><clipPath id="cp3"><rect x="16" y="500" width="560" height="116"/></clipPath><clipPath id="cp4"><rect x="16" y="654" width="560" height="116"/></clipPath><clipPath id="ct5"><rect x="16" y="16" width="560" height="22"/></clipPath><clipPath id="irc6"><rect x="16" y="38" width="560" height="116" rx="0"/></clipPath><clipPath id="ct8"><rect x="16" y="170" width="560" height="22"/></clipPath><clipPath id="irc9"><rect x="16" y="192" width="560" height="116" rx="0"/></clipPath><clipPath id="ct11"><rect x="16" y="324" width="560" height="22"/></clipPath><clipPath id="irc12"><rect x="16" y="346" width="560" height="116" rx="0"/></clipPath><clipPath id="ct14"><rect x="16" y="478" width="560" height="22"/></clipPath><clipPath id="irc15"><rect x="16" y="500" width="560" height="116" rx="0"/></clipPath><clipPath id="ct17"><rect x="16" y="632" width="560" height="22"/></clipPath><clipPath id="irc18"><rect x="16" y="654" width="560" height="116" rx="0"/></clipPath></defs><rect x="0" y="0" width="592" height="786" 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)">Info</text><g clip-path="url(#cp0)"><g clip-path="url(#irc6)"><clipPath id="svgimg7vclip"><rect x="16" y="38" width="560" height="116"/></clipPath><g clip-path="url(#svgimg7vclip)"><g transform="translate(16 38)"><defs><clipPath id="svgimg7cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="svgimg7ct2"><rect x="61" y="29.4" width="116.7" height="15"/></clipPath><clipPath id="svgimg7cp3"><rect x="61" y="44.4" width="254.4" height="13"/></clipPath><clipPath id="svgimg7ct4"><rect x="61" y="44.4" width="254.4" height="13"/></clipPath><clipPath id="svgimg7ct5"><rect x="437.6" y="29" width="65.4" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(235,244,252)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(166,207,242)" stroke-width="1"/><g clip-path="url(#svgimg7cp0)"><g color="rgb(26, 93, 207)"><clipPath id="svgimg7svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgimg7svgic1)"><g transform="translate(37 35.39)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12" y1="8" y2="12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12.01" y1="16" y2="16" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" 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="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(26,93,207)">Draft not published</text><g clip-path="url(#svgimg7cp3)"><g clip-path="url(#svgimg7ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(26,93,207)">Changes are saved but only visible to your team.</text></g></g><rect x="437.6" y="29" width="65.4" height="28.8" rx="14.4" fill="rgba(255,255,255,0.52)"/><rect x="438.5" y="29.5" width="64" height="28" rx="13.9" fill="none" stroke="rgb(26,93,207)" stroke-width="1"/><text x="449.83" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(26,93,207)">Publish</text></g></g></g></g><text x="16" y="182" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="600" fill="rgb(110,110,115)">Info with badge</text><g clip-path="url(#cp1)"><g clip-path="url(#irc9)"><clipPath id="svgimg10vclip"><rect x="16" y="192" width="560" height="116"/></clipPath><g clip-path="url(#svgimg10vclip)"><g transform="translate(16 192)"><defs><clipPath id="svgimg10cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="svgimg10ct2"><rect x="61" y="35.9" width="137.6" height="15"/></clipPath><clipPath id="svgimg10ct3"><rect x="206.6" y="33.4" width="20" height="20"/></clipPath><clipPath id="svgimg10ct4"><rect x="437.3" y="29" width="65.7" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(235,244,252)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(166,207,242)" stroke-width="1"/><g clip-path="url(#svgimg10cp0)"><g color="rgb(26, 93, 207)"><clipPath id="svgimg10svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgimg10svgic1)"><g transform="translate(37 35.39)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12" y1="8" y2="12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12.01" y1="16" y2="16" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(26, 93, 207)" 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="61" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(26,93,207)">Unanswered questions</text><rect x="206.6" y="33.4" width="20" height="20" rx="10" fill="rgb(26,93,207)"/><rect x="207.5" y="33.5" width="19" height="19" rx="9.5" fill="none" stroke="rgba(0,0,0,0)" stroke-width="1"/><text x="213.83" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(255,255,255)">1</text><rect x="437.3" y="29" width="65.7" height="28.8" rx="14.4" fill="rgba(255,255,255,0.52)"/><rect x="437.5" y="29.5" width="65" height="28" rx="13.9" fill="none" stroke="rgb(26,93,207)" stroke-width="1"/><text x="449.47" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(26,93,207)">Answer</text></g></g></g></g><text x="16" y="336" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="600" fill="rgb(110,110,115)">Success</text><g clip-path="url(#cp2)"><g clip-path="url(#irc12)"><clipPath id="svgimg13vclip"><rect x="16" y="346" width="560" height="116"/></clipPath><g clip-path="url(#svgimg13vclip)"><g transform="translate(16 346)"><defs><clipPath id="svgimg13cp0"><rect x="37" y="35" width="16" height="16"/></clipPath><clipPath id="svgimg13ct2"><rect x="61" y="29" width="132.1" height="15"/></clipPath><clipPath id="svgimg13cp3"><rect x="61" y="44" width="259.7" height="13"/></clipPath><clipPath id="svgimg13ct4"><rect x="61" y="44" width="259.7" height="13"/></clipPath></defs><rect x="28" y="20" width="484" height="46" rx="12" fill="rgb(227,247,232)"/><rect x="28.5" y="20.5" width="483" height="45" rx="11.5" fill="none" stroke="rgb(154,227,172)" stroke-width="1"/><g clip-path="url(#svgimg13cp0)"><g color="rgb(0, 121, 44)"><clipPath id="svgimg13svgic1"><rect x="37" y="35" width="16" height="16"/></clipPath><g clip-path="url(#svgimg13svgic1)"><g transform="translate(37 35)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(0, 121, 44)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="m16 9-5.5 5.5L8 12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(0, 121, 44)" 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="61" y="41" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(0,121,44)">Deployment complete</text><g clip-path="url(#svgimg13cp3)"><g clip-path="url(#svgimg13ct4)"><text x="61" y="55" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(0,121,44)">production.example.com is serving the new build.</text></g></g></g></g></g></g><text x="16" y="490" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="600" fill="rgb(110,110,115)">Warning</text><g clip-path="url(#cp3)"><g clip-path="url(#irc15)"><clipPath id="svgimg16vclip"><rect x="16" y="500" width="560" height="116"/></clipPath><g clip-path="url(#svgimg16vclip)"><g transform="translate(16 500)"><defs><clipPath id="svgimg16cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="svgimg16ct2"><rect x="61" y="29.4" width="166.1" height="15"/></clipPath><clipPath id="svgimg16cp3"><rect x="61" y="44.4" width="261" height="13"/></clipPath><clipPath id="svgimg16ct4"><rect x="61" y="44.4" width="261" height="13"/></clipPath><clipPath id="svgimg16ct5"><rect x="431.1" y="29" width="71.9" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(255,250,232)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(160,131,13)" stroke-width="1"/><g clip-path="url(#svgimg16cp0)"><g color="rgb(143, 94, 0)"><clipPath id="svgimg16svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgimg16svgic1)"><g transform="translate(37 35.39)scale(.66667)"><path d="m21.7 18-8-14a2 2 0 0 0-3.4 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(143, 94, 0)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M12 9v4" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(143, 94, 0)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M12 17z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(143, 94, 0)" 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="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(143,94,0)">Approaching your plan limit</text><g clip-path="url(#svgimg16cp3)"><g clip-path="url(#svgimg16ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(143,94,0)">You have used 92% of this month’s build minutes.</text></g></g><rect x="431.1" y="29" width="71.9" height="28.8" rx="14.4" fill="rgba(255,255,255,0.52)"/><rect x="431.5" y="29.5" width="71" height="28" rx="13.9" fill="none" stroke="rgb(143,94,0)" stroke-width="1"/><text x="443.28" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(143,94,0)">Upgrade</text></g></g></g></g><text x="16" y="644" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="600" fill="rgb(110,110,115)">Danger (alert)</text><g clip-path="url(#cp4)"><g clip-path="url(#irc18)"><clipPath id="svgimg19vclip"><rect x="16" y="654" width="560" height="116"/></clipPath><g clip-path="url(#svgimg19vclip)"><g transform="translate(16 654)"><defs><clipPath id="svgimg19cp0"><rect x="37" y="35" width="16" height="16.4"/></clipPath><clipPath id="svgimg19ct2"><rect x="61" y="29.4" width="67.5" height="15"/></clipPath><clipPath id="svgimg19cp3"><rect x="61" y="44.4" width="158.6" height="13"/></clipPath><clipPath id="svgimg19ct4"><rect x="61" y="44.4" width="158.6" height="13"/></clipPath><clipPath id="svgimg19ct5"><rect x="431.7" y="29" width="71.3" height="28.8"/></clipPath></defs><rect x="28" y="20" width="484" height="46.8" rx="12" fill="rgb(254,237,238)"/><rect x="28.5" y="20.5" width="483" height="46" rx="11.5" fill="none" stroke="rgb(249,173,175)" stroke-width="1"/><g clip-path="url(#svgimg19cp0)"><g color="rgb(194, 11, 32)"><clipPath id="svgimg19svgic1"><rect x="37" y="35.4" width="16" height="16"/></clipPath><g clip-path="url(#svgimg19svgic1)"><g transform="translate(37 35.39)scale(.66667)"><circle cx="12" cy="12" r="10" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(194, 11, 32)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12" y1="8" y2="12" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(194, 11, 32)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><line x1="12" x2="12.01" y1="16" y2="16" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(194, 11, 32)" 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="61" y="41.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="700" fill="rgb(194,11,32)">Build failed</text><g clip-path="url(#svgimg19cp3)"><g clip-path="url(#svgimg19ct4)"><text x="61" y="55.39" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" fill="rgb(194,11,32)">Step “test” exited with code 1.</text></g></g><rect x="431.7" y="29" width="71.3" height="28.8" rx="14.4" fill="rgba(255,255,255,0.52)"/><rect x="432.5" y="29.5" width="70" height="28" rx="13.9" fill="none" stroke="rgb(194,11,32)" stroke-width="1"/><text x="443.88" y="47.89" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="11" font-weight="650" fill="rgb(194,11,32)">View log</text></g></g></g></g></svg>
package/docs/layout.md CHANGED
@@ -96,6 +96,11 @@ also keeps 8px of root-scaled block padding independently of its semantic inline
96
96
  inset. Most interactive rows and toolbar groups are 44px tall.
97
97
  Toolbar groups reserve a real 1px outer border around a 42px inner area, even
98
98
  when their border and background are transparent.
99
+ A `Toolbar` lays its zones out against one 44px control band at its top: an
100
+ item no taller than the band is centered in it by its own size, and a taller
101
+ item (a wrapped title, a second trailing row) starts at the band's top and
102
+ grows down, so it never moves the other controls. A wrapped `ToolbarText`
103
+ centers its first line in the band.
99
104
  Trailing icon actions share one axis: a toolbar control centers its glyph in
100
105
  that 44px slot at the 8px inline margin, and a `ListHeader` action centers its
101
106
  fitted 36px square in a slot of the same size (a transparent hit layer extends
package/docs/recipes.md CHANGED
@@ -9,9 +9,9 @@ ship no stylesheet of their own and are not new monolithic components.
9
9
  Copy the recipe source together with the catalog-independent
10
10
  [`mount-recipe.ts`](../ux-demo/recipes/mount-recipe.ts) adapter. It mounts the
11
11
  controller at one stable application root, uses `delegateActions()` for recipe
12
- commands, forwards form and dialog lifecycle events, wires resize commits with
13
- the public `onCommit` callback, retains every disposer, and returns one
14
- idempotent disposer:
12
+ commands, forwards form and dialog lifecycle events, runs the recipe's own
13
+ `wire()` (for example `wireWorkbench` or `wireSidebar`), retains every
14
+ disposer, and returns one idempotent disposer:
15
15
 
16
16
  ```ts
17
17
  import { createRecipe } from "./navigation-sidebar.js";
@@ -31,24 +31,26 @@ specific dispatch; either way, wire once at a stable root and retain disposal.
31
31
  [Open the recipe](../ux-demo/?component=recipe-app-shell) · [TSX source](../ux-demo/recipes/app-shell.tsx)
32
32
 
33
33
  A filling `List` (`fill`, with the recipe's `data-*` markers through
34
- `rootAttributes`) stacks the app-bar `Toolbar` above a `Row` that places
35
- controlled `ResizableRegion` navigation and inspector panes around a content
36
- `Pane` that a one-column `Grid` grows to fill. Each region's lone `Pane` fills
37
- the region's full height, so it reaches the bottom edge the separator does.
38
- Only those three real panes own a
39
- `.kui-pane__content` scroll owner; no frame `Pane` wraps the layout in a scroll
40
- owner that never scrolls. Each pane lists the screen edges it reaches in
41
- `safeAreaEdges` (the bottom plus its outer side, or both sides when it is the
42
- only pane shown), and the app-bar `Toolbar` claims the top edge and both sides
43
- with its own `safeAreaEdges`, so it clears the status area. Below desktop sizes the app reads `deviceClass()` and shows one
44
- pane at a time, switched by a pressed-state `ToolbarControlGroup`. The recipe
45
- owns the shell topology; the app owns routing, responsive pane visibility,
46
- sizes, persistence, and data.
47
- Keep each visible pane's collapse action in its own toolbar. Once hidden, put
48
- its restore action in the adjacent main toolbar on the same logical edge:
49
- leading for an inline-start sidebar and trailing for an inline-end inspector.
50
- Collapse the pane completely rather than preserving an empty icon rail.
51
- Adapt only public `--kui-layout-*` and component variables.
34
+ `rootAttributes`) stacks the app-bar `Toolbar` above a `Workbench`
35
+ (`@kerfjs/ui/workbench`): resizable navigation and inspector rails around the
36
+ task list. Each rail composes its own panel toolbar — a default-size title and
37
+ the standard hide toggle — and the work area's `mainToolbar` carries the xl
38
+ view title. While a rail is hidden, `Workbench` relocates its show toggle into
39
+ the work-area toolbar on the same logical edge (leading for the navigation
40
+ rail, trailing for the inspector), and `wireWorkbench` hands focus between the
41
+ two positions. Collapse a rail completely rather than preserving an empty icon
42
+ rail. Only the three real panes own a `.kui-pane__content` scroll owner; no
43
+ frame `Pane` wraps the layout in a scroll owner that never scrolls, and the
44
+ app-bar `Toolbar` claims the top edge and both sides with its own
45
+ `safeAreaEdges`.
46
+
47
+ On a narrow container the rails overlay the task list one at a time instead of
48
+ squeezing it, leaving a 44px strip on the far side that dismisses the overlay
49
+ (`responsiveOverlayAt`, on by default; `compactOverlay: 'full'` covers the
50
+ whole width). The app owns each rail's collapsed and size signals — which
51
+ `wireWorkbench` keeps in sync with resizing and overlay dismissal — plus
52
+ routing, persistence, and data. Adapt only public `--kui-layout-*` and
53
+ component variables.
52
54
 
53
55
  ## Navigation sidebar
54
56
 
@@ -75,19 +77,23 @@ controls relocate without changing focus order.
75
77
 
76
78
  [Open the recipe](../ux-demo/?component=recipe-list-detail-dialog) · [TSX source](../ux-demo/recipes/list-detail-dialog.tsx)
77
79
 
78
- The production Web Awesome dialog owns modal focus, Escape, its labeled header,
79
- and its close control; the thin recipe adapter restores the invoking control
80
- after the hide event. `DialogSurface` chooses the large modal with no body
81
- inset, because `SplitView` and its rows own list geometry, and a comfortable
82
- footer inset for the record actions. On roomy devices `SplitView` shows the
83
- project list beside its detail; each pane opens with a `ListHeader` on one
84
- shared line, and the dialog title, both headers, and the list text share the
85
- 17px text edge while the `ValueTable` keeps the 8px outer margin. On compact
86
- devices the dialog becomes a full-screen sheet and `SplitView` becomes a
80
+ A list-detail dialog is laid out like a `Workbench` with a left sidebar: on
81
+ roomy devices the list is a full-height sidebar and the detail is a full-height
82
+ main column, each a `Pane` with its own top `Toolbar`. The sidebar's toolbar
83
+ carries its quiet default-size title (and it may add a bottom toolbar for
84
+ sidebar-only actions); the main column's toolbar carries the dialog's primary
85
+ extra-large title and the close control, and its footer carries the record
86
+ actions. The Web Awesome dialog therefore renders `without-header` there —
87
+ its label still names the modal — and the close button uses
88
+ `data-dialog="close"`. Web Awesome keeps modal focus and Escape, and the thin
89
+ recipe adapter restores the invoking control after the hide event.
90
+ `DialogSurface` chooses the large modal with no body inset, because the panes
91
+ own their geometry. On compact devices the dialog becomes a full-screen sheet
92
+ with its own labeled header and footer actions, and `SplitView` becomes a
87
93
  `NavStack` drill-down whose back control the application pops. The
88
94
  application owns open state, selection, the pushed detail, dismissal policy,
89
- and record actions. Do not rebuild the dialog or reach into private shadow
90
- parts.
95
+ and record actions. Do not put the primary title in a header spanning both
96
+ columns, rebuild the dialog, or reach into private shadow parts.
91
97
 
92
98
  ## Composer form
93
99
 
@@ -162,11 +168,12 @@ which values are still unknown.
162
168
 
163
169
  A mini app frame whose left navigation rail and bottom activity drawer are
164
170
  standalone `CollapsiblePanel`s (`@kerfjs/ui/collapsible-panel`) driven by
165
- `wireSidebar` (`@kerfjs/ui/wire-sidebar`). `CollapsiblePanelToggle` supplies the
166
- standard per-side glyph: a collapse toggle lives inside each panel, and the
167
- panel's expand toggle shows only while it is collapsed, so exactly one control
168
- owns each action and a collapsed panel is still reachable. The rail's expand
169
- toggle sits in the always-visible main header; the drawer's is a
171
+ `wireSidebar` (`@kerfjs/ui/wire-sidebar`). Each panel takes a `toolbar` — a
172
+ title plus the standard per-side toggle — so the hide control lives in the
173
+ panel's own header, and `CollapsiblePanelRelocated` renders the matching show
174
+ control only while the panel is collapsed, so exactly one control owns each
175
+ action and a collapsed panel is still reachable. The rail's relocated toggle
176
+ leads the always-visible main header; the drawer's sits in a
170
177
  `FloatingToolbar` passed as the drawer's own `restoreControl`, which the panel
171
178
  floats in its column's safe-area-aware bottom-end corner, next to where the
172
179
  drawer opens — do not hand-roll a conditional floating control beside the
@@ -18,7 +18,7 @@ padding and aligns with bordered siblings. Reserve `compact` or `comfortable`
18
18
  body insets for exceptional content that does not already have list/content-item
19
19
  geometry.
20
20
 
21
- Wrap one `wa-dropdown` with `PopupSurface`. `inset="list-zero"` removes menu
21
+ Wrap one `PopupMenu` (or another single `wa-dropdown`) with `PopupSurface`. `inset="list-zero"` removes menu
22
22
  padding for a child that already owns row insets, `compact` uses 4px, and
23
23
  `standard` uses the shared 8px surface inset. Keep the dropdown trigger named and
24
24
  preserve `data-morph-skip-children` when its upgraded light-DOM items must retain
package/docs/ux-demo.md CHANGED
@@ -10,7 +10,11 @@ launch Chromium, Firefox, and WebKit. The build emits
10
10
  `source-freshness.json`; browser coverage compares it with an independent hash
11
11
  of the current `src/` and `ux-demo/` inputs, so a stale `dist-demo` cannot pass
12
12
  after a route or component edit. `npm run demo:serve` remains a preview-only
13
- command for an already-built catalog.
13
+ command for an already-built catalog. The demo-conformance preflight also
14
+ rejects a component route that wraps its `CatalogExampleStack` in a card or
15
+ other container (`catalog-demo/wrapped-example-stack`): single-component demos
16
+ sit directly on the catalog grid, and only composition and recipe routes frame
17
+ their content.
14
18
 
15
19
  Ten lazy production-composition routes live under the `Recipes` category.
16
20
  Each `?component=recipe-*` route uses public package primitives, real wiring,
@@ -25,7 +29,7 @@ deterministic state, and semantic layout owners from the [recipe guide](./recipe
25
29
  - 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.
26
30
  - 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 preview scroll owner rather than a viewport-height stage or nested card, and one explicitly repeated SVG tile keeps the pattern continuous through below-fold content. 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.
27
31
  - 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.
28
- - The list-detail dialog recipe composes `DialogSurface`, the dialog's own labeled header and close control, `SplitView`, and footer actions. Its `SplitView` sits flush in the dialog body, both panes open with a `ListHeader` on one shared line, the dialog title and header text share the 17px text edge, the value table keeps the 8px outer margin, and the trailing actions keep the 16px footer gutter. Compact devices get a full-screen sheet with a list-to-detail drill-down. Browser geometry coverage protects those relationships at wide and narrow widths.
32
+ - The list-detail dialog recipe is laid out like a `Workbench` on roomy devices: a headerless `DialogSurface` modal whose `SplitView` holds a full-height list sidebar `Pane` with its own toolbar beside a full-height detail `Pane` that carries the primary xl title, the `data-dialog="close"` control, and the record actions in its footer. Compact devices get a full-screen sheet with its own labeled header, footer actions, and a list-to-detail drill-down. Browser geometry coverage protects those relationships at wide and narrow widths.
29
33
  - 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.
30
34
  - 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.
31
35
  - 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`.
package/docs/workbench.md CHANGED
@@ -65,7 +65,8 @@ const navCollapsed = signal(false);
65
65
  />;
66
66
  ```
67
67
 
68
- Each `WorkbenchPanel` takes `content`, an optional `collapsed`, an optional
68
+ Each `WorkbenchPanel` takes `content`, an optional `toolbar` and `footer` (see
69
+ [Panel toolbars](#panel-toolbars)), an optional `collapsed`, an optional
69
70
  `size` (rail width or drawer height in px, overriding the CSS default —
70
71
  `--kui-workbench-rail-width` 280px, `--kui-workbench-drawer-height` 220px), and
71
72
  an optional `label`. Common shell behavior is configured rather than restyled:
@@ -81,10 +82,20 @@ an optional `label`. Common shell behavior is configured rather than restyled:
81
82
  each exactly at its configured size (its separator border included, as in
82
83
  flow) up to the viewport-relative overlay maximum; the content fills the
83
84
  panel inside its border, so it is clamped with it;
84
- - `responsiveOverlayAt: "narrow" | "compact"` presents a rail or the bottom
85
- drawer as an overlay below a Workbench container breakpoint — 704px or less
86
- for `narrow`, 448px or less for `compact`, the breakpoints of
87
- `ResizableRegion`'s `responsiveFillAt` — and inline above it. The CSS
85
+ - `responsiveOverlayAt: "narrow" | "compact" | "never"` presents a rail or the
86
+ bottom drawer as an overlay below a Workbench container breakpoint — 704px
87
+ or less for `narrow`, 448px or less for `compact`, the breakpoints of
88
+ `ResizableRegion`'s `responsiveFillAt` — and inline above it. **Rails
89
+ default to `narrow`**, so on a small screen a sidebar covers the work area
90
+ (and an open drawer) instead of squeezing it; pass `never` to keep a rail
91
+ inline. The drawer stays inline unless it opts in. On a compact (448px or
92
+ less) Workbench an overlay rail fills the Workbench less a dismiss strip on
93
+ the side away from its edge — `--kui-workbench-overlay-dismiss-margin`,
94
+ 44px, one touch target — so a press beside it closes it;
95
+ `compactOverlay: "full"` (per rail) fills the Workbench instead, which
96
+ usually wants app-level handling of its own. Pass each rail's `collapsed`
97
+ signal to `wireWorkbench` so only one overlay is open at a time and a press
98
+ outside closes it. The CSS
88
99
  decides, so the app needs no `deviceClass` check for presentation; a
89
100
  collapsed overlay drops its surface and shadow so nothing covers the work
90
101
  area, and the work area keeps the safe-area inset of the edge the overlay
@@ -98,8 +109,10 @@ an optional `label`. Common shell behavior is configured rather than restyled:
98
109
  it covers the rest of the work area, and a collapsed overlay, which drops
99
110
  its pointer events, leaves the control beneath it usable;
100
111
  - `restoreControl` places an application-owned restore affordance in a
101
- corner of the Workbench itself while the panel is collapsed
102
- (`restorePosition` chooses the corner), inset by
112
+ corner of the Workbench itself while the panel is collapsed. Prefer a
113
+ `toolbar.toggle`, which the Workbench relocates for you; keep
114
+ `restoreControl` for a custom affordance. `restorePosition` chooses the
115
+ corner, inset by
103
116
  `--kui-workbench-restore-inset` (16px) plus the unsafe area of each edge the
104
117
  corner reaches. A rail's control sits in the Workbench's corner; the
105
118
  drawer's sits in the corner of the work-area column it restores into, so it
@@ -127,6 +140,78 @@ The same policy props are available on `ResizableRegion` and
127
140
  `CollapsiblePanel`, so a resizable application shell does not need to reach
128
141
  into `.kui-resizable-region__content`.
129
142
 
143
+ ## Panel toolbars
144
+
145
+ A panel's controls follow it open and closed when the Workbench composes the
146
+ toolbars. Give a panel a `toolbar` and the work area a `mainToolbar` (and, for
147
+ a drawer, optionally a `mainBottomToolbar`); the Workbench renders each as a
148
+ standard `Toolbar` over a `Pane`, and moves groups between them as panels open
149
+ and close. A panel's `toolbar` has four parts:
150
+
151
+ - `title` — the panel's `ToolbarText` (the quiet default size in a rail).
152
+ - `panelOnly` — groups that make sense only while the panel is open. They lead
153
+ its toolbar, after the title, and are unavailable while it is closed.
154
+ - `constant` — groups that stay available either way. They trail the panel's
155
+ toolbar while it is open and move to the work area's toolbar while it is
156
+ closed.
157
+ - `toggle: { action, name }` — the standard collapse toggle, which the
158
+ Workbench renders: the per-side panel glyph, `aria-controls` naming the
159
+ panel, `aria-expanded`, a "Show …"/"Hide …" label, and the `data-action`
160
+ the app handles. It is always the last group.
161
+
162
+ While a panel is closed, its `constant` groups and then its toggle go to:
163
+
164
+ | Panel | Where they go |
165
+ | ------------- | --------------------------------------------------------------------------------------------------------------- |
166
+ | Left rail | The leading edge of `mainToolbar`, before its `title` |
167
+ | Right rail | The trailing edge of `mainToolbar`, after its `trailing` groups, so the toggle is the toolbar's last group |
168
+ | Bottom drawer | The trailing edge of `mainBottomToolbar`; without one, a `FloatingToolbar` in the work area's bottom-end corner |
169
+
170
+ A rail with no `mainToolbar` floats its groups in its corner the same way, so
171
+ a closed panel can always be reopened. An open overlay panel carries its own
172
+ toggle, so it never depends on a control it covers. An app's own
173
+ `restoreControl` still wins over the floating fallback.
174
+
175
+ ```tsx
176
+ <Workbench
177
+ id="studio"
178
+ label="Studio"
179
+ mainToolbar={{ label: "Editor", title: <ToolbarText text="Editor" size="xlarge" /> }}
180
+ main={<Editor />}
181
+ leftRail={{
182
+ label: "Navigator",
183
+ toolbar: {
184
+ label: "Navigator",
185
+ title: <ToolbarText text="Navigator" />,
186
+ panelOnly: <NewFileGroup />,
187
+ constant: <SearchGroup />,
188
+ toggle: { action: "toggle-navigator", name: "navigator" },
189
+ },
190
+ content: <Files />,
191
+ collapsed: navCollapsed.value,
192
+ }}
193
+ />
194
+ ```
195
+
196
+ The work area's `Pane` can carry more fixed chrome: `mainHeader` renders under
197
+ `mainToolbar` (supporting copy) and `mainFooter` over `mainBottomToolbar` (a status
198
+ line or a resource toolbar), each divided from the scrolling `main`.
199
+ `mainHeaderPlacement` and `mainFooterPlacement` (`"fixed"` by default, or
200
+ `"scroll"`) let that header or footer chrome scroll away with `main` instead —
201
+ useful where large text would leave pinned chrome little room. `mainToolbar` also
202
+ takes the `Toolbar`'s `responsive` / `responsiveAt` policy; `responsive: "wrap"`
203
+ keeps a long title whole and wraps its actions below it.
204
+
205
+ Size a rail so its title and groups fit at its narrowest (a resizable rail's
206
+ `min`); a toolbar that cannot hold them drops the title rather than
207
+ truncating it. `constant` content renders in both places while the panel is
208
+ closed (the panel's copy is inert), so give it no `id`s. With `wireWorkbench`
209
+ given the panel's `collapsed` signal, focus follows the toggle: closing a
210
+ panel from its own toggle focuses the relocated toggle in the work area, and
211
+ opening it from there focuses the panel's own toggle. A panel's optional
212
+ `footer` renders below its content, for a sidebar's bottom toolbar. Without a
213
+ `toolbar` or `mainToolbar`, `content` and `main` render exactly as given.
214
+
130
215
  ## Resizable panels
131
216
 
132
217
  Resizing is **opt-in per panel**. Give a panel `resizable` — `true` for the
package/llms.txt CHANGED
@@ -187,10 +187,10 @@ the folder modules, and CSS only imports their owner stylesheets.
187
187
  `TokenSearchField`, Web Awesome controls — inside a `ToolbarControlGroup`. For an
188
188
  ordinary icon/action control inside the group use a **plain `<button>`** (the
189
189
  group styles it fully) — that is the default; reach for `wa-button` only when you
190
- need a Web Awesome feature, chiefly the `slot="trigger"` button of a `wa-dropdown`
191
- popup menu. A toolbar popup menu is a `single` `ToolbarControlGroup` around a
192
- `wa-dropdown` (its `slot="trigger"` `wa-button` is the toolbar button, kept under
193
- `data-morph-skip-children`). Let the group size the trigger from its icon,
190
+ need a Web Awesome feature. A toolbar popup menu is a `PopupMenu`
191
+ (`@kerfjs/ui/popup-menu`, registered once via `@kerfjs/ui/popup-menu/register`)
192
+ in a `single` `ToolbarControlGroup` with `nestedDropdown`; never hand-write
193
+ `wa-dropdown` markup for a menu. Let the group size the trigger from its icon,
194
194
  localized text, and caret; do not force a dropdown or button width. Compact
195
195
  mixed groups keep standard item padding and raised selected chrome without an
196
196
  internal separator; the selected item paints over the outer border. For an
@@ -249,7 +249,8 @@ the folder modules, and CSS only imports their owner stylesheets.
249
249
  editor focus before the next input task, so shortcut-letter typing stays in search.
250
250
  Select All deletion does the same; deletion
251
251
  restoration finishes before the next keystroke rather than on a delayed frame.
252
- Persist both query and remaining tokens read from an edited field. The one richer case is `wireTokenSearchFields`, which manages the
252
+ Persist both query and remaining tokens read from an edited field; change
253
+ `revision` to replace its DOM-owned text programmatically. The one richer case is `wireTokenSearchFields`, which manages the
253
254
  collapsible field's expand/collapse/focus by default (on, per-behavior opt-out) and
254
255
  exposes the `expanded` signal on its handle — bind it in render or hand in your own
255
256
  via `collapsible.signals`. Do not hand-roll open/collapse/focus that helper
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kerfjs/ui",
3
- "version": "5.0.0-beta.54",
3
+ "version": "5.0.0-beta.55",
4
4
  "description": "Accessible, composable UI primitives for kerf applications.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -37,7 +37,8 @@
37
37
  "sideEffects": [
38
38
  "**/*.css",
39
39
  "./dist/browser/*.js",
40
- "./dist/select-register.js"
40
+ "./dist/select-register.js",
41
+ "./dist/popup-menu-register.js"
41
42
  ],
42
43
  "exports": {
43
44
  ".": {
@@ -268,6 +269,15 @@
268
269
  "types": "./dist/wire-token-search-fields.d.ts",
269
270
  "import": "./dist/wire-token-search-fields.js"
270
271
  },
272
+ "./popup-menu": {
273
+ "types": "./dist/popup-menu.d.ts",
274
+ "browser": "./dist/browser/popup-menu.js",
275
+ "import": "./dist/popup-menu.js"
276
+ },
277
+ "./popup-menu/register": {
278
+ "types": "./dist/popup-menu-register.d.ts",
279
+ "import": "./dist/popup-menu-register.js"
280
+ },
271
281
  "./select/register": {
272
282
  "types": "./dist/select-register.d.ts",
273
283
  "import": "./dist/select-register.js"
@@ -330,6 +340,7 @@
330
340
  "./tab-scaffold.css": "./dist/styles/tab-scaffold.css",
331
341
  "./loading-spinner.css": "./dist/styles/loading-spinner.css",
332
342
  "./select.css": "./dist/styles/select.css",
343
+ "./popup-menu.css": "./dist/styles/popup-menu.css",
333
344
  "./skeleton.css": "./dist/styles/skeleton.css",
334
345
  "./sunken-panel.css": "./dist/styles/sunken-panel.css",
335
346
  "./segmented-control.css": "./dist/styles/segmented-control.css",