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

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 (418) hide show
  1. package/README.md +74 -41
  2. package/ai/application-ui-diagnostic-ids-v1.json +9 -1
  3. package/ai/application-ui-profile-sync.cjs +1 -1
  4. package/ai/application-ui-profile.defaults.json +63 -8
  5. package/ai/application-ui-profile.mjs +1 -1
  6. package/ai/compile-time-contracts-v1.json +2 -2
  7. package/ai/component-catalog.json +407 -80
  8. package/ai/component-catalog.schema.json +2 -0
  9. package/ai/component-class-owners.cjs +83 -0
  10. package/ai/component-composition-extension.d.ts +7 -0
  11. package/ai/component-composition-extension.schema.json +7 -0
  12. package/ai/{component-catalog-v2-overrides.json → component-composition-rules.json} +2 -1
  13. package/ai/{component-catalog-v2.d.ts → component-composition.d.ts} +9 -5
  14. package/ai/{component-catalog-v2.json → component-composition.json} +302 -61
  15. package/ai/{component-catalog-v2.schema.json → component-composition.schema.json} +21 -5
  16. package/ai/components/README.md +170 -0
  17. package/ai/components/application-tabs.md +65 -0
  18. package/ai/components/badge.md +72 -0
  19. package/ai/components/collapsible-panel.md +102 -0
  20. package/ai/components/content-item.md +90 -0
  21. package/ai/components/disclosure-arrow.md +77 -0
  22. package/ai/components/document-baseline.md +75 -0
  23. package/ai/components/empty-state.md +80 -0
  24. package/ai/components/feedback.md +71 -0
  25. package/ai/components/floating-toolbar.md +80 -0
  26. package/ai/components/foundation.md +65 -0
  27. package/ai/components/grid.md +93 -0
  28. package/ai/components/headers.md +63 -0
  29. package/ai/components/layout.md +75 -0
  30. package/ai/components/list-action-row.md +91 -0
  31. package/ai/components/list-header.md +89 -0
  32. package/ai/components/list-inset-control.md +74 -0
  33. package/ai/components/list-inset-text.md +72 -0
  34. package/ai/components/list-item.md +88 -0
  35. package/ai/components/list.md +103 -0
  36. package/ai/components/loading-spinner.md +72 -0
  37. package/ai/components/lucide-icon.md +66 -0
  38. package/ai/components/nav-stack.md +103 -0
  39. package/ai/components/pane.md +100 -0
  40. package/ai/components/popup-menu.md +82 -0
  41. package/ai/components/recipe-app-shell.md +57 -0
  42. package/ai/components/recipe-collapsible-sidebar.md +57 -0
  43. package/ai/components/recipe-compact-toolbar.md +57 -0
  44. package/ai/components/recipe-composer-form.md +57 -0
  45. package/ai/components/recipe-list-detail-dialog.md +57 -0
  46. package/ai/components/recipe-list-workspace-states.md +57 -0
  47. package/ai/components/recipe-loading-inspector.md +57 -0
  48. package/ai/components/recipe-navigation-sidebar.md +57 -0
  49. package/ai/components/recipe-navigation-stack.md +57 -0
  50. package/ai/components/recipe-workspace-header.md +57 -0
  51. package/ai/components/resize.md +101 -0
  52. package/ai/components/row.md +96 -0
  53. package/ai/components/segmented-control.md +82 -0
  54. package/ai/components/select.md +107 -0
  55. package/ai/components/skeleton.md +84 -0
  56. package/ai/components/spacer.md +86 -0
  57. package/ai/components/split-view.md +102 -0
  58. package/ai/components/state-banner.md +92 -0
  59. package/ai/components/sunken-panel.md +79 -0
  60. package/ai/components/surface-scaffold.md +78 -0
  61. package/ai/components/tab-bar.md +112 -0
  62. package/ai/components/tab-scaffold.md +94 -0
  63. package/ai/components/tabs.md +90 -0
  64. package/ai/components/text.md +82 -0
  65. package/ai/components/token-search-field.md +101 -0
  66. package/ai/components/toolbar-control-group.md +100 -0
  67. package/ai/components/toolbar-text.md +76 -0
  68. package/ai/components/toolbar.md +95 -0
  69. package/ai/components/value-table.md +72 -0
  70. package/ai/components/wa-accordion-item.md +55 -0
  71. package/ai/components/wa-accordion.md +65 -0
  72. package/ai/components/wa-animated-image.md +55 -0
  73. package/ai/components/wa-animation.md +55 -0
  74. package/ai/components/wa-avatar.md +55 -0
  75. package/ai/components/wa-badge.md +55 -0
  76. package/ai/components/wa-breadcrumb-item.md +53 -0
  77. package/ai/components/wa-breadcrumb.md +55 -0
  78. package/ai/components/wa-button-group.md +59 -0
  79. package/ai/components/wa-button.md +55 -0
  80. package/ai/components/wa-callout.md +58 -0
  81. package/ai/components/wa-card.md +59 -0
  82. package/ai/components/wa-carousel-item.md +53 -0
  83. package/ai/components/wa-carousel.md +55 -0
  84. package/ai/components/wa-checkbox-group.md +55 -0
  85. package/ai/components/wa-checkbox.md +55 -0
  86. package/ai/components/wa-color-picker.md +55 -0
  87. package/ai/components/wa-comparison.md +55 -0
  88. package/ai/components/wa-copy-button.md +55 -0
  89. package/ai/components/wa-details.md +61 -0
  90. package/ai/components/wa-dialog.md +59 -0
  91. package/ai/components/wa-divider.md +53 -0
  92. package/ai/components/wa-drawer.md +55 -0
  93. package/ai/components/wa-dropdown-item.md +60 -0
  94. package/ai/components/wa-dropdown.md +60 -0
  95. package/ai/components/wa-format-bytes.md +53 -0
  96. package/ai/components/wa-format-date.md +53 -0
  97. package/ai/components/wa-format-number.md +53 -0
  98. package/ai/components/wa-icon.md +58 -0
  99. package/ai/components/wa-include.md +53 -0
  100. package/ai/components/wa-input.md +59 -0
  101. package/ai/components/wa-intersection-observer.md +53 -0
  102. package/ai/components/wa-known-date.md +53 -0
  103. package/ai/components/wa-markdown.md +53 -0
  104. package/ai/components/wa-mutation-observer.md +53 -0
  105. package/ai/components/wa-number-input.md +55 -0
  106. package/ai/components/wa-option.md +59 -0
  107. package/ai/components/wa-otp-input.md +53 -0
  108. package/ai/components/wa-page.md +53 -0
  109. package/ai/components/wa-pagination.md +55 -0
  110. package/ai/components/wa-popover.md +55 -0
  111. package/ai/components/wa-popup.md +53 -0
  112. package/ai/components/wa-progress-bar.md +53 -0
  113. package/ai/components/wa-progress-ring.md +53 -0
  114. package/ai/components/wa-qr-code.md +53 -0
  115. package/ai/components/wa-radio-group.md +59 -0
  116. package/ai/components/wa-radio.md +55 -0
  117. package/ai/components/wa-random-content.md +53 -0
  118. package/ai/components/wa-rating.md +55 -0
  119. package/ai/components/wa-relative-time.md +53 -0
  120. package/ai/components/wa-resize-observer.md +53 -0
  121. package/ai/components/wa-scroller.md +53 -0
  122. package/ai/components/wa-select.md +63 -0
  123. package/ai/components/wa-skeleton.md +53 -0
  124. package/ai/components/wa-slider.md +55 -0
  125. package/ai/components/wa-spinner.md +58 -0
  126. package/ai/components/wa-split-panel.md +58 -0
  127. package/ai/components/wa-switch.md +53 -0
  128. package/ai/components/wa-tab-group.md +69 -0
  129. package/ai/components/wa-tab-panel.md +60 -0
  130. package/ai/components/wa-tab.md +59 -0
  131. package/ai/components/wa-tag.md +59 -0
  132. package/ai/components/wa-textarea.md +53 -0
  133. package/ai/components/wa-time-input.md +55 -0
  134. package/ai/components/wa-toast-item.md +60 -0
  135. package/ai/components/wa-toast.md +60 -0
  136. package/ai/components/wa-tooltip.md +55 -0
  137. package/ai/components/wa-tree-item.md +55 -0
  138. package/ai/components/wa-tree.md +55 -0
  139. package/ai/components/wa-zoomable-frame.md +55 -0
  140. package/ai/components/workbench.md +114 -0
  141. package/ai/public-api-signatures-v1.md +572 -101
  142. package/ai/skill.md +107 -52
  143. package/ai/webawesome-jsx-signatures-v1.md +8 -2
  144. package/analyzer/component-ownership.d.mts +56 -0
  145. package/analyzer/component-ownership.mjs +184 -0
  146. package/analyzer/index.d.mts +3 -0
  147. package/analyzer/index.mjs +274 -20
  148. package/analyzer/selectors.d.mts +21 -0
  149. package/analyzer/selectors.mjs +212 -0
  150. package/dist/app-tab.js +1 -1
  151. package/dist/badge.d.ts +35 -7
  152. package/dist/badge.js +1 -1
  153. package/dist/browser/catalog.js +25 -0
  154. package/dist/browser/collapsible-panel.js +7 -0
  155. package/dist/browser/content-item.js +3 -0
  156. package/dist/browser/nav-stack.js +8 -0
  157. package/dist/browser/select.js +1 -0
  158. package/dist/browser/split-view.js +10 -0
  159. package/dist/browser/tab-scaffold.js +4 -0
  160. package/dist/browser/workbench.js +10 -0
  161. package/dist/catalog-resources.d.ts +12 -1
  162. package/dist/catalog.d.ts +14 -3
  163. package/dist/catalog.js +53 -43
  164. package/dist/catalog.js.map +1 -1
  165. package/dist/{chunk-WZ2GLEY4.js → chunk-2G2ZJQYK.js} +2 -14
  166. package/dist/chunk-2G2ZJQYK.js.map +1 -0
  167. package/dist/{chunk-R754MHXX.js → chunk-553ASUK6.js} +8 -8
  168. package/dist/chunk-553ASUK6.js.map +1 -0
  169. package/dist/{chunk-D7GWXIAS.js → chunk-5I7QGQVT.js} +1 -1
  170. package/dist/chunk-5I7QGQVT.js.map +1 -0
  171. package/dist/{chunk-RNRUVPJ3.js → chunk-63ZWBGE3.js} +3 -2
  172. package/dist/chunk-63ZWBGE3.js.map +1 -0
  173. package/dist/{chunk-44IG7PFV.js → chunk-6CINWX2E.js} +3 -3
  174. package/dist/{chunk-44IG7PFV.js.map → chunk-6CINWX2E.js.map} +1 -1
  175. package/dist/{chunk-MTM43SJO.js → chunk-6YFHCLHG.js} +2 -2
  176. package/dist/chunk-6YFHCLHG.js.map +1 -0
  177. package/dist/{chunk-C2FAYFDE.js → chunk-AGXQQFKZ.js} +2 -2
  178. package/dist/{chunk-C2FAYFDE.js.map → chunk-AGXQQFKZ.js.map} +1 -1
  179. package/dist/{chunk-ATHXW6RP.js → chunk-AHEG27M7.js} +2 -2
  180. package/dist/{chunk-ATHXW6RP.js.map → chunk-AHEG27M7.js.map} +1 -1
  181. package/dist/chunk-BFPBS5Y4.js +250 -0
  182. package/dist/chunk-BFPBS5Y4.js.map +1 -0
  183. package/dist/{chunk-5OLVUEND.js → chunk-DG6G5EPF.js} +4 -6
  184. package/dist/chunk-DG6G5EPF.js.map +1 -0
  185. package/dist/{chunk-LZXQVUGN.js → chunk-EVYKTVBQ.js} +5 -14
  186. package/dist/chunk-EVYKTVBQ.js.map +1 -0
  187. package/dist/{chunk-7GUQYHKA.js → chunk-EZVNC4J6.js} +7 -1
  188. package/dist/chunk-EZVNC4J6.js.map +1 -0
  189. package/dist/{chunk-RNZAKSME.js → chunk-F4QMLOXJ.js} +5 -4
  190. package/dist/chunk-F4QMLOXJ.js.map +1 -0
  191. package/dist/{chunk-EAX2GSS4.js → chunk-G2RKFVRB.js} +54 -20
  192. package/dist/chunk-G2RKFVRB.js.map +1 -0
  193. package/dist/chunk-JCV4GXWB.js +249 -0
  194. package/dist/chunk-JCV4GXWB.js.map +1 -0
  195. package/dist/chunk-K47P7QZC.js +17 -0
  196. package/dist/chunk-K47P7QZC.js.map +1 -0
  197. package/dist/{chunk-HMQ2ZDGG.js → chunk-KROD7KZK.js} +3 -2
  198. package/dist/chunk-KROD7KZK.js.map +1 -0
  199. package/dist/{chunk-5NDQABWK.js → chunk-M7QV3IHH.js} +3 -1
  200. package/dist/chunk-M7QV3IHH.js.map +1 -0
  201. package/dist/chunk-MA73TA6D.js +42 -0
  202. package/dist/chunk-MA73TA6D.js.map +1 -0
  203. package/dist/{chunk-ZMBU522F.js → chunk-MEY33VWB.js} +2 -2
  204. package/dist/{chunk-ZMBU522F.js.map → chunk-MEY33VWB.js.map} +1 -1
  205. package/dist/chunk-MP2GDBQZ.js +50 -0
  206. package/dist/chunk-MP2GDBQZ.js.map +1 -0
  207. package/dist/{chunk-3NBL3OUQ.js → chunk-NAPE7WUS.js} +2 -2
  208. package/dist/chunk-NAPE7WUS.js.map +1 -0
  209. package/dist/{chunk-BSKEH3UC.js → chunk-NBYTIVHS.js} +2 -2
  210. package/dist/{chunk-BSKEH3UC.js.map → chunk-NBYTIVHS.js.map} +1 -1
  211. package/dist/{chunk-T22EM4ET.js → chunk-OUK6QRDR.js} +71 -31
  212. package/dist/chunk-OUK6QRDR.js.map +1 -0
  213. package/dist/chunk-PWXNJS2B.js +115 -0
  214. package/dist/chunk-PWXNJS2B.js.map +1 -0
  215. package/dist/{chunk-GUIHMIT2.js → chunk-QOWG4ZCL.js} +5 -4
  216. package/dist/chunk-QOWG4ZCL.js.map +1 -0
  217. package/dist/{chunk-5I22LMCV.js → chunk-VZOFZPSO.js} +2 -2
  218. package/dist/chunk-VZOFZPSO.js.map +1 -0
  219. package/dist/{chunk-4BIMLITI.js → chunk-WLG6SSNT.js} +5 -3
  220. package/dist/chunk-WLG6SSNT.js.map +1 -0
  221. package/dist/{chunk-NE5JAOQS.js → chunk-WOUF7YXM.js} +3 -3
  222. package/dist/{chunk-NE5JAOQS.js.map → chunk-WOUF7YXM.js.map} +1 -1
  223. package/dist/{chunk-N7FHFNT6.js → chunk-XCO6YCYM.js} +34 -5
  224. package/dist/chunk-XCO6YCYM.js.map +1 -0
  225. package/dist/{chunk-TZ5IHWB2.js → chunk-XDKAYSVD.js} +5 -3
  226. package/dist/chunk-XDKAYSVD.js.map +1 -0
  227. package/dist/collapsible-panel.d.ts +14 -3
  228. package/dist/collapsible-panel.js +13 -16
  229. package/dist/collapsible-panel.js.map +1 -1
  230. package/dist/content-item.d.ts +46 -0
  231. package/dist/content-item.js +4 -0
  232. package/dist/content-item.js.map +1 -0
  233. package/dist/css-values.d.ts +5 -11
  234. package/dist/css-values.js +1 -1
  235. package/dist/disclosure-arrow.d.ts +4 -1
  236. package/dist/disclosure-arrow.js +1 -1
  237. package/dist/floating-toolbar.d.ts +17 -6
  238. package/dist/floating-toolbar.js +1 -1
  239. package/dist/grid.js +1 -1
  240. package/dist/help-tags-register.d.ts +13 -0
  241. package/dist/help-tags-register.js +9 -0
  242. package/dist/help-tags-register.js.map +1 -0
  243. package/dist/index.d.ts +7 -5
  244. package/dist/index.js +29 -26
  245. package/dist/list-action-row.js +2 -1
  246. package/dist/list-header.d.ts +14 -1
  247. package/dist/list-header.js +1 -1
  248. package/dist/list-inset-control.d.ts +1 -1
  249. package/dist/list-inset-control.js +1 -1
  250. package/dist/list-inset-text.d.ts +3 -10
  251. package/dist/list-inset-text.js +1 -1
  252. package/dist/list-item.js +2 -1
  253. package/dist/list.d.ts +10 -3
  254. package/dist/list.js +1 -1
  255. package/dist/nav-stack.d.ts +50 -5
  256. package/dist/nav-stack.js +4 -1
  257. package/dist/pane.d.ts +37 -2
  258. package/dist/pane.js +1 -1
  259. package/dist/{panel-toolbar-BFQxFITu.d.ts → panel-toolbar-BN4x0rth.d.ts} +13 -1
  260. package/dist/popup-menu-register.js +3 -2
  261. package/dist/popup-menu-register.js.map +1 -1
  262. package/dist/popup-menu.js +1 -1
  263. package/dist/row.d.ts +1 -1
  264. package/dist/row.js +1 -1
  265. package/dist/select-register.js +70 -3
  266. package/dist/select-register.js.map +1 -1
  267. package/dist/select.d.ts +46 -8
  268. package/dist/select.js +2 -1
  269. package/dist/{divider-sides-BzB6rphT.d.ts → sides-BPSWde0A.d.ts} +1 -3
  270. package/dist/skeleton.js +1 -1
  271. package/dist/spacer.js +1 -1
  272. package/dist/split-view.d.ts +31 -3
  273. package/dist/split-view.js +34 -5
  274. package/dist/split-view.js.map +1 -1
  275. package/dist/state-banner.js +1 -1
  276. package/dist/styles/app-tab.css +31 -0
  277. package/dist/styles/badge.css +32 -11
  278. package/dist/styles/catalog/components/catalog-example.css +1 -1
  279. package/dist/styles/catalog/components/catalog-stage.css +1 -1
  280. package/dist/styles/collapsible-panel.css +199 -42
  281. package/dist/styles/content-item.css +30 -0
  282. package/dist/styles/floating-toolbar.css +26 -2
  283. package/dist/styles/foundation.css +28 -19
  284. package/dist/styles/layout.css +1 -21
  285. package/dist/styles/list-action-row.css +13 -1
  286. package/dist/styles/list-header.css +0 -12
  287. package/dist/styles/list-inset-text.css +1 -2
  288. package/dist/styles/list-item.css +14 -1
  289. package/dist/styles/list.css +5 -5
  290. package/dist/styles/nav-stack.css +63 -71
  291. package/dist/styles/pane.css +83 -1
  292. package/dist/styles/popup-menu.css +229 -0
  293. package/dist/styles/resizable-region.css +70 -15
  294. package/dist/styles/select.css +60 -19
  295. package/dist/styles/skeleton.css +30 -3
  296. package/dist/styles/split-view.css +31 -32
  297. package/dist/styles/state-banner.css +0 -19
  298. package/dist/styles/surface-scaffold.css +8 -3
  299. package/dist/styles/tab-bar.css +79 -28
  300. package/dist/styles/tab-scaffold.css +60 -14
  301. package/dist/styles/text.css +17 -1
  302. package/dist/styles/token-search-field.css +4 -4
  303. package/dist/styles/toolbar-control-group.css +143 -69
  304. package/dist/styles/toolbar-text.css +21 -0
  305. package/dist/styles/toolbar.css +22 -37
  306. package/dist/styles/value-table.css +19 -2
  307. package/dist/styles/webawesome.css +3 -1
  308. package/dist/styles/workbench.css +145 -42
  309. package/dist/tab-scaffold.d.ts +46 -2
  310. package/dist/tab-scaffold.js +52 -16
  311. package/dist/tab-scaffold.js.map +1 -1
  312. package/dist/token-search-field.d.ts +4 -2
  313. package/dist/token-search-field.js +1 -1
  314. package/dist/toolbar-text.d.ts +7 -1
  315. package/dist/toolbar-text.js +1 -1
  316. package/dist/toolbar.d.ts +20 -5
  317. package/dist/toolbar.js +1 -1
  318. package/dist/{types-D6vzj-VT.d.ts → types-BuHELdXR.d.ts} +39 -6
  319. package/dist/value-table.js +1 -1
  320. package/dist/webawesome.d.ts +7 -1
  321. package/dist/wire-catalog.d.ts +15 -2
  322. package/dist/wire-catalog.js +12 -2
  323. package/dist/wire-catalog.js.map +1 -1
  324. package/dist/wire-scroll-dividers.d.ts +69 -0
  325. package/dist/wire-scroll-dividers.js +3 -0
  326. package/dist/wire-scroll-dividers.js.map +1 -0
  327. package/dist/wire-token-search-fields.js +1 -1
  328. package/dist/workbench.d.ts +60 -22
  329. package/dist/workbench.js +1 -1
  330. package/docs/accessibility.md +116 -7
  331. package/docs/app-layouts.md +18 -8
  332. package/docs/catalog.md +26 -7
  333. package/docs/collapsible-panel.md +32 -9
  334. package/docs/component-contract.md +182 -30
  335. package/docs/component-selection.md +59 -46
  336. package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
  337. package/docs/design/templates/empty-state/with-action.svg +1 -1
  338. package/docs/design/templates/empty-state-dark.svg +1 -1
  339. package/docs/design/templates/empty-state.svg +1 -1
  340. package/docs/design/templates/list/compact-dark.svg +1 -1
  341. package/docs/design/templates/list/compact.svg +1 -1
  342. package/docs/design/templates/list/stack-dark.svg +1 -1
  343. package/docs/design/templates/list/stack.svg +1 -1
  344. package/docs/design/templates/list-action-row/default-dark.svg +1 -1
  345. package/docs/design/templates/list-action-row/default.svg +1 -1
  346. package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
  347. package/docs/design/templates/list-action-row/selected.svg +1 -1
  348. package/docs/design/templates/list-action-row-dark.svg +1 -1
  349. package/docs/design/templates/list-action-row.svg +1 -1
  350. package/docs/design/templates/list-dark.svg +1 -1
  351. package/docs/design/templates/list-item/default-dark.svg +1 -1
  352. package/docs/design/templates/list-item/default.svg +1 -1
  353. package/docs/design/templates/list-item/selected-dark.svg +1 -1
  354. package/docs/design/templates/list-item/selected.svg +1 -1
  355. package/docs/design/templates/list-item/trailing-dark.svg +1 -1
  356. package/docs/design/templates/list-item/trailing.svg +1 -1
  357. package/docs/design/templates/list-item-dark.svg +1 -1
  358. package/docs/design/templates/list-item.svg +1 -1
  359. package/docs/design/templates/list.svg +1 -1
  360. package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -1
  361. package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -1
  362. package/docs/design/templates/tab-bar-dark.svg +1 -1
  363. package/docs/design/templates/tab-bar.svg +1 -1
  364. package/docs/design/templates/value-table/details-dark.svg +1 -1
  365. package/docs/design/templates/value-table/details.svg +1 -1
  366. package/docs/design/templates/value-table-dark.svg +1 -1
  367. package/docs/design/templates/value-table.svg +1 -1
  368. package/docs/design-philosophy.md +31 -4
  369. package/docs/examples/application-ui-profile.json +4 -4
  370. package/docs/examples/command-palette-adapter.tsx +3 -2
  371. package/docs/examples/{component-catalog-extension-v2.json → component-composition-extension.json} +3 -3
  372. package/docs/layout.md +148 -29
  373. package/docs/nav-stack.md +77 -3
  374. package/docs/recipes.md +4 -3
  375. package/docs/split-view.md +54 -5
  376. package/docs/tab-scaffold.md +73 -2
  377. package/docs/type-contracts.md +21 -20
  378. package/docs/ui-analyzer.md +99 -5
  379. package/docs/ui-doctor.md +10 -0
  380. package/docs/ux-demo.md +2 -2
  381. package/docs/webawesome-theme.md +1 -2
  382. package/docs/workbench.md +57 -11
  383. package/doctor/index.mjs +6 -1
  384. package/llms.txt +117 -24
  385. package/package.json +29 -6
  386. package/ux-demo/recipes/collapsible-sidebar.tsx +3 -3
  387. package/ux-demo/recipes/composer-form.tsx +0 -1
  388. package/ux-demo/recipes/list-detail-dialog.tsx +0 -2
  389. package/ux-demo/recipes/list-workspace-states.tsx +0 -1
  390. package/ux-demo/recipes/loading-inspector.tsx +0 -1
  391. package/ux-demo/recipes/navigation-sidebar.tsx +3 -2
  392. package/ux-demo/recipes/navigation-stack.tsx +3 -2
  393. package/ux-demo/recipes/workspace-header.tsx +0 -1
  394. package/ai/component-catalog-extension-v2.d.ts +0 -7
  395. package/ai/component-catalog-extension-v2.schema.json +0 -7
  396. package/dist/chunk-3NBL3OUQ.js.map +0 -1
  397. package/dist/chunk-4BIMLITI.js.map +0 -1
  398. package/dist/chunk-5I22LMCV.js.map +0 -1
  399. package/dist/chunk-5NDQABWK.js.map +0 -1
  400. package/dist/chunk-5OLVUEND.js.map +0 -1
  401. package/dist/chunk-7GUQYHKA.js.map +0 -1
  402. package/dist/chunk-D7GWXIAS.js.map +0 -1
  403. package/dist/chunk-DQA5FMOX.js +0 -85
  404. package/dist/chunk-DQA5FMOX.js.map +0 -1
  405. package/dist/chunk-EAX2GSS4.js.map +0 -1
  406. package/dist/chunk-GUIHMIT2.js.map +0 -1
  407. package/dist/chunk-HMQ2ZDGG.js.map +0 -1
  408. package/dist/chunk-LZXQVUGN.js.map +0 -1
  409. package/dist/chunk-MTM43SJO.js.map +0 -1
  410. package/dist/chunk-N7FHFNT6.js.map +0 -1
  411. package/dist/chunk-R754MHXX.js.map +0 -1
  412. package/dist/chunk-RNRUVPJ3.js.map +0 -1
  413. package/dist/chunk-RNZAKSME.js.map +0 -1
  414. package/dist/chunk-T22EM4ET.js.map +0 -1
  415. package/dist/chunk-TZ5IHWB2.js.map +0 -1
  416. package/dist/chunk-WZ2GLEY4.js.map +0 -1
  417. package/dist/chunk-XD7DWYXG.js +0 -34
  418. package/dist/chunk-XD7DWYXG.js.map +0 -1
