@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
@@ -55,14 +55,14 @@
55
55
  --_kui-workbench-rail-safe-inset: var(--_kui-workbench-safe-inline-start);
56
56
  --kui-edge-inset-inline-start: var(--_kui-workbench-safe-inline-start);
57
57
  --kui-edge-inset-inline-end: 0px;
58
- border-inline-end: 1px solid var(--kui-color-border);
58
+ border-inline-end: 1px solid var(--kui-color-neutral-border-normal);
59
59
  }
60
60
 
61
61
  .kui-workbench__rail--right {
62
62
  --_kui-workbench-rail-safe-inset: var(--_kui-workbench-safe-inline-end);
63
63
  --kui-edge-inset-inline-start: 0px;
64
64
  --kui-edge-inset-inline-end: var(--_kui-workbench-safe-inline-end);
65
- border-inline-start: 1px solid var(--kui-color-border);
65
+ border-inline-start: 1px solid var(--kui-color-neutral-border-normal);
66
66
  }
67
67
 
68
68
  .kui-workbench__rail[data-collapsed="true"] {
@@ -157,30 +157,32 @@
157
157
  var(--kui-edge-inset-block-end);
158
158
  }
159
159
 
160
- .kui-workbench__main:not(
161
- :has(
162
- > :is(
163
- [data-component="pane"],
164
- [data-component="nav-stack"],
165
- [data-component="split-view"],
166
- [data-component="workbench"],
167
- [data-component="tab-scaffold"]
168
- ):only-child
169
- )
170
- )
171
- > *,
172
- .kui-workbench__panel-content:not(
173
- :has(
174
- > :is(
175
- [data-component="pane"],
176
- [data-component="nav-stack"],
177
- [data-component="split-view"],
178
- [data-component="workbench"],
179
- [data-component="tab-scaffold"]
180
- ):only-child
181
- )
182
- )
183
- > * {
160
+ /* Every other child sees a cleared context. The exemption is tested on the
161
+ child itself, never as `region:not(:has(…)) > *`: a `:has()` before a
162
+ universal child makes each child of the region re-check the region's
163
+ `:has()` on every DOM change (~46ms per restyle for 1000 rows in Chromium).
164
+ SplitView, NavStack, TabScaffold, and CollapsiblePanel content use the same
165
+ shape. */
166
+ .kui-workbench__main
167
+ > :not(
168
+ :is(
169
+ [data-component="pane"],
170
+ [data-component="nav-stack"],
171
+ [data-component="split-view"],
172
+ [data-component="workbench"],
173
+ [data-component="tab-scaffold"]
174
+ ):only-child
175
+ ),
176
+ .kui-workbench__panel-content
177
+ > :not(
178
+ :is(
179
+ [data-component="pane"],
180
+ [data-component="nav-stack"],
181
+ [data-component="split-view"],
182
+ [data-component="workbench"],
183
+ [data-component="tab-scaffold"]
184
+ ):only-child
185
+ ) {
184
186
  --kui-edge-inset-block-start: 0px;
185
187
  --kui-edge-inset-block-end: 0px;
186
188
  --kui-edge-inset-inline-start: 0px;
@@ -189,15 +191,11 @@
189
191
 
190
192
  /* A region whose only child is a Pane or layout lets it fill the region, so a
191
193
  composed toolbar's footer (or the app's own) sits at the region's bottom
192
- edge rather than under short content. */
194
+ edge rather than under short content. Each of those components fills the
195
+ region from its own stylesheet (pane.css, nav-stack.css, split-view.css,
196
+ tab-scaffold.css); a nested Workbench fills it here. */
193
197
  :is(.kui-workbench__main, .kui-workbench__panel-content)
194
- > :is(
195
- [data-component="pane"],
196
- [data-component="nav-stack"],
197
- [data-component="split-view"],
198
- [data-component="workbench"],
199
- [data-component="tab-scaffold"]
200
- ):only-child {
198
+ > [data-component="workbench"]:only-child {
201
199
  height: 100%;
202
200
  }
203
201
 
@@ -213,7 +211,7 @@
213
211
  flex: 0 0 var(--_kui-workbench-drawer-extent);
214
212
  min-height: 0;
215
213
  overflow: hidden;
216
- border-block-start: 1px solid var(--kui-color-border);
214
+ border-block-start: 1px solid var(--kui-color-neutral-border-normal);
217
215
  background: var(--kui-color-surface);
218
216
  }
219
217
 
@@ -387,10 +385,64 @@
387
385
  display: none;
388
386
  }
389
387
 
390
- /* Where the engine can extend a clip past the panel's edge, an expanded
391
- panel lets exactly the handle's outer half through, so the hit target
392
- straddles the separator like a ResizableRegion handle does. Collapsing drops
393
- the margin again before the content slides out. */
388
+ /* An expanded panel lets exactly the handle's outer half through its clip, so
389
+ the hit target straddles the separator like a ResizableRegion handle does
390
+ and the grip is drawn centered on the separator line. Collapsing drops the
391
+ extension again before the content slides out. Engines that can extend a
392
+ clip past the panel's edge do it with `overflow-clip-margin`; the rest
393
+ (WebKit) clip with a `clip-path` that reaches past the panel's edges. That
394
+ also makes the panel a stacking context, so the panel stacks at the
395
+ handle's own level to keep the handle's outer half above the work area
396
+ beside it. The clip and the stacking level sit at low specificity, so a
397
+ responsive overlay presentation (below) replaces both. */
398
+ @supports not (overflow-clip-margin: 10px) {
399
+ .kui-workbench__rail[data-resizable="true"][data-presentation="inline"]:not(
400
+ [data-collapsed="true"],
401
+ [data-content-overflow="visible"]
402
+ ),
403
+ .kui-workbench__drawer[data-resizable="true"][data-presentation="inline"]:not(
404
+ [data-collapsed="true"],
405
+ [data-content-overflow="visible"]
406
+ ) {
407
+ overflow: visible;
408
+ }
409
+
410
+ .kui-workbench__rail:where(
411
+ [data-resizable="true"][data-presentation="inline"]:not(
412
+ [data-collapsed="true"],
413
+ [data-content-overflow="visible"]
414
+ )
415
+ ) {
416
+ z-index: 3;
417
+ clip-path: inset(0 -10px);
418
+ }
419
+
420
+ .kui-workbench__drawer:where(
421
+ [data-resizable="true"][data-presentation="inline"]:not(
422
+ [data-collapsed="true"],
423
+ [data-content-overflow="visible"]
424
+ )
425
+ ) {
426
+ z-index: 3;
427
+ clip-path: inset(-10px 0 0);
428
+ }
429
+
430
+ .kui-workbench__rail--left[data-resizable="true"][data-presentation="inline"]
431
+ > .kui-workbench__handle {
432
+ inset-inline-end: -10px;
433
+ }
434
+
435
+ .kui-workbench__rail--right[data-resizable="true"][data-presentation="inline"]
436
+ > .kui-workbench__handle {
437
+ inset-inline-start: -10px;
438
+ }
439
+
440
+ .kui-workbench__drawer[data-resizable="true"][data-presentation="inline"]
441
+ > .kui-workbench__handle {
442
+ inset-block-start: -10px;
443
+ }
444
+ }
445
+
394
446
  @supports (overflow-clip-margin: 10px) {
395
447
  .kui-workbench__rail[data-resizable="true"]:not(
396
448
  [data-collapsed="true"],
@@ -542,6 +594,7 @@
542
594
  max-width: var(--kui-workbench-overlay-max-width, 85vw);
543
595
  inset-block: 0;
544
596
  box-shadow: var(--kui-shadow-l);
597
+ clip-path: none;
545
598
  }
546
599
 
547
600
  .kui-workbench__rail--left[data-responsive-overlay-at="narrow"] {
@@ -592,6 +645,7 @@
592
645
  inset-inline: 0;
593
646
  inset-block-end: 0;
594
647
  box-shadow: var(--kui-shadow-l);
648
+ clip-path: none;
595
649
  }
596
650
 
597
651
  .kui-workbench__drawer[data-responsive-overlay-at="narrow"][data-collapsed="true"] {
@@ -626,6 +680,7 @@
626
680
  max-width: var(--kui-workbench-overlay-max-width, 85vw);
627
681
  inset-block: 0;
628
682
  box-shadow: var(--kui-shadow-l);
683
+ clip-path: none;
629
684
  }
630
685
 
631
686
  .kui-workbench__rail--left[data-responsive-overlay-at="compact"] {
@@ -676,6 +731,7 @@
676
731
  inset-inline: 0;
677
732
  inset-block-end: 0;
678
733
  box-shadow: var(--kui-shadow-l);
734
+ clip-path: none;
679
735
  }
680
736
 
681
737
  .kui-workbench__drawer[data-responsive-overlay-at="compact"][data-collapsed="true"] {
@@ -717,10 +773,15 @@
717
773
  --kui-workbench-restore-inset,
718
774
  1rem
719
775
  );
720
- /* The corner owns the inset, so a FloatingToolbar composed here floats
721
- from this point instead of adding its own inset on top. */
722
- --kui-floating-toolbar-inset: 0px;
723
776
  position: absolute;
777
+ /* Hidden while an open rail overlay covers the work area (see below). */
778
+ visibility: var(
779
+ --_kui-workbench-covered,
780
+ var(
781
+ --_kui-collapsible-panel-covered,
782
+ var(--_kui-resizable-region-covered, inherit)
783
+ )
784
+ );
724
785
  z-index: var(
725
786
  --kui-workbench-restore-z,
726
787
  calc(var(--kui-workbench-overlay-z, 41) - 2)
@@ -788,6 +849,48 @@
788
849
  );
789
850
  }
790
851
 
852
+ /* An open rail overlay — static or a responsive one whose breakpoint applies —
853
+ covers the work area, so the work area's floating controls (a
854
+ FloatingToolbar in main, the drawer's restore corner, the other rail's
855
+ restore corner) are hidden, not merely stacked beneath it: they never paint
856
+ over the overlay whatever stacking context an app puts them in, and hidden
857
+ they leave the tab order and the accessibility tree. They come back as the
858
+ overlay closes. The Workbench's own covered context,
859
+ `--_kui-workbench-covered`, is set on the rail's siblings only (never on
860
+ the open rail), so the overlay's own floating controls stay; FloatingToolbar
861
+ and the layouts' restore corners read it. A direct child
862
+ resolves the Workbench's own container query, never a nested one's. */
863
+ .kui-workbench:has(
864
+ > .kui-workbench__rail[data-presentation="overlay"]:not(
865
+ [data-collapsed="true"]
866
+ )
867
+ )
868
+ > :is(.kui-workbench__center, .kui-workbench__restore) {
869
+ --_kui-workbench-covered: hidden;
870
+ }
871
+
872
+ @container kui-workbench (max-width: 44rem) {
873
+ .kui-workbench:has(
874
+ > .kui-workbench__rail[data-responsive-overlay-at="narrow"][data-presentation="inline"]:not(
875
+ [data-collapsed="true"]
876
+ )
877
+ )
878
+ > :is(.kui-workbench__center, .kui-workbench__restore) {
879
+ --_kui-workbench-covered: hidden;
880
+ }
881
+ }
882
+
883
+ @container kui-workbench (max-width: 28rem) {
884
+ .kui-workbench:has(
885
+ > .kui-workbench__rail[data-responsive-overlay-at="compact"][data-presentation="inline"]:not(
886
+ [data-collapsed="true"]
887
+ )
888
+ )
889
+ > :is(.kui-workbench__center, .kui-workbench__restore) {
890
+ --_kui-workbench-covered: hidden;
891
+ }
892
+ }
893
+
791
894
  @media (prefers-reduced-motion: reduce) {
792
895
  .kui-workbench__panel-content {
793
896
  transition: none;
@@ -1,7 +1,7 @@
1
1
  import { SafeHtml } from 'kerfjs';
2
2
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
3
3
 
4
- interface TabScaffoldTab<Id extends string = string> {
4
+ interface TabScaffoldTabBase<Id extends string> {
5
5
  id: Id;
6
6
  label: string;
7
7
  /** Decorative icon shown above the label in the bottom bar. */
@@ -9,6 +9,40 @@ interface TabScaffoldTab<Id extends string = string> {
9
9
  /** The tab's content — typically a `NavStack` so each tab keeps its own stack. */
10
10
  content: KerfUiContent;
11
11
  }
12
+ /** A tab with an optional count or short-status badge. */
13
+ interface TabScaffoldTabCountBadge {
14
+ /**
15
+ * Optional count or short status shown as a solid danger `Badge` at the
16
+ * top-trailing corner of the tab icon (the iOS tab-bar badge). Omitted, `''`,
17
+ * or non-finite numbers render no badge. The visual badge is `aria-hidden`;
18
+ * its meaning reaches assistive technology through `badgeLabel`.
19
+ *
20
+ * Pass `true` instead for the text-free dot (new content without a count).
21
+ */
22
+ badge?: string | number;
23
+ /**
24
+ * Localized phrase folded into the tab's accessible name as
25
+ * `"<label>, <badgeLabel>"` (for example `"3 unread"` → `"Inbox, 3 unread"`).
26
+ * Defaults to the badge text itself. Ignored when no badge renders.
27
+ */
28
+ badgeLabel?: string;
29
+ }
30
+ /** A tab with the text-free dot badge (new content without a count). */
31
+ interface TabScaffoldTabDotBadge {
32
+ /**
33
+ * `true` shows a solid danger dot `Badge` at the top-trailing corner of the
34
+ * tab icon — the iOS tab-bar dot for new content without a count.
35
+ */
36
+ badge: true;
37
+ /**
38
+ * Required localized phrase folded into the tab's accessible name as
39
+ * `"<label>, <badgeLabel>"` (for example `"New activity"` →
40
+ * `"Feed, New activity"`). A dot has no text, so this is its only meaning.
41
+ */
42
+ badgeLabel: string;
43
+ }
44
+ /** One bottom-bar destination: its label, optional icon and badge, and content. */
45
+ type TabScaffoldTab<Id extends string = string> = TabScaffoldTabBase<Id> & (TabScaffoldTabCountBadge | TabScaffoldTabDotBadge);
12
46
  interface TabScaffoldProps<Id extends string = string> {
13
47
  id: string;
14
48
  /** Accessible name for the tab bar. */
@@ -16,6 +50,16 @@ interface TabScaffoldProps<Id extends string = string> {
16
50
  tabs: readonly TabScaffoldTab<Id>[];
17
51
  /** The controlled active tab id (the app owns selection). */
18
52
  active: NoInfer<Id>;
53
+ /**
54
+ * The line over the tab bar, where it meets the active scene. `scroll`
55
+ * (default) shows it only while more of the scene's content lies below —
56
+ * never at the scroll end or when the content fits — once
57
+ * `wireScrollDividers` (`@kerfjs/ui/wire-scroll-dividers`) is wired above
58
+ * the scaffold; unwired, it does not show. `always` shows it without the
59
+ * wiring; `none` never, even when wired. The line is the bar's own 1px top
60
+ * border, so no state moves the bar or a tab.
61
+ */
62
+ chromeDividers?: 'scroll' | 'always' | 'none';
19
63
  className?: string;
20
64
  /** Native named-slot assignment when composed inside a web component. */
21
65
  slot?: string;
@@ -28,6 +72,6 @@ interface TabScaffoldProps<Id extends string = string> {
28
72
  * On larger classes, promote the tabs to a `Workbench` rail or sidebar instead of
29
73
  * a bottom bar. See `docs/23-app-layouts.md` §3.4.
30
74
  */
31
- declare function TabScaffold<Id extends string>({ id, label, tabs, active, className, slot, }: TabScaffoldProps<Id>): SafeHtml;
75
+ declare function TabScaffold<Id extends string>({ id, label, tabs, active, chromeDividers, className, slot, }: TabScaffoldProps<Id>): SafeHtml;
32
76
 
33
77
  export { TabScaffold, type TabScaffoldProps, type TabScaffoldTab };
@@ -1,11 +1,12 @@
1
+ import { Badge } from './chunk-MP2GDBQZ.js';
1
2
  import { jsxs, jsx } from 'kerfjs/jsx-runtime';
2
3
 
3
- // src/tab-scaffold.tsx
4
4
  function TabScaffold({
5
5
  id,
6
6
  label,
7
7
  tabs,
8
8
  active,
9
+ chromeDividers = "scroll",
9
10
  className = "",
10
11
  slot
11
12
  }) {
@@ -16,6 +17,7 @@ function TabScaffold({
16
17
  id,
17
18
  "data-component": "tab-scaffold",
18
19
  "data-tab-scaffold-id": id,
20
+ "data-chrome-dividers": chromeDividers === "always" || chromeDividers === "none" ? chromeDividers : void 0,
19
21
  slot,
20
22
  children: [
21
23
  /* @__PURE__ */ jsx("div", { class: "kui-tab-scaffold__scenes", children: tabs.map((tab) => /* @__PURE__ */ jsx(
@@ -28,25 +30,59 @@ function TabScaffold({
28
30
  children: tab.content
29
31
  }
30
32
  )) }),
31
- /* @__PURE__ */ jsx("nav", { class: "kui-tab-scaffold__bar", role: "tablist", "aria-label": label, children: tabs.map((tab) => /* @__PURE__ */ jsxs(
32
- "button",
33
- {
34
- type: "button",
35
- class: "kui-tab-scaffold__tab",
36
- role: "tab",
37
- "data-tab-scaffold-tab": tab.id,
38
- "aria-selected": String(tab.id === active),
39
- tabindex: tab.id === active ? "0" : "-1",
40
- children: [
41
- tab.icon && /* @__PURE__ */ jsx("span", { class: "kui-tab-scaffold__tab-icon", "aria-hidden": "true", children: tab.icon }),
42
- /* @__PURE__ */ jsx("span", { class: "kui-tab-scaffold__tab-label", children: tab.label })
43
- ]
44
- }
45
- )) })
33
+ /* @__PURE__ */ jsx("nav", { class: "kui-tab-scaffold__bar", role: "tablist", "aria-label": label, children: tabs.map((tab) => {
34
+ const dot = tab.badge === true;
35
+ const badgeText = dot ? void 0 : normalizeBadge(tab.badge);
36
+ const hasBadge = dot || badgeText !== void 0;
37
+ const badge = hasBadge && /* @__PURE__ */ jsx(
38
+ "span",
39
+ {
40
+ class: "kui-tab-scaffold__tab-badge",
41
+ "data-badge-kind": dot ? "dot" : "text",
42
+ children: badgeText === void 0 ? /* @__PURE__ */ jsx(Badge, { tone: "danger", size: "dot", ariaHidden: true }) : /* @__PURE__ */ jsx(
43
+ Badge,
44
+ {
45
+ tone: "danger",
46
+ appearance: "solid",
47
+ size: "compact",
48
+ ariaHidden: true,
49
+ children: badgeText
50
+ }
51
+ )
52
+ }
53
+ );
54
+ const badgeLabel = hasBadge ? tab.badgeLabel?.trim() || badgeText : void 0;
55
+ return /* @__PURE__ */ jsxs(
56
+ "button",
57
+ {
58
+ type: "button",
59
+ class: "kui-tab-scaffold__tab",
60
+ role: "tab",
61
+ "data-tab-scaffold-tab": tab.id,
62
+ "aria-selected": String(tab.id === active),
63
+ tabindex: tab.id === active ? "0" : "-1",
64
+ "aria-label": badgeLabel === void 0 ? void 0 : `${tab.label}, ${badgeLabel}`,
65
+ "data-has-badge": hasBadge ? "true" : void 0,
66
+ children: [
67
+ tab.icon ? /* @__PURE__ */ jsxs("span", { class: "kui-tab-scaffold__tab-icon", "aria-hidden": "true", children: [
68
+ tab.icon,
69
+ badge
70
+ ] }) : badge,
71
+ /* @__PURE__ */ jsx("span", { class: "kui-tab-scaffold__tab-label", children: tab.label })
72
+ ]
73
+ }
74
+ );
75
+ }) })
46
76
  ]
47
77
  }
48
78
  );
49
79
  }
80
+ function normalizeBadge(badge) {
81
+ if (typeof badge === "number")
82
+ return Number.isFinite(badge) ? String(badge) : void 0;
83
+ if (typeof badge === "string" && badge.trim()) return badge.trim();
84
+ return void 0;
85
+ }
50
86
 
51
87
  export { TabScaffold };
52
88
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tab-scaffold.tsx"],"names":[],"mappings":";;;AAiCO,SAAS,WAAA,CAA+B;AAAA,EAC7C,EAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ;AACF,CAAA,EAAyB;AACvB,EAAA,uBACE,IAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,CAAA,iBAAA,EAAoB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,MAC5C,EAAA;AAAA,MACA,gBAAA,EAAe,cAAA;AAAA,MACf,sBAAA,EAAsB,EAAA;AAAA,MACtB,IAAA;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,SAAI,KAAA,EAAM,0BAAA,EACR,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,qBACT,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAM,yBAAA;AAAA,YACN,2BAAyB,GAAA,CAAI,EAAA;AAAA,YAC7B,aAAA,EAAa,MAAA,CAAO,GAAA,CAAI,EAAA,KAAO,MAAM,CAAA;AAAA,YACrC,aAAA,EAAa,MAAA,CAAO,GAAA,CAAI,EAAA,KAAO,MAAM,CAAA;AAAA,YAEpC,QAAA,EAAA,GAAA,CAAI;AAAA;AAAA,SAER,CAAA,EACH,CAAA;AAAA,wBACA,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,uBAAA,EAAwB,IAAA,EAAK,SAAA,EAAU,YAAA,EAAY,KAAA,EAC3D,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,qBACT,IAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,KAAA,EAAM,uBAAA;AAAA,YACN,IAAA,EAAK,KAAA;AAAA,YACL,yBAAuB,GAAA,CAAI,EAAA;AAAA,YAC3B,eAAA,EAAe,MAAA,CAAO,GAAA,CAAI,EAAA,KAAO,MAAM,CAAA;AAAA,YACvC,QAAA,EAAU,GAAA,CAAI,EAAA,KAAO,MAAA,GAAS,GAAA,GAAM,IAAA;AAAA,YAEnC,QAAA,EAAA;AAAA,cAAA,GAAA,CAAI,IAAA,wBACF,MAAA,EAAA,EAAK,KAAA,EAAM,8BAA6B,aAAA,EAAY,MAAA,EAClD,cAAI,IAAA,EACP,CAAA;AAAA,8BAEF,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAM,6BAAA,EAA+B,cAAI,KAAA,EAAM;AAAA;AAAA;AAAA,SAExD,CAAA,EACH;AAAA;AAAA;AAAA,GACF;AAEJ","file":"tab-scaffold.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport type { KerfUiContent } from './semantic-content.js';\n\nexport interface TabScaffoldTab<Id extends string = string> {\n id: Id;\n label: string;\n /** Decorative icon shown above the label in the bottom bar. */\n icon?: SafeHtml;\n /** The tab's content — typically a `NavStack` so each tab keeps its own stack. */\n content: KerfUiContent;\n}\n\nexport interface TabScaffoldProps<Id extends string = string> {\n id: string;\n /** Accessible name for the tab bar. */\n label: string;\n tabs: readonly TabScaffoldTab<Id>[];\n /** The controlled active tab id (the app owns selection). */\n active: NoInfer<Id>;\n className?: string;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\n/**\n * A mobile-first, iOS-like bottom tab scaffold: a bottom tab bar that switches\n * between major sections, each tab keeping its own content (usually a `NavStack`)\n * mounted so its stack and scroll survive a switch. Controlled — the app owns\n * `active`; wire selection with `@kerfjs/ui/wire-tab-scaffold`'s `wireTabScaffold`.\n * On larger classes, promote the tabs to a `Workbench` rail or sidebar instead of\n * a bottom bar. See `docs/23-app-layouts.md` §3.4.\n */\nexport function TabScaffold<Id extends string>({\n id,\n label,\n tabs,\n active,\n className = '',\n slot,\n}: TabScaffoldProps<Id>) {\n return (\n <section\n class={`kui-tab-scaffold ${className}`.trim()}\n id={id}\n data-component=\"tab-scaffold\"\n data-tab-scaffold-id={id}\n slot={slot}\n >\n <div class=\"kui-tab-scaffold__scenes\">\n {tabs.map((tab) => (\n <div\n class=\"kui-tab-scaffold__scene\"\n data-tab-scaffold-scene={tab.id}\n data-active={String(tab.id === active)}\n aria-hidden={String(tab.id !== active)}\n >\n {tab.content}\n </div>\n ))}\n </div>\n <nav class=\"kui-tab-scaffold__bar\" role=\"tablist\" aria-label={label}>\n {tabs.map((tab) => (\n <button\n type=\"button\"\n class=\"kui-tab-scaffold__tab\"\n role=\"tab\"\n data-tab-scaffold-tab={tab.id}\n aria-selected={String(tab.id === active)}\n tabindex={tab.id === active ? '0' : '-1'}\n >\n {tab.icon && (\n <span class=\"kui-tab-scaffold__tab-icon\" aria-hidden=\"true\">\n {tab.icon}\n </span>\n )}\n <span class=\"kui-tab-scaffold__tab-label\">{tab.label}</span>\n </button>\n ))}\n </nav>\n </section>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/tab-scaffold.tsx"],"names":[],"mappings":"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","file":"tab-scaffold.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { Badge } from './badge.js';\nimport type { KerfUiContent } from './semantic-content.js';\n\ninterface TabScaffoldTabBase<Id extends string> {\n id: Id;\n label: string;\n /** Decorative icon shown above the label in the bottom bar. */\n icon?: SafeHtml;\n /** The tab's content — typically a `NavStack` so each tab keeps its own stack. */\n content: KerfUiContent;\n}\n\n/** A tab with an optional count or short-status badge. */\ninterface TabScaffoldTabCountBadge {\n /**\n * Optional count or short status shown as a solid danger `Badge` at the\n * top-trailing corner of the tab icon (the iOS tab-bar badge). Omitted, `''`,\n * or non-finite numbers render no badge. The visual badge is `aria-hidden`;\n * its meaning reaches assistive technology through `badgeLabel`.\n *\n * Pass `true` instead for the text-free dot (new content without a count).\n */\n badge?: string | number;\n /**\n * Localized phrase folded into the tab's accessible name as\n * `\"<label>, <badgeLabel>\"` (for example `\"3 unread\"` → `\"Inbox, 3 unread\"`).\n * Defaults to the badge text itself. Ignored when no badge renders.\n */\n badgeLabel?: string;\n}\n\n/** A tab with the text-free dot badge (new content without a count). */\ninterface TabScaffoldTabDotBadge {\n /**\n * `true` shows a solid danger dot `Badge` at the top-trailing corner of the\n * tab icon — the iOS tab-bar dot for new content without a count.\n */\n badge: true;\n /**\n * Required localized phrase folded into the tab's accessible name as\n * `\"<label>, <badgeLabel>\"` (for example `\"New activity\"` →\n * `\"Feed, New activity\"`). A dot has no text, so this is its only meaning.\n */\n badgeLabel: string;\n}\n\n/** One bottom-bar destination: its label, optional icon and badge, and content. */\nexport type TabScaffoldTab<Id extends string = string> =\n TabScaffoldTabBase<Id> & (TabScaffoldTabCountBadge | TabScaffoldTabDotBadge);\n\nexport interface TabScaffoldProps<Id extends string = string> {\n id: string;\n /** Accessible name for the tab bar. */\n label: string;\n tabs: readonly TabScaffoldTab<Id>[];\n /** The controlled active tab id (the app owns selection). */\n active: NoInfer<Id>;\n /**\n * The line over the tab bar, where it meets the active scene. `scroll`\n * (default) shows it only while more of the scene's content lies below —\n * never at the scroll end or when the content fits — once\n * `wireScrollDividers` (`@kerfjs/ui/wire-scroll-dividers`) is wired above\n * the scaffold; unwired, it does not show. `always` shows it without the\n * wiring; `none` never, even when wired. The line is the bar's own 1px top\n * border, so no state moves the bar or a tab.\n */\n chromeDividers?: 'scroll' | 'always' | 'none';\n className?: string;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\n/**\n * A mobile-first, iOS-like bottom tab scaffold: a bottom tab bar that switches\n * between major sections, each tab keeping its own content (usually a `NavStack`)\n * mounted so its stack and scroll survive a switch. Controlled — the app owns\n * `active`; wire selection with `@kerfjs/ui/wire-tab-scaffold`'s `wireTabScaffold`.\n * On larger classes, promote the tabs to a `Workbench` rail or sidebar instead of\n * a bottom bar. See `docs/23-app-layouts.md` §3.4.\n */\nexport function TabScaffold<Id extends string>({\n id,\n label,\n tabs,\n active,\n chromeDividers = 'scroll',\n className = '',\n slot,\n}: TabScaffoldProps<Id>) {\n return (\n <section\n class={`kui-tab-scaffold ${className}`.trim()}\n id={id}\n data-component=\"tab-scaffold\"\n data-tab-scaffold-id={id}\n data-chrome-dividers={\n chromeDividers === 'always' || chromeDividers === 'none'\n ? chromeDividers\n : undefined\n }\n slot={slot}\n >\n <div class=\"kui-tab-scaffold__scenes\">\n {tabs.map((tab) => (\n <div\n class=\"kui-tab-scaffold__scene\"\n data-tab-scaffold-scene={tab.id}\n data-active={String(tab.id === active)}\n aria-hidden={String(tab.id !== active)}\n >\n {tab.content}\n </div>\n ))}\n </div>\n <nav class=\"kui-tab-scaffold__bar\" role=\"tablist\" aria-label={label}>\n {tabs.map((tab) => {\n const dot = tab.badge === true;\n const badgeText = dot ? undefined : normalizeBadge(tab.badge);\n const hasBadge = dot || badgeText !== undefined;\n const badge = hasBadge && (\n <span\n class=\"kui-tab-scaffold__tab-badge\"\n data-badge-kind={dot ? 'dot' : 'text'}\n >\n {badgeText === undefined ? (\n <Badge tone=\"danger\" size=\"dot\" ariaHidden />\n ) : (\n <Badge\n tone=\"danger\"\n appearance=\"solid\"\n size=\"compact\"\n ariaHidden\n >\n {badgeText}\n </Badge>\n )}\n </span>\n );\n // A dot has no text fallback: without a usable badgeLabel (reachable\n // only from untyped callers) the tab keeps its plain accessible name.\n const badgeLabel = hasBadge\n ? tab.badgeLabel?.trim() || badgeText\n : undefined;\n return (\n <button\n type=\"button\"\n class=\"kui-tab-scaffold__tab\"\n role=\"tab\"\n data-tab-scaffold-tab={tab.id}\n aria-selected={String(tab.id === active)}\n tabindex={tab.id === active ? '0' : '-1'}\n aria-label={\n badgeLabel === undefined\n ? undefined\n : `${tab.label}, ${badgeLabel}`\n }\n data-has-badge={hasBadge ? 'true' : undefined}\n >\n {tab.icon ? (\n <span class=\"kui-tab-scaffold__tab-icon\" aria-hidden=\"true\">\n {tab.icon}\n {badge}\n </span>\n ) : (\n badge\n )}\n <span class=\"kui-tab-scaffold__tab-label\">{tab.label}</span>\n </button>\n );\n })}\n </nav>\n </section>\n );\n}\n\nfunction normalizeBadge(\n badge: string | number | undefined,\n): string | undefined {\n if (typeof badge === 'number')\n return Number.isFinite(badge) ? String(badge) : undefined;\n if (typeof badge === 'string' && badge.trim()) return badge.trim();\n return undefined;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import * as kerfjs from 'kerfjs';
1
+ import { SafeHtml } from 'kerfjs';
2
2
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
3
3
 
4
4
  interface TokenSearchToken {
@@ -41,6 +41,8 @@ interface TokenSearchFieldBaseProps {
41
41
  removeAction?: string;
42
42
  clearAction?: string;
43
43
  clearLabel?: string;
44
+ /** Icon for the clear button. Default: the Lucide `x` glyph token chips also use. */
45
+ clearIcon?: SafeHtml;
44
46
  className?: string;
45
47
  editorAttributes?: TokenSearchEditorAttributes;
46
48
  /** Native named-slot assignment when composed inside a web component. */
@@ -64,7 +66,7 @@ interface TokenSearchFieldValue {
64
66
  query: string;
65
67
  tokens: TokenSearchToken[];
66
68
  }
67
- declare function TokenSearchField({ id, label, query, tokens, revision, placeholder, tokenPlaceholder, disabled, autofocus, collapsible, expanded, expandAction, expandLabel, leading, trailing, presentation, editAction, removeAction, clearAction, clearLabel, className, editorAttributes, slot, }: TokenSearchFieldProps): kerfjs.SafeHtml;
69
+ declare function TokenSearchField({ id, label, query, tokens, revision, placeholder, tokenPlaceholder, disabled, autofocus, collapsible, expanded, expandAction, expandLabel, leading, trailing, presentation, editAction, removeAction, clearAction, clearLabel, clearIcon, className, editorAttributes, slot, }: TokenSearchFieldProps): SafeHtml;
68
70
  /** Read editable text and ordered token offsets from a rendered TokenSearchField editor. */
69
71
  declare function readTokenSearchField(editor: HTMLElement, knownTokens?: readonly TokenSearchToken[]): TokenSearchFieldValue;
70
72
  /** Focus an editor and place its caret at a text offset, skipping atomic token chips. */
@@ -1,4 +1,4 @@
1
- export { TokenSearchField, placeTokenSearchCaret, readTokenSearchField } from './chunk-RNRUVPJ3.js';
1
+ export { TokenSearchField, placeTokenSearchCaret, readTokenSearchField } from './chunk-63ZWBGE3.js';
2
2
 
3
3
 
4
4
  //# sourceMappingURL=token-search-field.js.map
@@ -23,6 +23,12 @@ interface ToolbarTextBaseProps {
23
23
  * instead. Default true.
24
24
  */
25
25
  ellipsis?: boolean;
26
+ /**
27
+ * Grow to fill the free space of the flex row it sits in (a Toolbar zone),
28
+ * truncating at the space left by its siblings instead of taking only its
29
+ * text's width. Default false.
30
+ */
31
+ fill?: boolean;
26
32
  /** Native named-slot assignment when composed inside a web component. */
27
33
  slot?: string;
28
34
  }
@@ -35,6 +41,6 @@ type ToolbarTextWrappingProps = {
35
41
  maxLines?: never;
36
42
  };
37
43
  type ToolbarTextProps = ToolbarTextBaseProps & ToolbarTextWrappingProps;
38
- declare function ToolbarText({ text, size, className, id, headingLevel, placeholder, wrap, ellipsis, maxLines, slot, }: ToolbarTextProps): kerfjs.SafeHtml;
44
+ declare function ToolbarText({ text, size, className, id, headingLevel, placeholder, wrap, ellipsis, maxLines, fill, slot, }: ToolbarTextProps): kerfjs.SafeHtml;
39
45
 
40
46
  export { type HeadingLevel, ToolbarText, type ToolbarTextProps, type ToolbarTextSize };
@@ -1,4 +1,4 @@
1
- export { ToolbarText } from './chunk-TZ5IHWB2.js';
1
+ export { ToolbarText } from './chunk-XDKAYSVD.js';
2
2
 
3
3
 
4
4
 
package/dist/toolbar.d.ts CHANGED
@@ -1,21 +1,30 @@
1
1
  import * as kerfjs from 'kerfjs';
2
- import { D as DividerSides } from './divider-sides-BzB6rphT.js';
3
2
  import { PaneSeparatorSide } from './pane.js';
4
3
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
4
+ import { S as Sides } from './sides-BPSWde0A.js';
5
5
 
6
6
  interface ToolbarProps {
7
7
  leading?: KerfUiContent;
8
8
  center?: KerfUiContent;
9
9
  trailing?: KerfUiContent;
10
10
  label?: string;
11
- /** Physical divider edges in canonical top/right/bottom/left order. Defaults to bottom. */
12
- dividerSides?: DividerSides;
11
+ /**
12
+ * Physical divider edges in canonical top/right/bottom/left order, drawn
13
+ * always. Defaults to none: a toolbar pinned over or under scrolling content
14
+ * gets its divider from the scroll state instead — a `Pane` draws the line
15
+ * between its chrome and content while content is scrolled away beneath it,
16
+ * and `wireScrollDividers` `targets` can name a toolbar as chrome, which
17
+ * then draws its facing side the same way.
18
+ */
19
+ dividerSides?: Sides;
13
20
  /** Horizontal treatment of the center zone. Defaults to centered content. */
14
21
  centerAlign?: 'center' | 'stretch';
15
22
  /**
16
23
  * Component-owned responsive layout; applications choose the policy rather
17
24
  * than restyling toolbar internals. Under every policy the trailing zone
18
- * wraps its groups instead of clipping an action.
25
+ * wraps its groups instead of clipping an action, and the center zone keeps
26
+ * its whole content width: when the zones do not fit one row, the leading
27
+ * title truncates with an ellipsis rather than the center overlapping it.
19
28
  * - `none` keeps one row; the leading identity truncates first.
20
29
  * - `stack` stacks the zones at `responsiveAt`, wrapping stacked control
21
30
  * groups onto further rows.
@@ -40,6 +49,12 @@ interface ToolbarProps {
40
49
  /** Native named-slot assignment when composed inside a web component. */
41
50
  slot?: string;
42
51
  }
52
+ /**
53
+ * A toolbar's configuration, apart from its content: the props a composite
54
+ * that renders a `Toolbar` for the app (a Workbench or CollapsiblePanel
55
+ * toolbar) forwards, so the app configures that toolbar instead of styling it.
56
+ */
57
+ type ToolbarConfig = Pick<ToolbarProps, 'dividerSides' | 'centerAlign' | 'responsive' | 'responsiveAt' | 'safeAreaEdges'>;
43
58
  declare function Toolbar({ leading, center, trailing, label, dividerSides, centerAlign, responsive, responsiveAt, safeAreaEdges, className, slot, }: ToolbarProps): kerfjs.SafeHtml;
44
59
 
45
- export { DividerSides, Toolbar, type ToolbarProps };
60
+ export { Sides, Toolbar, type ToolbarConfig, type ToolbarProps };
package/dist/toolbar.js CHANGED
@@ -1,3 +1,3 @@
1
- export { Toolbar } from './chunk-MTM43SJO.js';
1
+ export { Toolbar } from './chunk-6YFHCLHG.js';
2
2
 
3
3
  //# sourceMappingURL=toolbar.js.map
@@ -1,4 +1,6 @@
1
1
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
2
+ import { ToolbarConfig } from './toolbar.js';
3
+ import { WorkbenchPanel } from './workbench.js';
2
4
 
3
5
  /** A reference link shown in the detail footer for the active entry. */
4
6
  interface CatalogResource {
@@ -43,6 +45,20 @@ interface CatalogBrand {
43
45
  type CatalogStageRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
44
46
  'data-catalog-stage'?: never;
45
47
  }>;
48
+ /**
49
+ * The Catalog sidebar's configuration, forwarded to its Workbench left rail.
50
+ * Everything is optional; omitted fields keep the Catalog's defaults.
51
+ */
52
+ interface CatalogSidebarConfig extends Pick<WorkbenchPanel, 'resizable' | 'separator' | 'collapseMotion' | 'presentation' | 'responsiveOverlayAt' | 'compactOverlay'> {
53
+ /**
54
+ * Sidebar width in px (default 288). With `resizable`, it is the current
55
+ * width: render the app's size signal here and hand the same signal to
56
+ * `wireCatalog`'s `sidebarSize`, which writes each committed resize to it.
57
+ */
58
+ size?: number;
59
+ /** The sidebar header toolbar's configuration (default: no divider; its pane draws one while scrolled). */
60
+ toolbar?: ToolbarConfig;
61
+ }
46
62
  interface CatalogProps {
47
63
  /**
48
64
  * The catalog's `id` (default `kui-catalog`). Its Workbench derives the
@@ -67,15 +83,32 @@ interface CatalogProps {
67
83
  toggleThemeAction?: string;
68
84
  toggleSecondaryAction?: string;
69
85
  /**
70
- * Whether the entry toolbar stays pinned above the preview (`fixed`,
71
- * default) or scrolls away with it (`scroll`).
86
+ * Whether the entry toolbar and description stay pinned above the preview
87
+ * (`fixed`), scroll away with it (`scroll`), or stay pinned while the entry
88
+ * pane is tall enough and scroll with the preview when it is short (`auto`,
89
+ * default), so a short window or large text never squeezes the preview out.
90
+ */
91
+ headerPlacement?: 'fixed' | 'scroll' | 'auto';
92
+ /**
93
+ * The same for the status and resource footer (default `auto`).
94
+ */
95
+ footerPlacement?: 'fixed' | 'scroll' | 'auto';
96
+ /**
97
+ * The sidebar's size, resizing, and overlay configuration, forwarded to the
98
+ * Workbench left rail (default: 288px, not resizable, an overlay below the
99
+ * Workbench's `narrow` breakpoint, `inset` in a compact Workbench).
100
+ */
101
+ sidebar?: CatalogSidebarConfig;
102
+ /**
103
+ * The entry toolbar's configuration (default `responsive: 'wrap'`: the entry
104
+ * title stays whole and the actions wrap below it when narrow).
72
105
  */
73
- headerPlacement?: 'fixed' | 'scroll';
106
+ mainToolbar?: ToolbarConfig;
74
107
  /**
75
- * Whether the status and resource footer stays pinned below the preview
76
- * (`fixed`, default) or scrolls with it (`scroll`).
108
+ * The resource footer toolbar's configuration (default no divider,
109
+ * `responsive: 'stack'` at `responsiveAt: 'narrow'`).
77
110
  */
78
- footerPlacement?: 'fixed' | 'scroll';
111
+ footerToolbar?: ToolbarConfig;
79
112
  className?: string;
80
113
  /** Native named-slot assignment when composed inside a web component. */
81
114
  slot?: string;