@@ -1,4 +1,4 @@
1
- export { ValueTable, ValueTableRow } from './chunk-44IG7PFV.js';
1
+ export { ValueTable, ValueTableRow } from './chunk-6CINWX2E.js';
2
2
 
3
3
 
4
4
 
@@ -25,6 +25,9 @@ declare module 'kerfjs/jsx-runtime' {
25
25
  placeholder?: string;
26
26
  hint?: string;
27
27
  disabled?: boolean;
28
+ size?: 'xs' | 's' | 'm' | 'l' | 'xl';
29
+ appearance?: 'filled' | 'outlined' | 'filled-outlined';
30
+ placement?: 'top' | 'bottom';
28
31
  };
29
32
  'wa-option': KerfCustomElement & {
30
33
  value?: string;
@@ -40,7 +43,9 @@ declare module 'kerfjs/jsx-runtime' {
40
43
  'wa-comparison': KerfCustomElement;
41
44
  'wa-copy-button': KerfCustomElement;
42
45
  'wa-details': KerfCustomElement;
43
- 'wa-divider': KerfCustomElement;
46
+ 'wa-divider': KerfCustomElement & {
47
+ orientation?: 'horizontal' | 'vertical';
48
+ };
44
49
  'wa-dialog': KerfCustomElement;
45
50
  'wa-drawer': KerfCustomElement;
46
51
  'wa-button': KerfCustomElement & {
@@ -51,6 +56,7 @@ declare module 'kerfjs/jsx-runtime' {
51
56
  };
52
57
  'wa-dropdown': KerfCustomElement & {
53
58
  placement?: string;
59
+ size?: 'xs' | 's' | 'm' | 'l' | 'xl';
54
60
  };
55
61
  'wa-dropdown-item': KerfCustomElement;
56
62
  'wa-format-bytes': KerfCustomElement;
@@ -28,6 +28,17 @@ interface WireCatalogOptions {
28
28
  * open overlay closes it.
29
29
  */
30
30
  collapsed?: Signal<boolean>;
31
+ /**
32
+ * The app-owned sidebar width signal for a Catalog rendered with
33
+ * `sidebar={{ resizable: true, size: sidebarSize.value }}`. Each committed
34
+ * drag or keyboard resize is written to it.
35
+ */
36
+ sidebarSize?: Signal<number>;
37
+ /**
38
+ * With `sidebarSize`, load and save the width under this storage key so the
39
+ * catalog remembers the user's sidebar width.
40
+ */
41
+ sidebarStorageKey?: string;
31
42
  /** The Catalog's `id`, when it is not the default `kui-catalog`. */
32
43
  id?: string;
33
44
  }
@@ -62,8 +73,10 @@ declare function wireCatalogGeometryOverlay(root: HTMLElement): () => void;
62
73
  * item selection (and the related-entry popup menu), the sidebar collapse toggle, and
63
74
  * the theme toggle. The app owns the `active`/`collapsed`/`theme` signals and updates
64
75
  * them in the callbacks; optionally mirror the active id into the URL via `urlParam`.
65
- * Returns a disposer.
76
+ * It also wires the scroll dividers below root (`wireScrollDividers`), so the
77
+ * catalog's panes and every example in it show their chrome dividers only
78
+ * while scrolled. Returns a disposer.
66
79
  */
67
- declare function wireCatalog(root: HTMLElement, { onSelect, onToggleSidebar, onToggleTheme, onToggleSecondary, urlParam, revealSelection, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, collapsed, id: catalogId, }: WireCatalogOptions): () => void;
80
+ declare function wireCatalog(root: HTMLElement, { onSelect, onToggleSidebar, onToggleTheme, onToggleSecondary, urlParam, revealSelection, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, collapsed, sidebarSize, sidebarStorageKey, id: catalogId, }: WireCatalogOptions): () => void;
68
81
 
69
82
  export { type CatalogRevealOptions, type WireCatalogOptions, revealCatalogEntry, wireCatalog, wireCatalogGeometryOverlay };
@@ -1,4 +1,5 @@
1
1
  import { wireWorkbench } from './chunk-KH6VUGHU.js';
2
+ import { wireScrollDividers } from './chunk-JCV4GXWB.js';
2
3
 
3
4
 
4
5
 
@@ -233,6 +234,8 @@ function wireCatalog(root, {
233
234
  toggleThemeAction = "catalog-toggle-theme",
234
235
  toggleSecondaryAction = "catalog-toggle-secondary",
235
236
  collapsed,
237
+ sidebarSize,
238
+ sidebarStorageKey,
236
239
  id: catalogId = "kui-catalog"
237
240
  }) {
238
241
  let cancelReveal;
@@ -257,6 +260,7 @@ function wireCatalog(root, {
257
260
  }
258
261
  };
259
262
  const disposers = [
263
+ wireScrollDividers(root),
260
264
  // Sidebar items AND the footer's related-entry popup-menu items both carry
261
265
  // `data-action={selectAction}` + `data-item-id`, so one delegated click covers both.
262
266
  delegate(
@@ -299,11 +303,17 @@ function wireCatalog(root, {
299
303
  )
300
304
  );
301
305
  }
302
- if (collapsed)
306
+ if (collapsed || sidebarSize)
303
307
  disposers.push(
304
308
  wireWorkbench(root, {
305
309
  id: catalogId,
306
- panels: { leftRail: { collapsed } }
310
+ panels: {
311
+ leftRail: {
312
+ collapsed,
313
+ size: sidebarSize,
314
+ storageKey: sidebarStorageKey
315
+ }
316
+ }
307
317
  })
308
318
  );
309
319
  return () => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/wire-catalog.ts"],"names":[],"mappings":"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","file":"wire-catalog.js","sourcesContent":["import { delegate, type Signal } from 'kerfjs';\n\nimport { wireWorkbench } from './wire-workbench.js';\n\nexport interface WireCatalogOptions {\n /** Invoked with the entry id when a sidebar item or a related-entry option is chosen. */\n onSelect: (id: string) => void;\n /** Invoked when the sidebar collapse/expand control is activated. */\n onToggleSidebar?: () => void;\n /** Invoked when the theme toggle is activated. */\n onToggleTheme?: () => void;\n /** Invoked when the secondary (ecosystem) group's disclosure toggle is activated. */\n onToggleSecondary?: () => void;\n /** When set, `?<urlParam>=<id>` is written on select via `history.replaceState`. */\n urlParam?: string;\n /**\n * Reveal the chosen sidebar row after selection. `true` uses desktop-safe\n * defaults; pass options to customize scroll alignment or the media guard.\n */\n revealSelection?: boolean | CatalogRevealOptions;\n selectAction?: string;\n toggleSidebarAction?: string;\n toggleThemeAction?: string;\n toggleSecondaryAction?: string;\n /**\n * The sidebar's app-owned collapsed flag. With it, the catalog's Workbench\n * sidebar is wired like any Workbench rail: it becomes a transient overlay\n * on a small screen (collapsed as the breakpoint applies, closed on Escape\n * or a press outside, focus handed back), and choosing an entry from the\n * open overlay closes it.\n */\n collapsed?: Signal<boolean>;\n /** The Catalog's `id`, when it is not the default `kui-catalog`. */\n id?: string;\n}\n\nexport interface CatalogRevealOptions {\n /** Scroll alignment within the sidebar. Default `'nearest'`. */\n block?: ScrollLogicalPosition;\n /** Cross-axis alignment. Default `'nearest'`. */\n inline?: ScrollLogicalPosition;\n /** Scroll behavior. Default `'auto'`. */\n behavior?: ScrollBehavior;\n /**\n * Only reveal when this media query matches. Defaults to the Catalog's\n * desktop layout; pass `false` to reveal at every viewport size.\n */\n media?: string | false;\n}\n\n// The Workbench keeps the sidebar inline above its `narrow` breakpoint (704px).\nconst catalogDesktopMedia = '(min-width: 44.01rem)';\n\n/**\n * Reveal one Catalog sidebar entry after the controlled render settles without\n * moving focus. Returns a cancellation function for rapid selection changes.\n */\nexport function revealCatalogEntry(\n root: HTMLElement,\n id: string,\n {\n block = 'nearest',\n inline = 'nearest',\n behavior = 'auto',\n media = catalogDesktopMedia,\n }: CatalogRevealOptions = {},\n): () => void {\n const view = root.ownerDocument.defaultView;\n if (!view || (media && !view.matchMedia(media).matches)) return () => {};\n const frame = view.requestAnimationFrame(() => {\n for (const item of root.querySelectorAll<HTMLElement>('[data-item-id]')) {\n if (item.dataset.itemId !== id) continue;\n item.scrollIntoView({ block, inline, behavior });\n break;\n }\n });\n return () => view.cancelAnimationFrame(frame);\n}\n\nfunction pixels(value: string): number {\n const number = Number.parseFloat(value);\n if (!Number.isFinite(number)) return 0;\n return value.trim().endsWith('rem') ? number * 16 : number;\n}\n\nfunction isTransparent(color: string): boolean {\n const normalized = color.replace(/\\s+/g, '');\n return (\n normalized === 'transparent' || /(?:,|\\/)0(?:\\.0+)?\\)$/.test(normalized)\n );\n}\n\nfunction geometrySpecimens(canvas: HTMLElement): Element[] {\n const result: Element[] = [];\n for (const example of canvas.querySelectorAll<HTMLElement>(\n '[data-catalog-example]',\n )) {\n if (example.closest('[data-catalog-geometry-overlay-skip]')) continue;\n for (const child of example.children) {\n if (\n child.matches('[data-catalog-geometry-overlay]') ||\n child.matches('[data-catalog-example-label]') ||\n child.matches('[data-catalog-example-note]')\n )\n continue;\n result.push(child);\n }\n }\n for (const element of canvas.querySelectorAll<HTMLElement>(\n '[data-component]',\n )) {\n if (\n element.closest('[data-catalog-geometry-overlay]') ||\n element.closest('[data-catalog-geometry-overlay-skip]') ||\n element.closest('.kui-catalog-example')\n )\n continue;\n const parent =\n element.parentElement?.closest<HTMLElement>('[data-component]');\n if (parent && canvas.contains(parent)) continue;\n result.push(element);\n }\n return result;\n}\n\nfunction geometryBox(\n document: Document,\n className: string,\n left: number,\n top: number,\n width: number,\n height: number,\n): HTMLElement {\n const element = document.createElement('div');\n element.className = className;\n element.style.transform = `translate(${left}px, ${top}px)`;\n element.style.width = `${Math.max(0, width)}px`;\n element.style.height = `${Math.max(0, height)}px`;\n return element;\n}\n\nfunction effectiveBorderWidth(width: string, style: string): number {\n return style === 'none' || style === 'hidden' ? 0 : pixels(width);\n}\n\n/**\n * Keep a Catalog's opt-in geometry overlay synchronized with its preview.\n * Specimens receive computed border highlights (or a dashed bound when they\n * have no border and are transparent), while positive computed margins use\n * devtools-style orange bands. CSS/stylesheet-only changes are observed too.\n * Returns a disposer.\n */\nexport function wireCatalogGeometryOverlay(root: HTMLElement): () => void {\n const catalog = root.matches('[data-component=\"catalog\"]')\n ? root\n : root.querySelector<HTMLElement>('[data-component=\"catalog\"]');\n const canvas = catalog?.querySelector<HTMLElement>('.kui-catalog__canvas');\n const layer = catalog?.querySelector<HTMLElement>(\n '[data-catalog-geometry-overlay]',\n );\n const view = root.ownerDocument.defaultView;\n if (!catalog || !canvas || !layer || !view) return () => {};\n\n let frame = 0;\n const render = (): void => {\n frame = 0;\n layer.replaceChildren();\n if (catalog.dataset.geometryOverlay !== 'true') {\n syncObservedSpecimens([]);\n return;\n }\n const base = canvas.getBoundingClientRect();\n const specimens = geometrySpecimens(canvas);\n syncObservedSpecimens(specimens);\n for (const [specimenIndex, element] of specimens.entries()) {\n const rect = element.getBoundingClientRect();\n const style = view.getComputedStyle(element);\n const align = pixels(\n style.getPropertyValue('--kui-catalog-example-align'),\n );\n const top = pixels(style.marginTop);\n const right = Math.max(\n 0,\n pixels(style.marginRight) - (style.direction === 'rtl' ? align : 0),\n );\n const bottom = pixels(style.marginBottom);\n const left = Math.max(\n 0,\n pixels(style.marginLeft) - (style.direction === 'rtl' ? 0 : align),\n );\n const x = rect.left - base.left + canvas.scrollLeft;\n const y = rect.top - base.top + canvas.scrollTop;\n const borderWidths = [\n effectiveBorderWidth(style.borderTopWidth, style.borderTopStyle),\n effectiveBorderWidth(style.borderRightWidth, style.borderRightStyle),\n effectiveBorderWidth(style.borderBottomWidth, style.borderBottomStyle),\n effectiveBorderWidth(style.borderLeftWidth, style.borderLeftStyle),\n ];\n if (borderWidths.some((width) => width > 0)) {\n const border = geometryBox(\n root.ownerDocument,\n 'kui-catalog__geometry-border',\n x,\n y,\n rect.width,\n rect.height,\n );\n border.dataset.catalogGeometrySpecimen = String(specimenIndex);\n border.style.borderTopWidth = `${borderWidths[0]}px`;\n border.style.borderRightWidth = `${borderWidths[1]}px`;\n border.style.borderBottomWidth = `${borderWidths[2]}px`;\n border.style.borderLeftWidth = `${borderWidths[3]}px`;\n border.style.borderRadius = style.borderRadius;\n layer.append(border);\n } else if (isTransparent(style.backgroundColor)) {\n const bound = geometryBox(\n root.ownerDocument,\n 'kui-catalog__geometry-bound',\n x,\n y,\n rect.width,\n rect.height,\n );\n bound.dataset.catalogGeometrySpecimen = String(specimenIndex);\n layer.append(bound);\n }\n const margins: Array<\n readonly [string, number, number, number, number, number]\n > = [\n ['top', top, x - left, y - top, rect.width + left + right, top],\n [\n 'bottom',\n bottom,\n x - left,\n y + rect.height,\n rect.width + left + right,\n bottom,\n ],\n ['left', left, x - left, y, left, rect.height],\n ['right', right, x + rect.width, y, right, rect.height],\n ];\n for (const [side, size, marginX, marginY, width, height] of margins) {\n if (size <= 0) continue;\n const margin = geometryBox(\n root.ownerDocument,\n 'kui-catalog__geometry-margin',\n marginX,\n marginY,\n width,\n height,\n );\n margin.dataset.catalogGeometrySpecimen = String(specimenIndex);\n margin.dataset.catalogGeometrySide = side;\n layer.append(margin);\n }\n }\n };\n const schedule = (): void => {\n if (!frame) frame = view.requestAnimationFrame(render);\n };\n const resizeObserver = new view.ResizeObserver(schedule);\n resizeObserver.observe(canvas);\n const observedSpecimens = new Set<Element>();\n const syncObservedSpecimens = (specimens: Element[]): void => {\n const next = new Set(specimens);\n for (const specimen of observedSpecimens) {\n if (next.has(specimen)) continue;\n resizeObserver.unobserve(specimen);\n observedSpecimens.delete(specimen);\n }\n for (const specimen of next) {\n if (observedSpecimens.has(specimen)) continue;\n resizeObserver.observe(specimen);\n observedSpecimens.add(specimen);\n }\n };\n const mutationObserver = new view.MutationObserver((records) => {\n if (\n records.some(\n ({ target }) => target !== layer && !layer.contains(target as Node),\n )\n )\n schedule();\n });\n mutationObserver.observe(catalog, {\n attributes: true,\n childList: true,\n subtree: true,\n });\n mutationObserver.observe(root.ownerDocument.documentElement, {\n attributes: true,\n });\n const documentHead = root.ownerDocument.head;\n if (documentHead)\n mutationObserver.observe(documentHead, {\n attributes: true,\n characterData: true,\n childList: true,\n subtree: true,\n });\n const stylesheetLoaded = (): void => schedule();\n documentHead?.addEventListener('load', stylesheetLoaded, true);\n view.addEventListener('resize', schedule);\n render();\n return () => {\n if (frame) view.cancelAnimationFrame(frame);\n resizeObserver.disconnect();\n mutationObserver.disconnect();\n documentHead?.removeEventListener('load', stylesheetLoaded, true);\n view.removeEventListener('resize', schedule);\n layer.replaceChildren();\n };\n}\n\n/**\n * Wire a {@link Catalog}'s interactions with one delegated listener set: sidebar\n * item selection (and the related-entry popup menu), the sidebar collapse toggle, and\n * the theme toggle. The app owns the `active`/`collapsed`/`theme` signals and updates\n * them in the callbacks; optionally mirror the active id into the URL via `urlParam`.\n * Returns a disposer.\n */\nexport function wireCatalog(\n root: HTMLElement,\n {\n onSelect,\n onToggleSidebar,\n onToggleTheme,\n onToggleSecondary,\n urlParam,\n revealSelection,\n selectAction = 'catalog-select',\n toggleSidebarAction = 'catalog-toggle-sidebar',\n toggleThemeAction = 'catalog-toggle-theme',\n toggleSecondaryAction = 'catalog-toggle-secondary',\n collapsed,\n id: catalogId = 'kui-catalog',\n }: WireCatalogOptions,\n): () => void {\n let cancelReveal: (() => void) | undefined;\n const select = (id: string) => {\n onSelect(id);\n const view = root.ownerDocument.defaultView;\n if (urlParam && view) {\n const url = new URL(view.location.href);\n url.searchParams.set(urlParam, id);\n view.history.replaceState(null, '', url);\n }\n // An open overlay sidebar gives way to the entry just chosen from it.\n const rail = root.ownerDocument.getElementById(`${catalogId}-left-rail`);\n if (\n collapsed &&\n !collapsed.peek() &&\n rail &&\n root.ownerDocument.defaultView?.getComputedStyle(rail).position ===\n 'absolute'\n )\n collapsed.value = true;\n if (revealSelection) {\n cancelReveal?.();\n cancelReveal = revealCatalogEntry(\n root,\n id,\n revealSelection === true ? undefined : revealSelection,\n );\n }\n };\n\n const disposers: Array<() => void> = [\n // Sidebar items AND the footer's related-entry popup-menu items both carry\n // `data-action={selectAction}` + `data-item-id`, so one delegated click covers both.\n delegate(\n root,\n 'click',\n `[data-action=\"${selectAction}\"]`,\n (_event, element) => {\n const id = (element as HTMLElement).dataset.itemId;\n if (id) select(id);\n },\n ),\n ];\n if (onToggleSidebar) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleSidebarAction}\"]`, () =>\n onToggleSidebar(),\n ),\n );\n }\n if (onToggleTheme) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleThemeAction}\"]`, () =>\n onToggleTheme(),\n ),\n );\n }\n if (onToggleSecondary) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleSecondaryAction}\"]`, () =>\n onToggleSecondary(),\n ),\n );\n }\n if (collapsed)\n disposers.push(\n wireWorkbench(root, {\n id: catalogId,\n panels: { leftRail: { collapsed } },\n }),\n );\n return () => {\n cancelReveal?.();\n for (const dispose of disposers.splice(0)) dispose();\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/wire-catalog.ts"],"names":[],"mappings":"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","file":"wire-catalog.js","sourcesContent":["import { delegate, type Signal } from 'kerfjs';\n\nimport { wireScrollDividers } from './wire-scroll-dividers.js';\nimport { wireWorkbench } from './wire-workbench.js';\n\nexport interface WireCatalogOptions {\n /** Invoked with the entry id when a sidebar item or a related-entry option is chosen. */\n onSelect: (id: string) => void;\n /** Invoked when the sidebar collapse/expand control is activated. */\n onToggleSidebar?: () => void;\n /** Invoked when the theme toggle is activated. */\n onToggleTheme?: () => void;\n /** Invoked when the secondary (ecosystem) group's disclosure toggle is activated. */\n onToggleSecondary?: () => void;\n /** When set, `?<urlParam>=<id>` is written on select via `history.replaceState`. */\n urlParam?: string;\n /**\n * Reveal the chosen sidebar row after selection. `true` uses desktop-safe\n * defaults; pass options to customize scroll alignment or the media guard.\n */\n revealSelection?: boolean | CatalogRevealOptions;\n selectAction?: string;\n toggleSidebarAction?: string;\n toggleThemeAction?: string;\n toggleSecondaryAction?: string;\n /**\n * The sidebar's app-owned collapsed flag. With it, the catalog's Workbench\n * sidebar is wired like any Workbench rail: it becomes a transient overlay\n * on a small screen (collapsed as the breakpoint applies, closed on Escape\n * or a press outside, focus handed back), and choosing an entry from the\n * open overlay closes it.\n */\n collapsed?: Signal<boolean>;\n /**\n * The app-owned sidebar width signal for a Catalog rendered with\n * `sidebar={{ resizable: true, size: sidebarSize.value }}`. Each committed\n * drag or keyboard resize is written to it.\n */\n sidebarSize?: Signal<number>;\n /**\n * With `sidebarSize`, load and save the width under this storage key so the\n * catalog remembers the user's sidebar width.\n */\n sidebarStorageKey?: string;\n /** The Catalog's `id`, when it is not the default `kui-catalog`. */\n id?: string;\n}\n\nexport interface CatalogRevealOptions {\n /** Scroll alignment within the sidebar. Default `'nearest'`. */\n block?: ScrollLogicalPosition;\n /** Cross-axis alignment. Default `'nearest'`. */\n inline?: ScrollLogicalPosition;\n /** Scroll behavior. Default `'auto'`. */\n behavior?: ScrollBehavior;\n /**\n * Only reveal when this media query matches. Defaults to the Catalog's\n * desktop layout; pass `false` to reveal at every viewport size.\n */\n media?: string | false;\n}\n\n// The Workbench keeps the sidebar inline above its `narrow` breakpoint (704px).\nconst catalogDesktopMedia = '(min-width: 44.01rem)';\n\n/**\n * Reveal one Catalog sidebar entry after the controlled render settles without\n * moving focus. Returns a cancellation function for rapid selection changes.\n */\nexport function revealCatalogEntry(\n root: HTMLElement,\n id: string,\n {\n block = 'nearest',\n inline = 'nearest',\n behavior = 'auto',\n media = catalogDesktopMedia,\n }: CatalogRevealOptions = {},\n): () => void {\n const view = root.ownerDocument.defaultView;\n if (!view || (media && !view.matchMedia(media).matches)) return () => {};\n const frame = view.requestAnimationFrame(() => {\n for (const item of root.querySelectorAll<HTMLElement>('[data-item-id]')) {\n if (item.dataset.itemId !== id) continue;\n item.scrollIntoView({ block, inline, behavior });\n break;\n }\n });\n return () => view.cancelAnimationFrame(frame);\n}\n\nfunction pixels(value: string): number {\n const number = Number.parseFloat(value);\n if (!Number.isFinite(number)) return 0;\n return value.trim().endsWith('rem') ? number * 16 : number;\n}\n\nfunction isTransparent(color: string): boolean {\n const normalized = color.replace(/\\s+/g, '');\n return (\n normalized === 'transparent' || /(?:,|\\/)0(?:\\.0+)?\\)$/.test(normalized)\n );\n}\n\nfunction geometrySpecimens(canvas: HTMLElement): Element[] {\n const result: Element[] = [];\n for (const example of canvas.querySelectorAll<HTMLElement>(\n '[data-catalog-example]',\n )) {\n if (example.closest('[data-catalog-geometry-overlay-skip]')) continue;\n for (const child of example.children) {\n if (\n child.matches('[data-catalog-geometry-overlay]') ||\n child.matches('[data-catalog-example-label]') ||\n child.matches('[data-catalog-example-note]')\n )\n continue;\n result.push(child);\n }\n }\n for (const element of canvas.querySelectorAll<HTMLElement>(\n '[data-component]',\n )) {\n if (\n element.closest('[data-catalog-geometry-overlay]') ||\n element.closest('[data-catalog-geometry-overlay-skip]') ||\n element.closest('.kui-catalog-example')\n )\n continue;\n const parent =\n element.parentElement?.closest<HTMLElement>('[data-component]');\n if (parent && canvas.contains(parent)) continue;\n result.push(element);\n }\n return result;\n}\n\nfunction geometryBox(\n document: Document,\n className: string,\n left: number,\n top: number,\n width: number,\n height: number,\n): HTMLElement {\n const element = document.createElement('div');\n element.className = className;\n element.style.transform = `translate(${left}px, ${top}px)`;\n element.style.width = `${Math.max(0, width)}px`;\n element.style.height = `${Math.max(0, height)}px`;\n return element;\n}\n\nfunction effectiveBorderWidth(width: string, style: string): number {\n return style === 'none' || style === 'hidden' ? 0 : pixels(width);\n}\n\n/**\n * Keep a Catalog's opt-in geometry overlay synchronized with its preview.\n * Specimens receive computed border highlights (or a dashed bound when they\n * have no border and are transparent), while positive computed margins use\n * devtools-style orange bands. CSS/stylesheet-only changes are observed too.\n * Returns a disposer.\n */\nexport function wireCatalogGeometryOverlay(root: HTMLElement): () => void {\n const catalog = root.matches('[data-component=\"catalog\"]')\n ? root\n : root.querySelector<HTMLElement>('[data-component=\"catalog\"]');\n const canvas = catalog?.querySelector<HTMLElement>('.kui-catalog__canvas');\n const layer = catalog?.querySelector<HTMLElement>(\n '[data-catalog-geometry-overlay]',\n );\n const view = root.ownerDocument.defaultView;\n if (!catalog || !canvas || !layer || !view) return () => {};\n\n let frame = 0;\n const render = (): void => {\n frame = 0;\n layer.replaceChildren();\n if (catalog.dataset.geometryOverlay !== 'true') {\n syncObservedSpecimens([]);\n return;\n }\n const base = canvas.getBoundingClientRect();\n const specimens = geometrySpecimens(canvas);\n syncObservedSpecimens(specimens);\n for (const [specimenIndex, element] of specimens.entries()) {\n const rect = element.getBoundingClientRect();\n const style = view.getComputedStyle(element);\n const align = pixels(\n style.getPropertyValue('--kui-catalog-example-align'),\n );\n const top = pixels(style.marginTop);\n const right = Math.max(\n 0,\n pixels(style.marginRight) - (style.direction === 'rtl' ? align : 0),\n );\n const bottom = pixels(style.marginBottom);\n const left = Math.max(\n 0,\n pixels(style.marginLeft) - (style.direction === 'rtl' ? 0 : align),\n );\n const x = rect.left - base.left + canvas.scrollLeft;\n const y = rect.top - base.top + canvas.scrollTop;\n const borderWidths = [\n effectiveBorderWidth(style.borderTopWidth, style.borderTopStyle),\n effectiveBorderWidth(style.borderRightWidth, style.borderRightStyle),\n effectiveBorderWidth(style.borderBottomWidth, style.borderBottomStyle),\n effectiveBorderWidth(style.borderLeftWidth, style.borderLeftStyle),\n ];\n if (borderWidths.some((width) => width > 0)) {\n const border = geometryBox(\n root.ownerDocument,\n 'kui-catalog__geometry-border',\n x,\n y,\n rect.width,\n rect.height,\n );\n border.dataset.catalogGeometrySpecimen = String(specimenIndex);\n border.style.borderTopWidth = `${borderWidths[0]}px`;\n border.style.borderRightWidth = `${borderWidths[1]}px`;\n border.style.borderBottomWidth = `${borderWidths[2]}px`;\n border.style.borderLeftWidth = `${borderWidths[3]}px`;\n border.style.borderRadius = style.borderRadius;\n layer.append(border);\n } else if (isTransparent(style.backgroundColor)) {\n const bound = geometryBox(\n root.ownerDocument,\n 'kui-catalog__geometry-bound',\n x,\n y,\n rect.width,\n rect.height,\n );\n bound.dataset.catalogGeometrySpecimen = String(specimenIndex);\n layer.append(bound);\n }\n const margins: Array<\n readonly [string, number, number, number, number, number]\n > = [\n ['top', top, x - left, y - top, rect.width + left + right, top],\n [\n 'bottom',\n bottom,\n x - left,\n y + rect.height,\n rect.width + left + right,\n bottom,\n ],\n ['left', left, x - left, y, left, rect.height],\n ['right', right, x + rect.width, y, right, rect.height],\n ];\n for (const [side, size, marginX, marginY, width, height] of margins) {\n if (size <= 0) continue;\n const margin = geometryBox(\n root.ownerDocument,\n 'kui-catalog__geometry-margin',\n marginX,\n marginY,\n width,\n height,\n );\n margin.dataset.catalogGeometrySpecimen = String(specimenIndex);\n margin.dataset.catalogGeometrySide = side;\n layer.append(margin);\n }\n }\n };\n const schedule = (): void => {\n if (!frame) frame = view.requestAnimationFrame(render);\n };\n const resizeObserver = new view.ResizeObserver(schedule);\n resizeObserver.observe(canvas);\n const observedSpecimens = new Set<Element>();\n const syncObservedSpecimens = (specimens: Element[]): void => {\n const next = new Set(specimens);\n for (const specimen of observedSpecimens) {\n if (next.has(specimen)) continue;\n resizeObserver.unobserve(specimen);\n observedSpecimens.delete(specimen);\n }\n for (const specimen of next) {\n if (observedSpecimens.has(specimen)) continue;\n resizeObserver.observe(specimen);\n observedSpecimens.add(specimen);\n }\n };\n const mutationObserver = new view.MutationObserver((records) => {\n if (\n records.some(\n ({ target }) => target !== layer && !layer.contains(target as Node),\n )\n )\n schedule();\n });\n mutationObserver.observe(catalog, {\n attributes: true,\n childList: true,\n subtree: true,\n });\n mutationObserver.observe(root.ownerDocument.documentElement, {\n attributes: true,\n });\n const documentHead = root.ownerDocument.head;\n if (documentHead)\n mutationObserver.observe(documentHead, {\n attributes: true,\n characterData: true,\n childList: true,\n subtree: true,\n });\n const stylesheetLoaded = (): void => schedule();\n documentHead?.addEventListener('load', stylesheetLoaded, true);\n view.addEventListener('resize', schedule);\n render();\n return () => {\n if (frame) view.cancelAnimationFrame(frame);\n resizeObserver.disconnect();\n mutationObserver.disconnect();\n documentHead?.removeEventListener('load', stylesheetLoaded, true);\n view.removeEventListener('resize', schedule);\n layer.replaceChildren();\n };\n}\n\n/**\n * Wire a {@link Catalog}'s interactions with one delegated listener set: sidebar\n * item selection (and the related-entry popup menu), the sidebar collapse toggle, and\n * the theme toggle. The app owns the `active`/`collapsed`/`theme` signals and updates\n * them in the callbacks; optionally mirror the active id into the URL via `urlParam`.\n * It also wires the scroll dividers below root (`wireScrollDividers`), so the\n * catalog's panes and every example in it show their chrome dividers only\n * while scrolled. Returns a disposer.\n */\nexport function wireCatalog(\n root: HTMLElement,\n {\n onSelect,\n onToggleSidebar,\n onToggleTheme,\n onToggleSecondary,\n urlParam,\n revealSelection,\n selectAction = 'catalog-select',\n toggleSidebarAction = 'catalog-toggle-sidebar',\n toggleThemeAction = 'catalog-toggle-theme',\n toggleSecondaryAction = 'catalog-toggle-secondary',\n collapsed,\n sidebarSize,\n sidebarStorageKey,\n id: catalogId = 'kui-catalog',\n }: WireCatalogOptions,\n): () => void {\n let cancelReveal: (() => void) | undefined;\n const select = (id: string) => {\n onSelect(id);\n const view = root.ownerDocument.defaultView;\n if (urlParam && view) {\n const url = new URL(view.location.href);\n url.searchParams.set(urlParam, id);\n view.history.replaceState(null, '', url);\n }\n // An open overlay sidebar gives way to the entry just chosen from it.\n const rail = root.ownerDocument.getElementById(`${catalogId}-left-rail`);\n if (\n collapsed &&\n !collapsed.peek() &&\n rail &&\n root.ownerDocument.defaultView?.getComputedStyle(rail).position ===\n 'absolute'\n )\n collapsed.value = true;\n if (revealSelection) {\n cancelReveal?.();\n cancelReveal = revealCatalogEntry(\n root,\n id,\n revealSelection === true ? undefined : revealSelection,\n );\n }\n };\n\n const disposers: Array<() => void> = [\n wireScrollDividers(root),\n // Sidebar items AND the footer's related-entry popup-menu items both carry\n // `data-action={selectAction}` + `data-item-id`, so one delegated click covers both.\n delegate(\n root,\n 'click',\n `[data-action=\"${selectAction}\"]`,\n (_event, element) => {\n const id = (element as HTMLElement).dataset.itemId;\n if (id) select(id);\n },\n ),\n ];\n if (onToggleSidebar) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleSidebarAction}\"]`, () =>\n onToggleSidebar(),\n ),\n );\n }\n if (onToggleTheme) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleThemeAction}\"]`, () =>\n onToggleTheme(),\n ),\n );\n }\n if (onToggleSecondary) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleSecondaryAction}\"]`, () =>\n onToggleSecondary(),\n ),\n );\n }\n if (collapsed || sidebarSize)\n disposers.push(\n wireWorkbench(root, {\n id: catalogId,\n panels: {\n leftRail: {\n collapsed,\n size: sidebarSize,\n storageKey: sidebarStorageKey,\n },\n },\n }),\n );\n return () => {\n cancelReveal?.();\n for (const dispose of disposers.splice(0)) dispose();\n };\n}\n"]}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * An app-owned scroll arrangement outside a `Pane`: the `id` of the element
3
+ * that scrolls and the `id`s of the pinned chrome on each physical side of it.
4
+ * Each named chrome element shows its divider on the side facing the scroller
5
+ * while content is scrolled away beyond that side. Ids are resolved below the
6
+ * wired root on every refresh, so a re-render that replaces an element keeps
7
+ * the pairing.
8
+ */
9
+ interface ScrollDividerTarget {
10
+ /** The `id` of the scrolling element. */
11
+ scroller: string;
12
+ /** Chrome above the scroller: shows its bottom divider once scrolled down. */
13
+ top?: string;
14
+ /**
15
+ * Chrome right of the scroller: shows its left divider while content is
16
+ * hidden beyond the scroller's right edge (never when nothing overflows).
17
+ */
18
+ right?: string;
19
+ /**
20
+ * Chrome below the scroller: shows its top divider while content is hidden
21
+ * beyond the scroller's bottom edge (never when nothing overflows).
22
+ */
23
+ bottom?: string;
24
+ /** Chrome left of the scroller: shows its right divider once scrolled right. */
25
+ left?: string;
26
+ }
27
+ interface WireScrollDividersOptions {
28
+ /**
29
+ * App-owned scroll arrangements to pair beyond the ones found by structure
30
+ * (every `Pane`'s header and footer around its content, every `NavStack`'s
31
+ * and `TabScaffold`'s chrome around its active region, and every `TabBar`
32
+ * strip).
33
+ */
34
+ targets?: readonly ScrollDividerTarget[];
35
+ }
36
+ /**
37
+ * Wire scroll dividers below `root`: a divider between pinned chrome and the
38
+ * content that scrolls beside it shows only while content is scrolled away
39
+ * from that edge. Near edges (top, left) hide at the scroll start; far edges
40
+ * (bottom, right) hide at the scroll end and whenever nothing overflows.
41
+ *
42
+ * The wiring only reports scroll state; each component draws its own divider
43
+ * from it. It writes `data-scroll-overflow` (the edges with hidden content, in
44
+ * canonical `t`/`r`/`b`/`l` order) on each scroller, and `data-scroll-divider`
45
+ * (the sides to draw) on each paired chrome element:
46
+ *
47
+ * - every `Pane` with a header or footer: its header shows a bottom divider and
48
+ * its footer a top divider (drawn by the Pane, per its `chromeDividers`);
49
+ * - every `NavStack`'s top chrome and bottom toolbar around its active view,
50
+ * and every `TabScaffold`'s bar under its active scene: the chrome shows a
51
+ * bottom (top chrome) or top (bottom toolbar, bar) divider. The scroller is
52
+ * whichever element actually scrolls there: the view or scene itself, or,
53
+ * through a sole child with no chrome of its own on that edge, a `Pane`'s
54
+ * content or a nested `NavStack` / `TabScaffold` region (a Pane's own header
55
+ * or footer draws that boundary instead);
56
+ * - every `TabBar` strip: the bar draws a divider on each side of the strip
57
+ * whose tabs are scrolled out of view;
58
+ * - each app-owned `targets` pairing: a `Toolbar` or `List` named as chrome
59
+ * draws the divider on its facing side.
60
+ *
61
+ * Structure is re-read after every DOM change below root (a re-render that
62
+ * drops the attributes gets them back before paint), scroll is tracked with
63
+ * one capturing listener, and size changes of each scroller and its children
64
+ * with a `ResizeObserver`. Returns a disposer that removes every attribute it
65
+ * wrote. See `docs/23-app-layouts.md` §3.7.
66
+ */
67
+ declare function wireScrollDividers(root: HTMLElement | Document, { targets }?: WireScrollDividersOptions): () => void;
68
+
69
+ export { type ScrollDividerTarget, type WireScrollDividersOptions, wireScrollDividers };
@@ -0,0 +1,3 @@
1
+ export { wireScrollDividers } from './chunk-JCV4GXWB.js';
2
+
3
+ //# sourceMappingURL=wire-scroll-dividers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"wire-scroll-dividers.js"}
@@ -1,4 +1,4 @@
1
- export { wireTokenSearchFields } from './chunk-BSKEH3UC.js';
1
+ export { wireTokenSearchFields } from './chunk-NBYTIVHS.js';
2
2
 
3
3
 
4
4
 
@@ -1,12 +1,15 @@
1
1
  import { SafeHtml } from 'kerfjs';
2
+ import { ListConfig } from './list.js';
3
+ import { PaneConfig } from './pane.js';
2
4
  import { ResizableRegionSeparator, ResizableRegionCollapseMotion, ResizableRegionContentOverflow, ResizableRegionPresentation, ResizableRegionRestorePosition } from './resizable-region.js';
3
5
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
4
- import { a as PanelToolbar, b as PanelToggle } from './panel-toolbar-BFQxFITu.js';
5
- import { ToolbarProps } from './toolbar.js';
6
+ import { a as PanelToolbar, b as PanelToggle } from './panel-toolbar-BN4x0rth.js';
7
+ import { ToolbarConfig } from './toolbar.js';
8
+ import './css-values.js';
9
+ import './flex-alignment-4ms8ZbV8.js';
10
+ import './sides-BPSWde0A.js';
6
11
  import './lucide-icon.js';
7
12
  import 'lucide';
8
- import './divider-sides-BzB6rphT.js';
9
- import './pane.js';
10
13
 
11
14
  /** The standard toggle a Workbench renders for a panel (see {@link PanelToggle}). */
12
15
  type WorkbenchPanelToggle = PanelToggle;
@@ -19,8 +22,13 @@ type WorkbenchPanelToggle = PanelToggle;
19
22
  * `FloatingToolbar` in the work area's bottom-end corner.
20
23
  */
21
24
  type WorkbenchPanelToolbar = PanelToolbar;
22
- /** The work area's top toolbar; collapsed rails add their groups to it. */
23
- interface WorkbenchMainToolbar {
25
+ /**
26
+ * The work area's top toolbar; collapsed rails add their groups to it. Its
27
+ * configuration forwards to its `Toolbar`. It draws no divider of its own by
28
+ * default: the work area's `Pane` draws one under its header chrome, wherever
29
+ * that chrome ends, while `main` is scrolled (`mainPane.chromeDividers`).
30
+ */
31
+ interface WorkbenchMainToolbar extends ToolbarConfig {
24
32
  label: string;
25
33
  /** The work area's title, usually an extra-large `ToolbarText`. */
26
34
  title?: KerfUiContent;
@@ -29,26 +37,27 @@ interface WorkbenchMainToolbar {
29
37
  center?: KerfUiContent;
30
38
  /** Groups at the trailing edge, before a collapsed right rail's groups. */
31
39
  trailing?: KerfUiContent;
32
- /** The toolbar's narrow-width policy (see `Toolbar.responsive`). */
33
- responsive?: ToolbarProps['responsive'];
34
- responsiveAt?: ToolbarProps['responsiveAt'];
35
40
  }
36
- /** The work area's bottom toolbar; a collapsed drawer adds its groups to it. */
37
- interface WorkbenchMainBottomToolbar {
41
+ /**
42
+ * The work area's bottom toolbar; a collapsed drawer adds its groups to it.
43
+ * Its configuration forwards to its `Toolbar`. It draws no divider of its own
44
+ * by default: the work area's `Pane` draws one over its footer chrome while
45
+ * more of `main` lies below (`mainPane.chromeDividers`).
46
+ */
47
+ interface WorkbenchMainBottomToolbar extends ToolbarConfig {
38
48
  label: string;
39
49
  leading?: KerfUiContent;
50
+ center?: KerfUiContent;
40
51
  trailing?: KerfUiContent;
41
52
  }
42
53
  /**
43
- * The work area: the app's `main` under `mainToolbar` (and above
44
- * `mainBottomToolbar`), with each collapsed panel's groups added to the
45
- * toolbar on its side. Without either toolbar, `main` renders as given.
46
- */
47
- /**
48
- * Whether the work area's header or footer chrome stays pinned (`fixed`) or
49
- * scrolls away with the content (`scroll`).
54
+ * Whether the work area's header or footer chrome stays pinned (`fixed`),
55
+ * scrolls away with the content (`scroll`), or stays pinned while the work
56
+ * area is tall enough and scrolls with the content when it is short (`auto`,
57
+ * the Pane's `chromePlacement="auto"`; it applies to the pinned header and
58
+ * footer together).
50
59
  */
51
- type WorkbenchChromePlacement = 'fixed' | 'scroll';
60
+ type WorkbenchChromePlacement = 'fixed' | 'scroll' | 'auto';
52
61
 
53
62
  /**
54
63
  * The Workbench container breakpoint below which a panel presents as an
@@ -81,6 +90,14 @@ interface WorkbenchPanel {
81
90
  toolbar?: WorkbenchPanelToolbar;
82
91
  /** Optional bottom toolbar under a `toolbar` panel's content. */
83
92
  footer?: KerfUiContent;
93
+ /**
94
+ * Configuration for a `toolbar` panel's `Pane` (`contentElement`,
95
+ * `contentLabel`, `separators`, `safeAreaEdges`, `chromeDividers`) — for example
96
+ * `{ contentElement: 'nav', contentLabel: 'Sections' }` for a navigation
97
+ * rail. Omitted or `undefined` fields keep the `Pane` defaults. Ignored
98
+ * without a `toolbar`, where `content` renders as given.
99
+ */
100
+ pane?: PaneConfig;
84
101
  /** Whether the panel is currently collapsed (the app owns this). */
85
102
  collapsed?: boolean;
86
103
  /**
@@ -158,13 +175,34 @@ interface WorkbenchProps {
158
175
  */
159
176
  mainBottomToolbar?: WorkbenchMainBottomToolbar;
160
177
  /**
161
- * Whether `mainToolbar` and `mainHeader` stay pinned (`fixed`, default) or
178
+ * Whether `mainToolbar` and `mainHeader` stay pinned (`fixed`, default),
162
179
  * scroll away with `main` (`scroll`) — useful where large text would leave
163
- * pinned chrome little room.
180
+ * pinned chrome little room — or stay pinned while the work area is tall
181
+ * enough and scroll with `main` when it is short (`auto`).
164
182
  */
165
183
  mainHeaderPlacement?: WorkbenchChromePlacement;
166
184
  /** The same for `mainFooter` and `mainBottomToolbar` (default `fixed`). */
167
185
  mainFooterPlacement?: WorkbenchChromePlacement;
186
+ /**
187
+ * Configuration for the work area's `Pane` (`contentElement`,
188
+ * `contentLabel`, `separators`, `safeAreaEdges`, `chromeDividers`), which it has whenever it
189
+ * has a toolbar, `mainHeader`, or `mainFooter`; without that chrome, `main`
190
+ * renders as given and this is ignored. Omitted or `undefined` fields keep
191
+ * the `Pane` defaults.
192
+ */
193
+ mainPane?: PaneConfig;
194
+ /**
195
+ * Configuration for the `List` that holds `mainHeader` (`gap`, `hAlign`,
196
+ * `vAlign`, `dividerSides`, `textInsets`, `controlInsets`). Omitted or
197
+ * `undefined` fields keep the defaults (no divider: the work area's
198
+ * `Pane` draws the line under its header chrome).
199
+ */
200
+ mainHeaderList?: ListConfig;
201
+ /**
202
+ * The same for the `List` that holds `mainFooter` (no divider by default:
203
+ * the work area's `Pane` draws the line over its footer chrome).
204
+ */
205
+ mainFooterList?: ListConfig;
168
206
  leftRail?: WorkbenchPanel;
169
207
  rightRail?: WorkbenchPanel;
170
208
  bottomDrawer?: WorkbenchPanel;
@@ -201,6 +239,6 @@ interface WorkbenchProps {
201
239
  * lives outside it and stays reachable). A panel may opt in to drag and keyboard resizing with
202
240
  * `resizable`, which `wireWorkbench` drives. See `docs/23-app-layouts.md` §3.3.
203
241
  */
204
- declare function Workbench({ id, label, main, leftRail, rightRail, bottomDrawer, mainToolbar, mainHeader, mainFooter, mainBottomToolbar, mainHeaderPlacement, mainFooterPlacement, mainMinSize, mainMinHeight, className, slot, }: WorkbenchProps): SafeHtml;
242
+ declare function Workbench({ id, label, main, leftRail, rightRail, bottomDrawer, mainToolbar, mainHeader, mainFooter, mainBottomToolbar, mainHeaderPlacement, mainFooterPlacement, mainPane, mainHeaderList, mainFooterList, mainMinSize, mainMinHeight, className, slot, }: WorkbenchProps): SafeHtml;
205
243
 
206
244
  export { Workbench, type WorkbenchChromePlacement, type WorkbenchCompactOverlay, type WorkbenchMainBottomToolbar, type WorkbenchMainToolbar, type WorkbenchPanel, type WorkbenchPanelResizable, type WorkbenchPanelToggle, type WorkbenchPanelToolbar, type WorkbenchProps, type WorkbenchResponsiveOverlayAt };
package/dist/workbench.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Workbench } from './chunk-EAX2GSS4.js';
1
+ export { Workbench } from './chunk-G2RKFVRB.js';
2
2
 
3
3
 
4
4
 
@@ -16,7 +16,7 @@ These are normative contracts for package components and consuming applications.
16
16
  - `StateBanner` defaults to polite `role="status"`; use `urgency="alert"` only for an attention-requiring failure. Its optional `badge` is persistent inline status/count content beside the title and is announced as part of the banner; keep it terse and do not rely on color alone for its meaning.
17
17
  - `EmptyState` reports busy state through `aria-busy` and never relies on an illustration as its label.
18
18
  - `Select` follows the Web Awesome host's standard `input`/`change` events. Application tests verify the live `value`, focus, and events—not attributes alone. Its decorative option icons and value-dependent selected content remain present after controlled rerenders, so the visible choice does not silently lose its non-text cue.
19
- - `DisclosureArrow` is an 18px root-scaled decorative visual by default, not an interaction target. Its owning native control supplies a stable accessible name, pointer and keyboard interaction, and `aria-expanded`; multiple arrows keep independently controlled state. Consumers may override `--kui-disclosure-arrow-size` without changing that ownership. Configured directions animate over the shortest path; a 180-degree closed-to-open tie uses counterclockwise rotation.
19
+ - `DisclosureArrow` is an 18px root-scaled decorative visual by default, not an interaction target. Its owning native control supplies a stable accessible name, pointer and keyboard interaction, and `aria-expanded`; multiple arrows keep independently controlled state. Consumers may resize it with the typed `size` prop without changing that ownership. Configured directions animate over the shortest path; a 180-degree closed-to-open tie uses counterclockwise rotation.
20
20
  - `List` is layout-only and adds no `list` role. Children own their native or ARIA semantics. Give a scrollable List a bounded block size, avoid nested scroll owners, and keep focused children visible while scrolling.
21
21
 
22
22
  ## Select
@@ -30,6 +30,27 @@ adding height or spacing. This also applies to `renderSelected`: selected conten
30
30
  stays separate from the control's stable accessible name. Applications do not
31
31
  need shadow-DOM patches or extra label styling.
32
32
 
33
+ Set `multiple` (with an array `value`) to let the person choose any number
34
+ of choices. The popup stays open while they toggle choices with the pointer,
35
+ Enter, or Space, and closes on an outside press, Escape, or focus leaving,
36
+ returning focus to the combobox. The listbox is `aria-multiselectable`, each
37
+ chosen option shows its check, and the closed control reads the chosen labels
38
+ in choice order as one short localized list (the `placeholderText` when none
39
+ are chosen) instead of a removable tag per choice. `change` and `input` report
40
+ the value array; in a form, every chosen value is submitted under `name`.
41
+
42
+ A toolbar filter menu (a "Filter by label" funnel) is a multiple Select with
43
+ `selectedPresentation="icon-only"` and a fixed `triggerIcon`; the types accept
44
+ `triggerIcon` only there, and require it there, because no single chosen
45
+ choice has an icon to show. The trigger keeps the icon-only pill geometry
46
+ below: the fixed icon, then, while any choice is chosen, a compact brand
47
+ `Badge` with the count 4px after it, then the caret. The badge is hidden from
48
+ assistive technology; instead the combobox's accessible name ends with the
49
+ chosen labels in choice order ("Filter by label: Bug, Docs", just "Filter by
50
+ label" when none are chosen), and its hidden value text stays empty so screen
51
+ readers do not announce the list twice. With a visible `label` the same summary
52
+ reads in the label, standing in for the hidden value.
53
+
33
54
  Use `presentation="toolbar-borderless"` inside a `ToolbarControlGroup`, with
34
55
  `size="compact"` in a compact group; set `focusRingOwner="group"` when that
35
56
  parent paints the composed focus ring. `selectedPresentation="icon-only"` hides
@@ -41,7 +62,12 @@ trigger (8px inline padding on both sides, 12px from the icon to the caret, a
41
62
  choice list. Inside a group the trigger is inset evenly on every side (2px in a
42
63
  default group, 1px in a compact one) with a concentric radius; the group grows
43
64
  to the trigger's width, so a single group is wider than it is tall and its
44
- focus ring follows the pill while focused and while its listbox is open.
65
+ focus ring follows the pill while focused. While the listbox is open the
66
+ trigger drops its ring, as a `PopupMenu` trigger does: the open popup and its
67
+ current option show where focus is, and the ring returns when the listbox
68
+ closes with focus still on the control. A group that owns the ring
69
+ (`focusRing="outline"` or `"halo"`) drops it the same way while a Select
70
+ listbox or `PopupMenu` inside the group is open.
45
71
  Beside other controls in one group, the icon-only trigger is one more segment:
46
72
  it keeps the group's gap and its siblings' block inset, height, item radius,
47
73
  and hover pill. In a group with per-control rings (`focusRing="control"`, the
@@ -81,6 +107,79 @@ repeated and out-of-order completions, cancellation, instance isolation, and
81
107
  removal. `tests/browser/select-lifecycle.spec.ts` repeats animation/resize/reopen
82
108
  sequences at wide and narrow widths in Chromium, Firefox, and WebKit.
83
109
 
110
+ ### Help tags on icon-only triggers
111
+
112
+ An icon-only control has no visible title, so sighted pointer and keyboard users
113
+ would otherwise see only its icon (and a filter's count). Following the Apple
114
+ HIG convention for toolbar items, three kinds of icon-only control show a help
115
+ tag: a Web Awesome `wa-tooltip` in the theme's tooltip palette, below the
116
+ control.
117
+
118
+ - an icon-only `Select` (`selectedPresentation="icon-only"`, single or
119
+ `multiple`);
120
+ - an icon-only `PopupMenu` (named by `label` rather than visible `text`);
121
+ - an icon-only `<button>` or link (`<a href>`) inside a `ToolbarControlGroup`,
122
+ named by a non-empty `aria-label`, with no visible text, no native `title`,
123
+ and no Web Awesome tooltip `for` it.
124
+
125
+ Tags are on by default and take no props. One document-level installer covers
126
+ all three kinds, and any of `@kerfjs/ui/select/register`,
127
+ `@kerfjs/ui/popup-menu/register`, or `@kerfjs/ui/help-tags/register` installs
128
+ it (once per document, however many are imported). An application whose
129
+ toolbars have icon-only buttons but no registered `Select` or `PopupMenu`
130
+ imports `@kerfjs/ui/help-tags/register`, which registers only the tooltip
131
+ element. Pure `SafeHtml` rendering stays zero-JS: without an installer, nothing
132
+ shows a tag.
133
+
134
+ - **Text.** The tag says what the accessible name says: a filter's name and
135
+ chosen labels ("Filter by label: Bug, Docs", or "Filter by label" when none
136
+ are chosen), a single Select's name and current choice ("Rendering balance:
137
+ Balanced"), a menu's `label` ("Sort tickets"), or a toolbar button's
138
+ `aria-label` ("Pin view"). It updates with the selection.
139
+ - **Showing.** It appears after the pointer rests on the control for 500ms, at
140
+ once when a neighboring tag closed moments ago (so scanning along a toolbar
141
+ stays quick, across buttons, Selects, and menus alike), and immediately on
142
+ keyboard focus (`:focus-visible`). A pointer press that focuses the control
143
+ and touch input never show it.
144
+ - **Hiding.** It hides when the pointer and keyboard focus have both left the
145
+ control, on a press, on Escape, and whenever a popup opens. It does not come
146
+ back when the popup closes and focus returns to the trigger, or while the
147
+ pointer stays on a pressed button; it returns after the pointer moves onto
148
+ something else or focus leaves and comes back.
149
+ - **Assistive technology.** The tag is `aria-hidden` and never joins the
150
+ control's `aria-labelledby` or `aria-describedby` (kerf anchors it directly
151
+ rather than through `for`), so the accessible name is unchanged and announced
152
+ once; the accessibility tree is identical with the tag open or closed.
153
+ - **Isolation.** A Select's or PopupMenu's tag lives in the control's own
154
+ shadow root, so the morph never touches it and light-DOM `:has([open])`
155
+ selectors do not see it. A plain button cannot host a shadow root, so its tag
156
+ lives in one `aria-hidden`, `data-morph-skip` layer at the end of `<body>`
157
+ (fixed and zero-sized, so it never joins a grid or flex body's flow, and
158
+ re-attached if a body re-render drops it) and leaves that layer once hidden.
159
+ It copies the button's `color-scheme`, so it matches a subtree theme, and its
160
+ popup renders in the browser's top layer, so it shows above a modal dialog
161
+ that holds the button. Tags' `wa-show` / `wa-hide` lifecycle events stop at
162
+ the tag, so a listener on the control (or a delegated one above it) hears only
163
+ the popup; a document capture-phase listener still observes them. A long tag
164
+ wraps at the tooltip's maximum width and keeps 8px clear of the viewport
165
+ edge.
166
+
167
+ A labeled Select, a `PopupMenu` with visible `text`, and a toolbar button with
168
+ visible text get no tag: their visible text already names them. A button that
169
+ carries a native `title`, or that the application has already given a
170
+ `wa-tooltip` `for` its `id`, keeps that and gets no second tag, so nothing is
171
+ shown twice. Zero-JS components that name an icon control with a native `title`
172
+ (the `ListHeader` action, the `AppTab` close button, the `TokenSearchField`
173
+ reveal and clear buttons, and `SegmentedControl` choice titles) keep the
174
+ browser's own tooltip, which needs no script; the installer deliberately skips
175
+ them rather than stacking a second tag on the first. Icon-only buttons outside
176
+ a `ToolbarControlGroup` are application markup and keep whatever naming the
177
+ application gives them.
178
+ `tests/unit/help-tag.test.ts` walks the hover, focus, press, Escape, popup, and
179
+ warm-window transitions for every kind; `tests/browser/select-help-tag.spec.ts`
180
+ and `tests/browser/toolbar-help-tag.spec.ts` check the real elements in
181
+ Chromium.
182
+
84
183
  ## PopupMenu
85
184
 
86
185
  `PopupMenu` renders a Web Awesome dropdown, so the menu roles, arrow-key and
@@ -88,8 +187,13 @@ typeahead navigation, Escape, and focus return to the trigger come from
88
187
  `wa-dropdown`. Kerf's part is the trigger's name. A Web Awesome button takes its
89
188
  name from its content and ignores an `aria-label` on the host, so an icon-only
90
189
  trigger requires `label`, which renders as visually hidden text inside the
91
- button; a trigger with visible `text` is named by that text. Group headings render as the dropdown's native menu labels, and
92
- dividers are presentational. A disabled item stays in the menu but cannot be
190
+ button; a trigger with visible `text` is named by that text. An icon-only
191
+ trigger also shows its `label` as an `aria-hidden` help tag on hover and
192
+ keyboard focus (see [Help tags on icon-only triggers](#help-tags-on-icon-only-triggers)). Group headings
193
+ render as the same uppercase group titles a grouped `Select` shows, and dividers
194
+ are presentational. A keyboard-focused item is the menu's current row, painted
195
+ with the Select's current-option fill rather than a second focus ring inside the
196
+ open popup. A disabled item stays in the menu but cannot be
93
197
  chosen; disable the whole trigger only when every command is unavailable.
94
198
 
95
199
  ## ListActionRow
@@ -183,10 +287,15 @@ forced to a dark color scheme, but it is **not** in the top layer, so it never
183
287
  covers dialogs, popovers, or other overlays. Its children are the app's controls
184
288
  (normally `ToolbarControlGroup`s), which keep their own names, focus, and
185
289
  keyboard behavior; the application owns their actions, the toolbar's visibility,
186
- and — via `position` and `--kui-floating-toolbar-inset`, set on the toolbar
187
- or an ancestor — where it sits. Inside a `Workbench`, `CollapsiblePanel`, or
290
+ and — via `position` and the typed `inset` prop — where it sits. Inside a `Workbench`, `CollapsiblePanel`, or
188
291
  `ResizableRegion` `restoreControl` the restore corner owns the inset, so the
189
- toolbar floats from that corner.
292
+ toolbar floats from that corner. While one of those layouts has a side overlay
293
+ open over the toolbar's region (a Workbench rail overlay, a `wireSidebar`
294
+ compact overlay, an overlay `CollapsiblePanel` or horizontal
295
+ `ResizableRegion`), the toolbar is hidden (`visibility: hidden`), so it is
296
+ unfocusable and out of the accessibility tree rather than a control stranded
297
+ behind the overlay's focus trap; it returns when the overlay closes. The
298
+ overlay's own floating toolbars stay.
190
299
 
191
300
  ## Tabs
192
301