@kerfjs/ui 5.0.0-beta.97 → 5.0.0-beta.99

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 (416) hide show
  1. package/README.md +42 -1
  2. package/ai/application-ui-diagnostic-ids-v1.json +1 -0
  3. package/ai/component-catalog.json +487 -66
  4. package/ai/component-catalog.schema.json +1 -1
  5. package/ai/component-composition-rules.json +22 -2
  6. package/ai/component-composition.json +360 -33
  7. package/ai/component-composition.schema.json +1 -1
  8. package/ai/components/README.md +18 -17
  9. package/ai/components/anchored-surface.md +13 -0
  10. package/ai/components/application-tabs.md +1 -1
  11. package/ai/components/chip.md +9 -5
  12. package/ai/components/choice-chips.md +15 -8
  13. package/ai/components/collapsible-panel.md +3 -2
  14. package/ai/components/composer.md +83 -0
  15. package/ai/components/content-item.md +2 -2
  16. package/ai/components/corner-status.md +1 -1
  17. package/ai/components/document-baseline.md +3 -3
  18. package/ai/components/foundation.md +2 -2
  19. package/ai/components/layout.md +1 -1
  20. package/ai/components/list-action-row.md +5 -1
  21. package/ai/components/list-item.md +5 -1
  22. package/ai/components/list.md +19 -3
  23. package/ai/components/nav-stack.md +11 -2
  24. package/ai/components/pane.md +13 -4
  25. package/ai/components/popup-menu.md +4 -4
  26. package/ai/components/recipe-app-shell.md +3 -3
  27. package/ai/components/recipe-collapsible-sidebar.md +3 -3
  28. package/ai/components/recipe-compact-toolbar.md +1 -1
  29. package/ai/components/recipe-composer-form.md +3 -3
  30. package/ai/components/recipe-list-detail-dialog.md +2 -2
  31. package/ai/components/recipe-list-workspace-states.md +3 -3
  32. package/ai/components/recipe-loading-inspector.md +1 -1
  33. package/ai/components/recipe-navigation-sidebar.md +3 -3
  34. package/ai/components/recipe-navigation-stack.md +3 -3
  35. package/ai/components/recipe-workspace-header.md +3 -3
  36. package/ai/components/resize.md +2 -2
  37. package/ai/components/split-view.md +4 -2
  38. package/ai/components/sunken-panel.md +2 -2
  39. package/ai/components/surface-scaffold.md +15 -3
  40. package/ai/components/tab-bar.md +1 -0
  41. package/ai/components/tab-navigator.md +4 -0
  42. package/ai/components/toolbar-control-group.md +2 -0
  43. package/ai/components/toolbar-text.md +1 -0
  44. package/ai/components/toolbar.md +1 -0
  45. package/ai/components/workbench.md +1 -0
  46. package/ai/public-api-signatures-v1.md +504 -80
  47. package/ai/skill.md +41 -14
  48. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  49. package/analyzer/component-ownership.mjs +1 -1
  50. package/analyzer/index.mjs +41 -14
  51. package/dist/anchored-surface.d.ts +30 -2
  52. package/dist/anchored-surface.js +1 -1
  53. package/dist/app-tab.js +1 -1
  54. package/dist/browser/composer.js +4 -0
  55. package/dist/catalog-resources.d.ts +3 -2
  56. package/dist/catalog-resources.js +4 -4
  57. package/dist/catalog-resources.js.map +1 -1
  58. package/dist/catalog.d.ts +39 -8
  59. package/dist/catalog.js +55 -32
  60. package/dist/catalog.js.map +1 -1
  61. package/dist/chip.d.ts +41 -9
  62. package/dist/chip.js +1 -1
  63. package/dist/choice-chips.d.ts +40 -16
  64. package/dist/choice-chips.js +1 -1
  65. package/dist/chunk-34U4ANDJ.js +119 -0
  66. package/dist/chunk-34U4ANDJ.js.map +1 -0
  67. package/dist/{chunk-36TL6BCR.js → chunk-3GLYIIFR.js} +34 -6
  68. package/dist/chunk-3GLYIIFR.js.map +1 -0
  69. package/dist/{chunk-HWY4BSLS.js → chunk-3VXDSIBJ.js} +2 -2
  70. package/dist/{chunk-HWY4BSLS.js.map → chunk-3VXDSIBJ.js.map} +1 -1
  71. package/dist/chunk-3WYREXW4.js +120 -0
  72. package/dist/chunk-3WYREXW4.js.map +1 -0
  73. package/dist/chunk-AV7CPAPT.js +82 -0
  74. package/dist/chunk-AV7CPAPT.js.map +1 -0
  75. package/dist/{chunk-XK4E225T.js → chunk-B53PS2LE.js} +2 -2
  76. package/dist/{chunk-XK4E225T.js.map → chunk-B53PS2LE.js.map} +1 -1
  77. package/dist/{chunk-R42D2BAO.js → chunk-CA7LNX3J.js} +2 -2
  78. package/dist/{chunk-R42D2BAO.js.map → chunk-CA7LNX3J.js.map} +1 -1
  79. package/dist/{chunk-AYHC62OZ.js → chunk-CMETHPKR.js} +26 -29
  80. package/dist/chunk-CMETHPKR.js.map +1 -0
  81. package/dist/{chunk-Y43B6DS3.js → chunk-CVD5IZGB.js} +2 -2
  82. package/dist/{chunk-Y43B6DS3.js.map → chunk-CVD5IZGB.js.map} +1 -1
  83. package/dist/{chunk-6STQXRT4.js → chunk-CXZXHZTR.js} +121 -12
  84. package/dist/chunk-CXZXHZTR.js.map +1 -0
  85. package/dist/{chunk-GZE2XVKC.js → chunk-DZJ4GBSP.js} +3 -3
  86. package/dist/{chunk-GZE2XVKC.js.map → chunk-DZJ4GBSP.js.map} +1 -1
  87. package/dist/chunk-ELCMSQNJ.js +49 -0
  88. package/dist/chunk-ELCMSQNJ.js.map +1 -0
  89. package/dist/{chunk-P74VXMB6.js → chunk-EOO6PYGF.js} +7 -14
  90. package/dist/chunk-EOO6PYGF.js.map +1 -0
  91. package/dist/{chunk-PRG4CL3Q.js → chunk-FR76ZJQC.js} +21 -19
  92. package/dist/chunk-FR76ZJQC.js.map +1 -0
  93. package/dist/{chunk-QQ3TTWFH.js → chunk-G3J7JDP6.js} +1 -1
  94. package/dist/{chunk-QQ3TTWFH.js.map → chunk-G3J7JDP6.js.map} +1 -1
  95. package/dist/{chunk-IGTWXPTN.js → chunk-HGV7J4T6.js} +3 -3
  96. package/dist/{chunk-IGTWXPTN.js.map → chunk-HGV7J4T6.js.map} +1 -1
  97. package/dist/{chunk-YWQGSUF2.js → chunk-HLDRH23D.js} +3 -3
  98. package/dist/{chunk-YWQGSUF2.js.map → chunk-HLDRH23D.js.map} +1 -1
  99. package/dist/{chunk-PBT3CPPY.js → chunk-HQZYKJ56.js} +24 -4
  100. package/dist/chunk-HQZYKJ56.js.map +1 -0
  101. package/dist/{chunk-V6W56V3N.js → chunk-HZPHCSCS.js} +16 -3
  102. package/dist/chunk-HZPHCSCS.js.map +1 -0
  103. package/dist/{chunk-GJYQ27C2.js → chunk-INI4WDWC.js} +8 -1
  104. package/dist/chunk-INI4WDWC.js.map +1 -0
  105. package/dist/{chunk-U657IHFB.js → chunk-IQSRHXZR.js} +10 -4
  106. package/dist/chunk-IQSRHXZR.js.map +1 -0
  107. package/dist/{chunk-KQDU7Z7P.js → chunk-K4AT3V3J.js} +2 -1
  108. package/dist/chunk-K4AT3V3J.js.map +1 -0
  109. package/dist/{chunk-QIAPOWHH.js → chunk-KCS6NJ3O.js} +2 -2
  110. package/dist/{chunk-QIAPOWHH.js.map → chunk-KCS6NJ3O.js.map} +1 -1
  111. package/dist/{chunk-UKKRPP56.js → chunk-LOSRXZAH.js} +2 -2
  112. package/dist/{chunk-UKKRPP56.js.map → chunk-LOSRXZAH.js.map} +1 -1
  113. package/dist/{chunk-ROZLJULF.js → chunk-MF6ZUUJZ.js} +8 -3
  114. package/dist/chunk-MF6ZUUJZ.js.map +1 -0
  115. package/dist/{chunk-6IVNMC6R.js → chunk-MHMWQ7RB.js} +2 -2
  116. package/dist/{chunk-6IVNMC6R.js.map → chunk-MHMWQ7RB.js.map} +1 -1
  117. package/dist/{chunk-JYD7G4RG.js → chunk-PIVY32AE.js} +15 -5
  118. package/dist/chunk-PIVY32AE.js.map +1 -0
  119. package/dist/{chunk-BU23Z5HZ.js → chunk-PYBBYSZ3.js} +13 -18
  120. package/dist/chunk-PYBBYSZ3.js.map +1 -0
  121. package/dist/chunk-QDSZTQXL.js +28 -0
  122. package/dist/chunk-QDSZTQXL.js.map +1 -0
  123. package/dist/{chunk-YXOMI7ES.js → chunk-QIG4IGUP.js} +2 -2
  124. package/dist/{chunk-YXOMI7ES.js.map → chunk-QIG4IGUP.js.map} +1 -1
  125. package/dist/{chunk-6BRRUPJY.js → chunk-QROYYGWU.js} +3 -3
  126. package/dist/chunk-QROYYGWU.js.map +1 -0
  127. package/dist/{chunk-FOQK4F3L.js → chunk-RHD7RKGI.js} +28 -7
  128. package/dist/chunk-RHD7RKGI.js.map +1 -0
  129. package/dist/{chunk-BBU2SPRE.js → chunk-T4WJ5VGP.js} +4 -4
  130. package/dist/{chunk-BBU2SPRE.js.map → chunk-T4WJ5VGP.js.map} +1 -1
  131. package/dist/{chunk-6NOLL5KG.js → chunk-TGLUDQP2.js} +3 -3
  132. package/dist/{chunk-6NOLL5KG.js.map → chunk-TGLUDQP2.js.map} +1 -1
  133. package/dist/{chunk-HO6FU3G7.js → chunk-TLMMFQWM.js} +4 -4
  134. package/dist/{chunk-HO6FU3G7.js.map → chunk-TLMMFQWM.js.map} +1 -1
  135. package/dist/chunk-UMKV7YVQ.js +20 -0
  136. package/dist/chunk-UMKV7YVQ.js.map +1 -0
  137. package/dist/{chunk-M2NRCFRO.js → chunk-VFYO3UGZ.js} +2 -2
  138. package/dist/{chunk-M2NRCFRO.js.map → chunk-VFYO3UGZ.js.map} +1 -1
  139. package/dist/{chunk-YOKEL75M.js → chunk-WVS6CUCT.js} +2 -2
  140. package/dist/{chunk-YOKEL75M.js.map → chunk-WVS6CUCT.js.map} +1 -1
  141. package/dist/{chunk-MN3POJFN.js → chunk-YMUIQRWK.js} +2 -2
  142. package/dist/{chunk-MN3POJFN.js.map → chunk-YMUIQRWK.js.map} +1 -1
  143. package/dist/{chunk-Y3LC7JQO.js → chunk-YOA5W5ZH.js} +2 -2
  144. package/dist/{chunk-Y3LC7JQO.js.map → chunk-YOA5W5ZH.js.map} +1 -1
  145. package/dist/{chunk-44A6LP54.js → chunk-YQ2AC4E2.js} +2 -2
  146. package/dist/{chunk-44A6LP54.js.map → chunk-YQ2AC4E2.js.map} +1 -1
  147. package/dist/chunk-ZNROKDSZ.js +54 -0
  148. package/dist/chunk-ZNROKDSZ.js.map +1 -0
  149. package/dist/collapsible-panel.d.ts +3 -2
  150. package/dist/collapsible-panel.js +4 -3
  151. package/dist/collapsible-panel.js.map +1 -1
  152. package/dist/composer.d.ts +62 -0
  153. package/dist/composer.js +5 -0
  154. package/dist/composer.js.map +1 -0
  155. package/dist/corner-status.d.ts +1 -1
  156. package/dist/corner-status.js +1 -1
  157. package/dist/css-values.d.ts +9 -1
  158. package/dist/css-values.js +1 -1
  159. package/dist/disclosure-arrow.js +1 -1
  160. package/dist/empty-state.js +1 -1
  161. package/dist/grid.js +1 -1
  162. package/dist/icon-button.js +1 -1
  163. package/dist/icon-toggle-button.js +1 -1
  164. package/dist/index.d.ts +10 -5
  165. package/dist/index.js +40 -37
  166. package/dist/list-action-row.d.ts +10 -2
  167. package/dist/list-action-row.js +1 -1
  168. package/dist/list-header.js +1 -1
  169. package/dist/list-icon-tile-B8dr97OW.d.ts +18 -0
  170. package/dist/list-item.d.ts +10 -3
  171. package/dist/list-item.js +1 -1
  172. package/dist/list.d.ts +36 -4
  173. package/dist/list.js +1 -1
  174. package/dist/loading-spinner.js +1 -1
  175. package/dist/lucide-icon.js +1 -1
  176. package/dist/{nav-stack-BvSKY448.d.ts → nav-stack-VXTumzKa.d.ts} +53 -4
  177. package/dist/nav-stack.d.ts +3 -2
  178. package/dist/nav-stack.js +2 -1
  179. package/dist/pane.d.ts +40 -3
  180. package/dist/pane.js +1 -1
  181. package/dist/{panel-toolbar-CL9tYOkh.d.ts → panel-toolbar-vg6Ir5Dy.d.ts} +6 -1
  182. package/dist/popup-menu-register.d.ts +2 -1
  183. package/dist/popup-menu-register.js +97 -22
  184. package/dist/popup-menu-register.js.map +1 -1
  185. package/dist/popup-menu.js +1 -1
  186. package/dist/row.js +1 -1
  187. package/dist/scroll-clearance-BikHljTc.d.ts +14 -0
  188. package/dist/select-register.js +11 -0
  189. package/dist/select-register.js.map +1 -1
  190. package/dist/select.js +1 -1
  191. package/dist/skeleton.js +1 -1
  192. package/dist/spacer.js +1 -1
  193. package/dist/split-button.js +1 -1
  194. package/dist/split-view.d.ts +7 -5
  195. package/dist/split-view.js +6 -3
  196. package/dist/split-view.js.map +1 -1
  197. package/dist/state-banner.d.ts +6 -1
  198. package/dist/state-banner.js +1 -1
  199. package/dist/styles/anchored-surface.css +27 -1
  200. package/dist/styles/catalog/components/catalog-example-stack.css +5 -0
  201. package/dist/styles/catalog/components/catalog-example.css +33 -0
  202. package/dist/styles/catalog/components/catalog-stage.css +7 -0
  203. package/dist/styles/chip.css +70 -0
  204. package/dist/styles/components/actions/popup-menu/popup-menu.css +21 -4
  205. package/dist/styles/components/actions/toolbar/toolbar.css +19 -0
  206. package/dist/styles/components/actions/toolbar-control-group/toolbar-control-group.css +75 -1
  207. package/dist/styles/components/actions/toolbar-text/toolbar-text.css +75 -0
  208. package/dist/styles/components/collections/list/list.css +77 -7
  209. package/dist/styles/components/collections/list-action-row/list-action-row.css +177 -22
  210. package/dist/styles/components/collections/list-item/list-item.css +158 -11
  211. package/dist/styles/components/feedback/anchored-surface/anchored-surface.css +27 -1
  212. package/dist/styles/components/feedback/chip/chip.css +70 -0
  213. package/dist/styles/components/feedback/state-banner/state-banner.css +24 -13
  214. package/dist/styles/components/forms/composer/composer.css +100 -0
  215. package/dist/styles/components/forms/select/select.css +1 -0
  216. package/dist/styles/components/forms/token-search-field/token-search-field.css +13 -2
  217. package/dist/styles/components/layout/pane/pane.css +81 -2
  218. package/dist/styles/components/navigation/nav-stack/nav-stack.css +84 -0
  219. package/dist/styles/components/navigation/tab-bar/tab-bar.css +15 -4
  220. package/dist/styles/components/navigation/tab-navigator/tab-navigator.css +79 -4
  221. package/dist/styles/components/surfaces/surface-scaffold/surface-scaffold.css +195 -0
  222. package/dist/styles/composer.css +100 -0
  223. package/dist/styles/foundation.css +66 -0
  224. package/dist/styles/list-action-row.css +177 -22
  225. package/dist/styles/list-item.css +158 -11
  226. package/dist/styles/list.css +77 -7
  227. package/dist/styles/nav-stack.css +84 -0
  228. package/dist/styles/pane.css +81 -2
  229. package/dist/styles/popup-menu.css +21 -4
  230. package/dist/styles/select.css +1 -0
  231. package/dist/styles/state-banner.css +24 -13
  232. package/dist/styles/styles.css +1 -0
  233. package/dist/styles/surface-scaffold.css +195 -0
  234. package/dist/styles/tab-bar.css +15 -4
  235. package/dist/styles/tab-navigator.css +79 -4
  236. package/dist/styles/token-search-field.css +13 -2
  237. package/dist/styles/toolbar-control-group.css +75 -1
  238. package/dist/styles/toolbar-text.css +75 -0
  239. package/dist/styles/toolbar.css +19 -0
  240. package/dist/styles/webawesome.css +18 -0
  241. package/dist/surface-scaffold-register.d.ts +6 -1
  242. package/dist/surface-scaffold-register.js +89 -3
  243. package/dist/surface-scaffold-register.js.map +1 -1
  244. package/dist/surface-scaffold.d.ts +66 -7
  245. package/dist/surface-scaffold.js +1 -1
  246. package/dist/tab-navigator.d.ts +23 -2
  247. package/dist/tab-navigator.js +2 -0
  248. package/dist/tab-navigator.js.map +1 -1
  249. package/dist/token-search-field.d.ts +1 -1
  250. package/dist/token-search-field.js +1 -1
  251. package/dist/{token-search-model-DTcTXWMS.d.ts → token-search-model-aYR0YAei.d.ts} +32 -2
  252. package/dist/token-search-model.d.ts +1 -1
  253. package/dist/toolbar-control-group.js +1 -1
  254. package/dist/toolbar-text.js +1 -1
  255. package/dist/toolbar.d.ts +1 -0
  256. package/dist/value-table.js +1 -1
  257. package/dist/wire-catalog.d.ts +3 -2
  258. package/dist/wire-catalog.js +2 -2
  259. package/dist/wire-composers.d.ts +16 -0
  260. package/dist/wire-composers.js +3 -0
  261. package/dist/wire-composers.js.map +1 -0
  262. package/dist/wire-list-focus-scroll.d.ts +16 -0
  263. package/dist/wire-list-focus-scroll.js +3 -0
  264. package/dist/wire-list-focus-scroll.js.map +1 -0
  265. package/dist/wire-nav-stack.js +135 -0
  266. package/dist/wire-nav-stack.js.map +1 -1
  267. package/dist/wire-scroll-dividers.d.ts +9 -0
  268. package/dist/wire-scroll-dividers.js +1 -1
  269. package/dist/wire-tab-bars.js +1 -1
  270. package/dist/wire-tab-navigator.d.ts +3 -1
  271. package/dist/wire-tab-navigator.js +133 -1
  272. package/dist/wire-tab-navigator.js.map +1 -1
  273. package/dist/wire-token-search-fields.d.ts +1 -1
  274. package/dist/wire-token-search-fields.js +1 -1
  275. package/dist/workbench.d.ts +8 -3
  276. package/dist/workbench.js +2 -1
  277. package/docs/accessibility.md +132 -3
  278. package/docs/anchored-surface.md +46 -4
  279. package/docs/app-layouts.md +23 -2
  280. package/docs/apple-hig.md +1 -0
  281. package/docs/catalog.md +61 -9
  282. package/docs/collapsible-panel.md +9 -6
  283. package/docs/component-contract.md +46 -13
  284. package/docs/component-selection.md +147 -20
  285. package/docs/composer.md +143 -0
  286. package/docs/design/templates/choice-chips/multiple-dark.svg +1 -0
  287. package/docs/design/templates/choice-chips/multiple.svg +1 -0
  288. package/docs/design/templates/choice-chips-dark.svg +1 -1
  289. package/docs/design/templates/choice-chips.svg +1 -1
  290. package/docs/design/templates/composer/chat-dark.svg +1 -0
  291. package/docs/design/templates/composer/chat.svg +1 -0
  292. package/docs/design/templates/composer/prompt-dark.svg +1 -0
  293. package/docs/design/templates/composer/prompt.svg +1 -0
  294. package/docs/design/templates/composer-dark.svg +1 -0
  295. package/docs/design/templates/composer.svg +1 -0
  296. package/docs/design/templates/empty-state/filtered-dark.svg +1 -1
  297. package/docs/design/templates/empty-state/filtered.svg +1 -1
  298. package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
  299. package/docs/design/templates/empty-state/with-action.svg +1 -1
  300. package/docs/design/templates/empty-state-dark.svg +1 -1
  301. package/docs/design/templates/empty-state.svg +1 -1
  302. package/docs/design/templates/list/compact-dark.svg +1 -1
  303. package/docs/design/templates/list/compact.svg +1 -1
  304. package/docs/design/templates/list-action-row/default-dark.svg +1 -1
  305. package/docs/design/templates/list-action-row/default.svg +1 -1
  306. package/docs/design/templates/list-action-row/icon-tile-dark.svg +1 -0
  307. package/docs/design/templates/list-action-row/icon-tile.svg +1 -0
  308. package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
  309. package/docs/design/templates/list-action-row/selected.svg +1 -1
  310. package/docs/design/templates/list-action-row/trailing-menu-dark.svg +1 -1
  311. package/docs/design/templates/list-action-row/trailing-menu.svg +1 -1
  312. package/docs/design/templates/list-action-row-dark.svg +1 -1
  313. package/docs/design/templates/list-action-row.svg +1 -1
  314. package/docs/design/templates/list-dark.svg +1 -1
  315. package/docs/design/templates/list-header/size-l-dark.svg +1 -1
  316. package/docs/design/templates/list-header/size-l.svg +1 -1
  317. package/docs/design/templates/list-header/size-m-dark.svg +1 -1
  318. package/docs/design/templates/list-header/size-m.svg +1 -1
  319. package/docs/design/templates/list-header/size-xl-dark.svg +1 -1
  320. package/docs/design/templates/list-header/size-xl.svg +1 -1
  321. package/docs/design/templates/list-header-dark.svg +1 -1
  322. package/docs/design/templates/list-header.svg +1 -1
  323. package/docs/design/templates/list-item/icon-tile-dark.svg +1 -0
  324. package/docs/design/templates/list-item/icon-tile.svg +1 -0
  325. package/docs/design/templates/list-item/selected-dark.svg +1 -1
  326. package/docs/design/templates/list-item/selected.svg +1 -1
  327. package/docs/design/templates/list-item-dark.svg +1 -1
  328. package/docs/design/templates/list-item.svg +1 -1
  329. package/docs/design/templates/list.svg +1 -1
  330. package/docs/design/templates/segmented-control-dark.svg +1 -1
  331. package/docs/design/templates/segmented-control.svg +1 -1
  332. package/docs/design/templates/skeleton-dark.svg +1 -1
  333. package/docs/design/templates/skeleton.svg +1 -1
  334. package/docs/design/templates/state-banner/danger-dark.svg +1 -1
  335. package/docs/design/templates/state-banner/danger.svg +1 -1
  336. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -1
  337. package/docs/design/templates/state-banner/info-badge.svg +1 -1
  338. package/docs/design/templates/state-banner/info-dark.svg +1 -1
  339. package/docs/design/templates/state-banner/info.svg +1 -1
  340. package/docs/design/templates/state-banner/strip-dark.svg +1 -1
  341. package/docs/design/templates/state-banner/strip.svg +1 -1
  342. package/docs/design/templates/state-banner/success-dark.svg +1 -1
  343. package/docs/design/templates/state-banner/success.svg +1 -1
  344. package/docs/design/templates/state-banner/warning-dark.svg +1 -1
  345. package/docs/design/templates/state-banner/warning.svg +1 -1
  346. package/docs/design/templates/state-banner-dark.svg +1 -1
  347. package/docs/design/templates/state-banner.svg +1 -1
  348. package/docs/design/templates/tab-bar-dark.svg +1 -1
  349. package/docs/design/templates/tab-bar.svg +1 -1
  350. package/docs/design/templates/token-search-field-dark.svg +1 -1
  351. package/docs/design/templates/token-search-field.svg +1 -1
  352. package/docs/design/templates/toolbar-control-group-dark.svg +1 -1
  353. package/docs/design/templates/toolbar-control-group.svg +1 -1
  354. package/docs/design/templates/toolbar-dark.svg +1 -1
  355. package/docs/design/templates/toolbar-text/default-dark.svg +1 -1
  356. package/docs/design/templates/toolbar-text/default.svg +1 -1
  357. package/docs/design/templates/toolbar-text/large-dark.svg +1 -1
  358. package/docs/design/templates/toolbar-text/large.svg +1 -1
  359. package/docs/design/templates/toolbar-text-dark.svg +1 -1
  360. package/docs/design/templates/toolbar-text.svg +1 -1
  361. package/docs/design/templates/toolbar.svg +1 -1
  362. package/docs/design/templates/value-table/details-dark.svg +1 -1
  363. package/docs/design/templates/value-table/details.svg +1 -1
  364. package/docs/design/templates/value-table-dark.svg +1 -1
  365. package/docs/design/templates/value-table.svg +1 -1
  366. package/docs/design-philosophy.md +9 -1
  367. package/docs/examples/command-palette-adapter.tsx +3 -3
  368. package/docs/layout.md +147 -14
  369. package/docs/nav-stack.md +132 -8
  370. package/docs/recipes.md +9 -9
  371. package/docs/split-view.md +3 -3
  372. package/docs/sunken-panel.md +2 -2
  373. package/docs/surface-scaffold.md +138 -7
  374. package/docs/tab-navigator.md +38 -1
  375. package/docs/type-contracts.md +16 -16
  376. package/docs/ui-analyzer.md +3 -1
  377. package/docs/ui-doctor.md +71 -0
  378. package/docs/ux-demo.md +6 -6
  379. package/docs/webawesome-theme.md +7 -0
  380. package/docs/workbench.md +10 -6
  381. package/docs/writing.md +152 -0
  382. package/doctor/copy-capitalization-checks.mjs +591 -0
  383. package/doctor/index.mjs +17 -8
  384. package/llms.txt +105 -11
  385. package/package.json +15 -1
  386. package/ux-demo/recipes/app-shell.tsx +11 -11
  387. package/ux-demo/recipes/collapsible-sidebar.tsx +12 -11
  388. package/ux-demo/recipes/compact-toolbar.tsx +10 -10
  389. package/ux-demo/recipes/composer-form.tsx +8 -8
  390. package/ux-demo/recipes/list-detail-dialog.tsx +13 -13
  391. package/ux-demo/recipes/list-workspace-states.tsx +13 -13
  392. package/ux-demo/recipes/loading-inspector.tsx +10 -10
  393. package/ux-demo/recipes/navigation-sidebar.tsx +7 -7
  394. package/ux-demo/recipes/navigation-stack.tsx +5 -5
  395. package/ux-demo/recipes/workspace-header.tsx +5 -5
  396. package/dist/chunk-36TL6BCR.js.map +0 -1
  397. package/dist/chunk-4LOK4634.js +0 -21
  398. package/dist/chunk-4LOK4634.js.map +0 -1
  399. package/dist/chunk-6BRRUPJY.js.map +0 -1
  400. package/dist/chunk-6STQXRT4.js.map +0 -1
  401. package/dist/chunk-76PWEN5Y.js +0 -64
  402. package/dist/chunk-76PWEN5Y.js.map +0 -1
  403. package/dist/chunk-AYHC62OZ.js.map +0 -1
  404. package/dist/chunk-BU23Z5HZ.js.map +0 -1
  405. package/dist/chunk-DQDTZE4W.js +0 -70
  406. package/dist/chunk-DQDTZE4W.js.map +0 -1
  407. package/dist/chunk-FOQK4F3L.js.map +0 -1
  408. package/dist/chunk-GJYQ27C2.js.map +0 -1
  409. package/dist/chunk-JYD7G4RG.js.map +0 -1
  410. package/dist/chunk-KQDU7Z7P.js.map +0 -1
  411. package/dist/chunk-P74VXMB6.js.map +0 -1
  412. package/dist/chunk-PBT3CPPY.js.map +0 -1
  413. package/dist/chunk-PRG4CL3Q.js.map +0 -1
  414. package/dist/chunk-ROZLJULF.js.map +0 -1
  415. package/dist/chunk-U657IHFB.js.map +0 -1
  416. package/dist/chunk-V6W56V3N.js.map +0 -1
@@ -84,34 +84,39 @@
84
84
  "category": "Foundation",
85
85
  "kind": "component",
86
86
  "source": "kerf",
87
- "description": "A short tag with semantic tone and an optional accessible remove button, including compact and disabled variants.",
87
+ "description": "A short tag with semantic or inherited tone, an optional accessible remove button, or a native link and download form, including compact and disabled variants.",
88
88
  "uses": [],
89
- "purpose": "Render removable tags without application rules on Web Awesome internals.",
89
+ "purpose": "Render removable tags and file or link chips without application rules on Web Awesome internals or anchor chrome.",
90
90
  "publicExports": [
91
91
  "Chip"
92
92
  ],
93
93
  "useWhen": [
94
- "Show a short tag that the application can remove through a delegated action, including a compact or disabled tag."
94
+ "Show a short tag that the application can remove through a delegated action, including a compact or disabled tag.",
95
+ "Show a downloadable file or a short link with chip geometry, such as the referenced files of a chat message; set tone inherit inside a brand-loud or neutral ContentItem bubble."
95
96
  ],
96
97
  "avoidWhen": [
97
98
  "Use Badge for non-interactive status and count metadata.",
98
- "Do not use the remove button without a specific accessible name."
99
+ "Do not use the remove button without a specific accessible name.",
100
+ "Use ListItemLink for a navigation row and ToolbarActionLink for a toolbar link."
99
101
  ],
100
102
  "alternatives": [],
101
103
  "appOwns": [
102
104
  "tag text and identity",
103
105
  "remove action and list update",
106
+ "link destination and download file name",
104
107
  "disabled policy"
105
108
  ],
106
109
  "variants": [
107
- "neutral, info, pop, success, warning, or danger tone",
110
+ "neutral, info, pop, success, warning, danger, or inherit tone",
108
111
  "quiet, solid, or outline appearance",
109
112
  "pill or rounded shape",
110
113
  "compact or default size",
111
- "removable or plain, enabled or disabled"
114
+ "removable, link, or plain, enabled or disabled"
112
115
  ],
113
116
  "accessibility": [
114
117
  "The remove control is a native button and requires an action and a specific removeLabel. A disabled chip disables that button and removes it from keyboard interaction.",
118
+ "A link chip is a native anchor named by its visible label; external adds a safe rel, a new tab, and an \"(opens in new tab)\" name suffix, and a disabled link chip drops its destination and leaves the tab order.",
119
+ "The inherit tone paints no fill, so its label keeps the surrounding text contrast, and its focus ring follows the surrounding foreground.",
115
120
  "Keep meaningful tag text visible because tone is supplementary."
116
121
  ],
117
122
  "geometry": {
@@ -314,7 +319,7 @@
314
319
  },
315
320
  {
316
321
  "id": "foundation",
317
- "name": "Foundation tokens",
322
+ "name": "Foundation Tokens",
318
323
  "category": "Foundation",
319
324
  "kind": "composition",
320
325
  "source": "kerf",
@@ -404,6 +409,9 @@
404
409
  "--kui-color-surface-lowered",
405
410
  "--kui-sunken-texture",
406
411
  "--kui-sunken-surface",
412
+ "--kui-chrome-material",
413
+ "--kui-chrome-material-raised",
414
+ "--kui-chrome-material-filter",
407
415
  "--kui-color-text",
408
416
  "--kui-color-text-quiet",
409
417
  "--kui-color-text-link",
@@ -478,7 +486,7 @@
478
486
  },
479
487
  {
480
488
  "id": "document-baseline",
481
- "name": "Document baseline",
489
+ "name": "Document Baseline",
482
490
  "category": "Foundation",
483
491
  "kind": "composition",
484
492
  "source": "kerf",
@@ -544,7 +552,7 @@
544
552
  },
545
553
  {
546
554
  "id": "layout",
547
- "name": "Application layout",
555
+ "name": "Application Layout",
548
556
  "category": "Foundation",
549
557
  "kind": "composition",
550
558
  "source": "kerf",
@@ -638,11 +646,14 @@
638
646
  "Pinned chrome needs a divider from the scrolling content only while content is scrolled beneath it (wireScrollDividers).",
639
647
  "A lowered background must cover the scrolling work viewport and blank space after short content without a second scroll container (appearance: sunken).",
640
648
  "A child table or other component needs edge-to-edge decoration with text aligned to other pane content.",
641
- "An opaque edge-to-edge child needs a reserved vertical scrollbar gutter."
649
+ "An opaque edge-to-edge child needs a reserved vertical scrollbar gutter.",
650
+ "Scrolling content must pass beneath chrome laid over the pane edge (a DialogSurface floating footer) while its first and last items still rest clear of it (scrollClearance).",
651
+ "The header should float over the scrolling content on a translucent material so content scrolls visibly beneath it, with the first item still resting below the header (headerPresentation: overlay, measured by wireScrollDividers)."
642
652
  ],
643
653
  "avoidWhen": [
644
654
  "Do not use Pane as a padded card or add a competing scroll owner around its content slot.",
645
- "Do not enable separators merely as decoration; use them only where the pane owns a real boundary."
655
+ "Do not enable separators merely as decoration; use them only where the pane owns a real boundary.",
656
+ "A ToolbarText description in an overlay header is fine: an untoned ToolbarText there takes the normal text color for its title and lifts its description halfway toward it, keeping AA over the content passing beneath. Do not put other quiet secondary text in an overlay header; keep it in the content."
646
657
  ],
647
658
  "alternatives": [
648
659
  {
@@ -661,7 +672,9 @@
661
672
  "whether the chrome dividers follow the scroll, always show, or never show (chromeDividers)",
662
673
  "default or sunken scrolling work surface (appearance)",
663
674
  "whether to reserve a vertical scrollbar gutter for opaque edge-to-edge content (--kui-pane-scrollbar-gutter)",
664
- "optional keyboard or programmatic focus (tabIndex) and persistent focus outline (outlined)"
675
+ "optional keyboard or programmatic focus (tabIndex) and persistent focus outline (outlined)",
676
+ "whether the scrolling content clears overlaying chrome on its block edges (scrollClearance, also in PaneConfig, so a Workbench mainPane or panel pane, a CollapsiblePanel pane, or a NavStack view pane forwards it)",
677
+ "whether the header is docked in its own row or laid over the scrolling content on the translucent chrome material (headerPresentation, also in PaneConfig)"
665
678
  ],
666
679
  "variants": [
667
680
  "content only",
@@ -672,11 +685,14 @@
672
685
  "inline-start separator",
673
686
  "inline-end separator",
674
687
  "chrome dividers only while scrolled (default, wired by wireScrollDividers)",
675
- "always or no chrome dividers"
688
+ "always or no chrome dividers",
689
+ "scrollClearance block-start, block-end, or both on the scrolling content",
690
+ "overlay header on the translucent chrome material (headerPresentation: overlay)"
676
691
  ],
677
692
  "accessibility": [
678
693
  "Choose semantic root and content elements that match the region and provide labels for landmark elements.",
679
- "Keep fixed header/footer chrome outside the single scrolling content slot so reading and focus order remain coherent."
694
+ "Keep fixed header/footer chrome outside the single scrolling content slot so reading and focus order remain coherent.",
695
+ "An overlay header's text uses the normal text color, which keeps WCAG AA over the 80% chrome material on any content; the material turns opaque under prefers-reduced-transparency, prefers-contrast: more, forced colors, or without backdrop-filter."
680
696
  ],
681
697
  "geometry": {
682
698
  "margin": "child",
@@ -687,7 +703,9 @@
687
703
  "Safe areas: the root and separators paint through unsafe areas while header, content, and footer pad the sides the pane still reaches (routed by --kui-edge-inset-*); content block insets are scroll padding.",
688
704
  "The scrolling content exposes its resolved logical inline padding to descendants as --kui-pane-content-inset-inline-start/end, including safe areas and deepInset.",
689
705
  "deepInset adds --kui-space-xs to every side of the scrolling content and its block scroll padding; header/footer chrome still owns safe-area padding at its edge.",
690
- "For opaque edge-to-edge children, --kui-pane-scrollbar-gutter: stable reserves a vertical scrollbar gutter outside the published content insets; the default is auto."
706
+ "For opaque edge-to-edge children, --kui-pane-scrollbar-gutter: stable reserves a vertical scrollbar gutter outside the published content insets; the default is auto.",
707
+ "scrollClearance adds the inherited --kui-scroll-clearance-block-start/end context, published by overlaying chrome, to the scrolling content block padding and scroll padding alongside safe areas and deepInset.",
708
+ "headerPresentation overlay: once wireScrollDividers measures the header, the header shares the content cell above the scroller, its border-box height is published as --kui-scroll-clearance-block-start on the Pane root, and the content clears it automatically; unwired or with chromePlacement auto, the header stays docked."
691
709
  ]
692
710
  },
693
711
  "delivery": {
@@ -712,6 +730,11 @@
712
730
  "name": "data-scroll-divider",
713
731
  "on": "kui-pane__header and kui-pane__footer",
714
732
  "meaning": "The sides, in t/r/b/l order, on which this chrome currently draws its scroll divider: the side facing the scroller while content is hidden beyond it. Re-applied if a re-render drops it."
733
+ },
734
+ {
735
+ "name": "data-header-overlay",
736
+ "on": "kui-pane",
737
+ "meaning": "measured once the wiring has measured an overlay header (headerPresentation: overlay) and published its border-box height as --kui-scroll-clearance-block-start on the Pane root (and a classic content scrollbar's inline size as --kui-pane-scrollbar-inline-size, which the header leaves uncovered); the header then lies over the content, which clears it. Both are re-applied if a re-render drops them."
715
738
  }
716
739
  ]
717
740
  }
@@ -734,7 +757,10 @@
734
757
  "--kui-pane-content-inset-inline-start",
735
758
  "--kui-pane-content-inset-inline-end",
736
759
  "--kui-pane-scrollbar-gutter",
737
- "--kui-sunken-panel-background"
760
+ "--kui-sunken-panel-background",
761
+ "--kui-chrome-material",
762
+ "--kui-chrome-material-filter",
763
+ "--kui-scroll-clearance-block-start"
738
764
  ],
739
765
  "links": {
740
766
  "catalogRoute": "?component=pane",
@@ -759,6 +785,8 @@
759
785
  "NavStackView",
760
786
  "NavStackToolbarConfig",
761
787
  "NavStackProps",
788
+ "NavStackChromePresentation",
789
+ "NavStackBottomToolbarPresentation",
762
790
  "NavStack"
763
791
  ],
764
792
  "useWhen": [
@@ -795,7 +823,9 @@
795
823
  "per-view leading, center, and trailing top-toolbar groups",
796
824
  "per-view header and footer with List and Pane configuration",
797
825
  "top-toolbar defaults, title size, and heading level",
798
- "whether the chrome and bottom-toolbar dividers follow the scroll, always show, or never show (chromeDividers)"
826
+ "whether the chrome and bottom-toolbar dividers follow the scroll, always show, or never show (chromeDividers)",
827
+ "whether the top chrome docks above the active view or lies over it on the translucent chrome material (chromePresentation)",
828
+ "whether the bottom toolbar docks below the active view or lies over it on the translucent chrome material (bottomToolbarPresentation)"
799
829
  ],
800
830
  "variants": [
801
831
  "single root view",
@@ -807,13 +837,17 @@
807
837
  "persistent final top-toolbar group (panelToggle) when embedded in a Workbench panel",
808
838
  "persistent bottom-toolbar fallback",
809
839
  "chrome and bottom-toolbar dividers only while the active view scrolls beneath them (wired by wireScrollDividers)",
810
- "permanent or no chrome dividers (chromeDividers always or none)"
840
+ "permanent or no chrome dividers (chromeDividers always or none)",
841
+ "translucent top chrome laid over the active view (chromePresentation overlay, measured by wireNavStack)",
842
+ "translucent bottom toolbar laid over the active view (bottomToolbarPresentation overlay, measured by wireNavStack)"
811
843
  ],
812
844
  "accessibility": [
813
845
  "Give the stack region an accessible label and every back control a stable action label; visible backText names the control itself.",
814
846
  "Set toolbarConfig.headingLevel when the view title is the page's or section's heading landmark.",
815
847
  "Use wireNavStack so each controlled push moves focus into the new top view and each pop restores the revealed view's remembered descendant.",
816
- "Mark a preferred initial heading or control with data-nav-focus when the first enabled focusable descendant is not the right target."
848
+ "Mark a preferred initial heading or control with data-nav-focus when the first enabled focusable descendant is not the right target.",
849
+ "Overlay chrome (chromePresentation overlay) keeps WCAG AA over content passing beneath the translucent material: an untoned ToolbarText there takes the normal text color for its title and lifts its description halfway toward it; keep other quiet copy in the view. The material turns opaque under reduced transparency, increased contrast, forced colors, or without backdrop-filter.",
850
+ "An overlay bottom toolbar (bottomToolbarPresentation overlay) keeps the same AA rule: an untoned ToolbarText there lifts its title and description, and a default-tone ToolbarControlGroup in either overlaid bar takes the normal text color for its controls. Its 1px top edge stays visible in forced colors."
817
851
  ],
818
852
  "geometry": {
819
853
  "margin": "none",
@@ -821,7 +855,9 @@
821
855
  "padding": "child",
822
856
  "notes": [
823
857
  "The stack owns its full-height chrome and viewport; each view owns its internal content padding and scrollable content.",
824
- "The top chrome's bottom line and the bottom toolbar's top line are scroll state (wireScrollDividers), drawn as an overlaid 1px pseudo-element on the chrome and the bottom toolbar's always-present 1px top border, so neither moves the chrome or the content."
858
+ "The top chrome's bottom line and the bottom toolbar's top line are scroll state (wireScrollDividers), drawn as an overlaid 1px pseudo-element on the chrome and the bottom toolbar's always-present 1px top border, so neither moves the chrome or the content.",
859
+ "chromePresentation overlay: once wireNavStack measures the live chrome (never a cross-fading copy), the chrome lies over the viewport's top edge and its border-box height, top safe area included, becomes the viewport's block-start --kui-edge-inset-* context, so a plain view, a sole Pane, or a nested layout pads and scroll-pads by it automatically; the chrome ends where a classic scrollbar in the active view begins, so its track stays uncovered; unwired, or with hideToolbar, the chrome stays docked.",
860
+ "bottomToolbarPresentation overlay: once wireNavStack measures the live bottom toolbar (never a cross-fading copy), the toolbar lies over the viewport's bottom edge and its border-box height, bottom safe area and divider border included, becomes the viewport's block-end --kui-edge-inset-* context, so a plain view, a sole Pane (its content, or its footer), or a nested layout pads and scroll-pads by it automatically and the last item rests just above the toolbar; it ends where a classic scrollbar in the active view begins; unwired, or while no bottom toolbar is shown, it stays docked. It is independent of chromePresentation, which governs only the top chrome."
825
861
  ]
826
862
  },
827
863
  "delivery": {
@@ -857,6 +893,16 @@
857
893
  "name": "data-nav-exiting",
858
894
  "on": "kui-nav-stack__view",
859
895
  "meaning": "\"true\" on a popped view the helper briefly re-inserts to slide it out."
896
+ },
897
+ {
898
+ "name": "data-chrome-overlay",
899
+ "on": "kui-nav-stack",
900
+ "meaning": "measured once the helper has measured an overlay chrome (chromePresentation: overlay) and published its border-box height on the stack root; the chrome then lies over the active view, which clears it through the block-start edge context. Both are re-applied if a re-render drops them."
901
+ },
902
+ {
903
+ "name": "data-bottom-toolbar-overlay",
904
+ "on": "kui-nav-stack",
905
+ "meaning": "measured once the helper has measured an overlay bottom toolbar (bottomToolbarPresentation: overlay) and published its border-box height on the stack root; the toolbar then lies over the active view, which clears it through the block-end edge context. Both are re-applied if a re-render drops them."
860
906
  }
861
907
  ]
862
908
  },
@@ -874,6 +920,11 @@
874
920
  "name": "data-scroll-divider",
875
921
  "on": "kui-nav-stack__chrome and kui-nav-stack__bottom",
876
922
  "meaning": "The sides, in t/r/b/l order, on which this chrome currently draws its scroll divider: the side facing the scroller while content is hidden beyond it. Re-applied if a re-render drops it."
923
+ },
924
+ {
925
+ "name": "data-header-overlay",
926
+ "on": "kui-pane",
927
+ "meaning": "measured once the wiring has measured a Pane's overlay header (headerPresentation: overlay) and published its border-box height as --kui-scroll-clearance-block-start on the Pane root, plus a classic content scrollbar's inline size as --kui-pane-scrollbar-inline-size, which the header leaves uncovered. Re-applied if a re-render drops it."
877
928
  }
878
929
  ]
879
930
  }
@@ -1018,6 +1069,16 @@
1018
1069
  "name": "data-nav-exiting",
1019
1070
  "on": "kui-nav-stack__view",
1020
1071
  "meaning": "\"true\" on a popped view the helper briefly re-inserts to slide it out."
1072
+ },
1073
+ {
1074
+ "name": "data-chrome-overlay",
1075
+ "on": "kui-nav-stack",
1076
+ "meaning": "measured once the helper has measured the compact stack's overlay chrome (compactStack.chromePresentation: overlay) and published its border-box height on the stack root. Re-applied if a re-render drops it."
1077
+ },
1078
+ {
1079
+ "name": "data-bottom-toolbar-overlay",
1080
+ "on": "kui-nav-stack",
1081
+ "meaning": "measured once the helper has measured the compact stack's overlay bottom toolbar (compactStack.bottomToolbarPresentation: overlay) and published its border-box height on the stack root. Re-applied if a re-render drops it."
1021
1082
  }
1022
1083
  ]
1023
1084
  }
@@ -1090,13 +1151,15 @@
1090
1151
  "one NavStack per tab",
1091
1152
  "bar divider only while the active scene continues below it (wired by wireScrollDividers)",
1092
1153
  "permanent or no bar divider (chromeDividers always or none)",
1093
- "sunken active-scene separator (separator auto or hidden)"
1154
+ "sunken active-scene separator (separator auto or hidden)",
1155
+ "translucent tab bar laid over the active scene (barPresentation overlay, measured by wireTabNavigator)"
1094
1156
  ],
1095
1157
  "accessibility": [
1096
1158
  "Give the tablist an accessible label and keep exactly the active tab in the sequential focus order.",
1097
1159
  "Wire selection through the controlled active id while leaving inactive scenes mounted and hidden.",
1098
1160
  "A focusable scene is a tabpanel named by its tab label; optional scene tabIndex applies only while active.",
1099
- "A tab badge is aria-hidden; supply badgeLabel so the tab's accessible name becomes \"<label>, <badgeLabel>\" (it defaults to the badge text). The dot form, badge: true, has no text, so its badgeLabel is required."
1161
+ "A tab badge is aria-hidden; supply badgeLabel so the tab's accessible name becomes \"<label>, <badgeLabel>\" (it defaults to the badge text). The dot form, badge: true, has no text, so its badgeLabel is required.",
1162
+ "Over the overlay bar's translucent material, unselected labels lift halfway toward --kui-color-text and the selected label mixes 40% of it into the brand color, so both keep 4.5:1 over worst-case content; the material turns opaque under reduced transparency or increased contrast and paints Canvas with a CanvasText edge in forced colors."
1100
1163
  ],
1101
1164
  "geometry": {
1102
1165
  "margin": "none",
@@ -1104,7 +1167,8 @@
1104
1167
  "padding": "self",
1105
1168
  "notes": [
1106
1169
  "The navigator owns the full-height scene region and safe-area-aware bottom bar; scene content owns its internal geometry.",
1107
- "The bar's reserved 1px top edge separates a sunken active scene or nested Pane by default; on flat surfaces it follows scroll state (wireScrollDividers). separator=hidden suppresses it."
1170
+ "The bar's reserved 1px top edge separates a sunken active scene or nested Pane by default; on flat surfaces it follows scroll state (wireScrollDividers). separator=hidden suppresses it.",
1171
+ "barPresentation=overlay: once wireTabNavigator has measured the live bar (data-bar-overlay=measured), the bar is absolutely positioned over the scenes on --kui-chrome-material and the scenes route its border-box height (bottom safe area included) as the block-end --kui-edge-inset-* context, so a plain scene pads and scroll-pads by it and a sole Pane or NavStack clears it; unwired it stays docked."
1108
1172
  ]
1109
1173
  },
1110
1174
  "delivery": {
@@ -1135,6 +1199,11 @@
1135
1199
  "name": "data-scroll-divider",
1136
1200
  "on": "kui-tab-scaffold__bar",
1137
1201
  "meaning": "The sides, in t/r/b/l order, on which this chrome currently draws its scroll divider: the side facing the scroller while content is hidden beyond it. Re-applied if a re-render drops it."
1202
+ },
1203
+ {
1204
+ "name": "data-header-overlay",
1205
+ "on": "kui-pane",
1206
+ "meaning": "measured once the wiring has measured a Pane's overlay header (headerPresentation: overlay) and published its border-box height as --kui-scroll-clearance-block-start on the Pane root, plus a classic content scrollbar's inline size as --kui-pane-scrollbar-inline-size, which the header leaves uncovered. Re-applied if a re-render drops it."
1138
1207
  }
1139
1208
  ]
1140
1209
  }
@@ -1294,6 +1363,11 @@
1294
1363
  "name": "data-scroll-divider",
1295
1364
  "on": "kui-pane__header and kui-pane__footer of each panel and work-area Pane",
1296
1365
  "meaning": "The sides, in t/r/b/l order, on which this chrome currently draws its scroll divider: the side facing the scroller while content is hidden beyond it. Re-applied if a re-render drops it."
1366
+ },
1367
+ {
1368
+ "name": "data-header-overlay",
1369
+ "on": "kui-pane",
1370
+ "meaning": "measured once the wiring has measured a Pane's overlay header (headerPresentation: overlay) and published its border-box height as --kui-scroll-clearance-block-start on the Pane root, plus a classic content scrollbar's inline size as --kui-pane-scrollbar-inline-size, which the header leaves uncovered. Re-applied if a re-render drops it."
1297
1371
  }
1298
1372
  ]
1299
1373
  }
@@ -1449,6 +1523,11 @@
1449
1523
  "name": "data-scroll-divider",
1450
1524
  "on": "kui-pane__header and kui-pane__footer of each panel and work-area Pane",
1451
1525
  "meaning": "The sides, in t/r/b/l order, on which this chrome currently draws its scroll divider: the side facing the scroller while content is hidden beyond it. Re-applied if a re-render drops it."
1526
+ },
1527
+ {
1528
+ "name": "data-header-overlay",
1529
+ "on": "kui-pane",
1530
+ "meaning": "measured once the wiring has measured a Pane's overlay header (headerPresentation: overlay) and published its border-box height as --kui-scroll-clearance-block-start on the Pane root, plus a classic content scrollbar's inline size as --kui-pane-scrollbar-inline-size, which the header leaves uncovered. Re-applied if a re-render drops it."
1452
1531
  }
1453
1532
  ]
1454
1533
  }
@@ -1634,6 +1713,11 @@
1634
1713
  "name": "data-scroll-divider",
1635
1714
  "on": "a Toolbar named as targets chrome",
1636
1715
  "meaning": "The sides, in t/r/b/l order, on which this chrome currently draws its scroll divider: the side facing the scroller while content is hidden beyond it. Re-applied if a re-render drops it."
1716
+ },
1717
+ {
1718
+ "name": "data-header-overlay",
1719
+ "on": "kui-pane",
1720
+ "meaning": "measured once the wiring has measured a Pane's overlay header (headerPresentation: overlay) and published its border-box height as --kui-scroll-clearance-block-start on the Pane root, plus a classic content scrollbar's inline size as --kui-pane-scrollbar-inline-size, which the header leaves uncovered. Re-applied if a re-render drops it."
1637
1721
  }
1638
1722
  ]
1639
1723
  },
@@ -1770,7 +1854,9 @@
1770
1854
  "accessibility": [
1771
1855
  "Name the group when its relationship is not evident from context.",
1772
1856
  "A disabled native button (disabled, or aria-disabled=\"true\" when it must stay focusable) dims to half opacity with the not-allowed cursor and no hover surface; a disabled raw wa-button paints no hover surface either. Do not add disabled styling yourself.",
1773
- "Name an icon-only button or link with aria-label, not title. Once any help-tag installer is imported (select/register, popup-menu/register, or help-tags/register), it shows an aria-hidden Web Awesome help tag repeating that name after a 500ms hover and at once on keyboard focus, hidden on a press and on Escape, and never joins aria-labelledby. A native title keeps the browser tooltip and gets no second tag."
1857
+ "Name an icon-only button or link with aria-label, not title. Once any help-tag installer is imported (select/register, popup-menu/register, or help-tags/register), it shows an aria-hidden Web Awesome help tag repeating that name after a 500ms hover and at once on keyboard focus, hidden on a press and on Escape, and never joins aria-labelledby. A native title keeps the browser tooltip and gets no second tag.",
1858
+ "In an overlay Pane header (headerPresentation=\"overlay\"), overlay NavStack chrome (chromePresentation=\"overlay\") or bottom toolbar (bottomToolbarPresentation=\"overlay\"), or a DialogSurface floating header's header-actions (headerPresentation=\"floating\"), a default-tone group (not dark-toned, not an avatar scrim) takes --kui-color-text for its controls, so they keep WCAG AA over content passing beneath the translucent chrome material.",
1859
+ "A dark-toned group's hover paints a 14% surface wash over its loud fill, on one control of a group or across a lone control's whole group, so the on-loud icon keeps at least 3:1 over a light page and well above it in dark."
1774
1860
  ],
1775
1861
  "geometry": {
1776
1862
  "margin": "none",
@@ -1913,7 +1999,7 @@
1913
1999
  },
1914
2000
  {
1915
2001
  "id": "surface-scaffold",
1916
- "name": "Surface scaffolds",
2002
+ "name": "Surface Scaffolds",
1917
2003
  "category": "Structure",
1918
2004
  "kind": "component",
1919
2005
  "source": "kerf",
@@ -1933,11 +2019,14 @@
1933
2019
  "A Web Awesome dialog or dropdown needs a standard size, presentation, body/footer inset, or list-compatible menu inset.",
1934
2020
  "A dialog body should compose rows, sections, or aligned bare prose through List and ListInsetText.",
1935
2021
  "A modal needs a typed preferred width, viewport gutter, or dynamic viewport-bounded height cap while retaining native body scrolling and footer actions.",
1936
- "A dialog that must leave the page interactive and close on Escape or an outside press uses PopoverDialogSurface; one that fills its body with a SplitView or Pane uses height and bodyLayout=\"fill\"."
2022
+ "A dialog that must leave the page interactive and close on Escape or an outside press uses PopoverDialogSurface; one that fills its body with a SplitView or Pane uses height and bodyLayout=\"fill\".",
2023
+ "A chat-style dialog floats its composer over the transcript with footerPresentation=\"floating\" and keeps a heading or notice above one scrolling transcript with bodyLayout=\"fill-last\".",
2024
+ "A dialog's title bar should float over the body on the translucent chrome material so a transcript scrolls visibly beneath both the title bar and a floating composer (headerPresentation=\"floating\" with bodyLayout=\"fill\" and a List or Pane that opts into scrollClearance=\"both\")."
1937
2025
  ],
1938
2026
  "avoidWhen": [
1939
2027
  "Do not use it as a generic layout wrapper or to replace application-owned modal state and focus lifecycle.",
1940
- "Do not stack a dialog body inset around children that already own List or content-item geometry; use bodyInset none."
2028
+ "Do not stack a dialog body inset around children that already own List or content-item geometry; use bodyInset none.",
2029
+ "Do not put quiet secondary text of your own in a floating dialog header; it can fall below AA over the content passing beneath. A ToolbarText slotted as the dialog's label (or into header-actions) is fine: its title takes the normal text color and its description lifts halfway toward it, keeping AA."
1941
2030
  ],
1942
2031
  "alternatives": [],
1943
2032
  "appOwns": [
@@ -1953,12 +2042,20 @@
1953
2042
  "modal, side-sheet, or fullscreen dialog",
1954
2043
  "typed modal preferred width, viewport gutter, and maximum height, including viewport cap",
1955
2044
  "definite viewport-bounded modal height and a fill body layout for one child",
1956
- "non-modal light-dismiss PopoverDialogSurface, overlay or embedded in flow",
2045
+ "fill-last body layout: fixed rows above one filling, scrolling last child",
2046
+ "docked or floating footer with a typed footerOffset; the body reserves the measured footer height",
2047
+ "floating footer over a filling child that opts into block-end scrollClearance: content scrolls beneath the footer through the published --kui-scroll-clearance-block-end",
2048
+ "docked or floating header (headerPresentation) on the translucent chrome material; the body reserves the measured header height",
2049
+ "floating header over a filling only child that opts into block-start scrollClearance: content scrolls beneath the title bar through the published --kui-scroll-clearance-block-start",
2050
+ "floating header divider as scroll state: a hairline under the title bar only while the body or a filling child beneath it is scrolled away from its top",
2051
+ "non-modal light-dismiss PopoverDialogSurface, overlay or embedded in flow, named by label or labelledBy and described by describedBy",
1957
2052
  "none, compact, or comfortable body and footer inset",
1958
2053
  "standard, compact, or zero-inset popup menu"
1959
2054
  ],
1960
2055
  "accessibility": [
1961
2056
  "Supply the wrapped wa-dialog label and retain Web Awesome's native modal and focus behavior.",
2057
+ "Name a PopoverDialogSurface with label or labelledBy, and describe it with describedBy (rendered as aria-describedby), usually a title ToolbarText descriptionId.",
2058
+ "A floating header's title uses the normal text color, which keeps WCAG AA over the 80% raised chrome material on any content; the material turns opaque under prefers-reduced-transparency, prefers-contrast: more, forced colors, or without backdrop-filter.",
1962
2059
  "Use popup surfaces only for real dropdown menus with named triggers."
1963
2060
  ],
1964
2061
  "geometry": {
@@ -1984,7 +2081,11 @@
1984
2081
  "publicTokens": [
1985
2082
  "--kui-radius-l",
1986
2083
  "--kui-wa-container-inset",
1987
- "--kui-wa-surface-inset"
2084
+ "--kui-wa-surface-inset",
2085
+ "--kui-chrome-material-raised",
2086
+ "--kui-chrome-material-filter",
2087
+ "--kui-scroll-clearance-block-start",
2088
+ "--kui-scroll-clearance-block-end"
1988
2089
  ],
1989
2090
  "links": {
1990
2091
  "catalogRoute": "?component=surface-scaffold",
@@ -2040,6 +2141,30 @@
2040
2141
  "viewportGutter={remify(8)}"
2041
2142
  ]
2042
2143
  },
2144
+ {
2145
+ "path": "footerOffset",
2146
+ "grammar": "length",
2147
+ "helpers": [
2148
+ "px",
2149
+ "rem",
2150
+ "remify",
2151
+ "em",
2152
+ "pct",
2153
+ "space",
2154
+ "lengthVar",
2155
+ "calc"
2156
+ ],
2157
+ "nonStandaloneHelpers": [
2158
+ "plus"
2159
+ ],
2160
+ "shorthands": [],
2161
+ "canonicalShorthands": [],
2162
+ "exceptionalShorthands": [],
2163
+ "rawPolicy": "forbid",
2164
+ "examples": [
2165
+ "footerOffset={remify(8)}"
2166
+ ]
2167
+ },
2043
2168
  {
2044
2169
  "path": "maxHeight",
2045
2170
  "grammar": "length",
@@ -2222,7 +2347,8 @@
2222
2347
  ],
2223
2348
  "accessibility": [
2224
2349
  "Plain text is not a heading; pass headingLevel to expose role=heading + aria-level for a page/section title.",
2225
- "Actionable text is a native button with its full text as its accessible name; action cannot be combined with headingLevel, placeholder, or wrap."
2350
+ "Actionable text is a native button with its full text as its accessible name; action cannot be combined with headingLevel, placeholder, or wrap.",
2351
+ "In a Pane header with headerPresentation=\"overlay\" or NavStack chrome with chromePresentation=\"overlay\" (or its bottom toolbar with bottomToolbarPresentation=\"overlay\"), or slotted as the label (or into header-actions) of a DialogSurface header with headerPresentation=\"floating\", untoned text keeps WCAG AA over the translucent chrome material: the title takes --kui-color-text at every size and the description mixes --kui-color-text-quiet halfway toward it."
2226
2352
  ],
2227
2353
  "geometry": {
2228
2354
  "margin": "none",
@@ -3416,7 +3542,8 @@
3416
3542
  "lengthVar",
3417
3543
  "plus",
3418
3544
  "calc",
3419
- "flex"
3545
+ "flex",
3546
+ "wireListFocusScroll"
3420
3547
  ],
3421
3548
  "publicExportImports": {
3422
3549
  "px": "@kerfjs/ui/css-values",
@@ -3427,7 +3554,8 @@
3427
3554
  "lengthVar": "@kerfjs/ui/css-values",
3428
3555
  "plus": "@kerfjs/ui/css-values",
3429
3556
  "calc": "@kerfjs/ui/css-values",
3430
- "flex": "@kerfjs/ui/css-values"
3557
+ "flex": "@kerfjs/ui/css-values",
3558
+ "wireListFocusScroll": "@kerfjs/ui/wire-list-focus-scroll"
3431
3559
  },
3432
3560
  "cssValueProps": [
3433
3561
  {
@@ -3495,6 +3623,52 @@
3495
3623
  "flex=\"none\"",
3496
3624
  "flex={flex(1, 1, rem(20))}"
3497
3625
  ]
3626
+ },
3627
+ {
3628
+ "path": "maxHeight",
3629
+ "grammar": "length",
3630
+ "helpers": [
3631
+ "px",
3632
+ "rem",
3633
+ "em",
3634
+ "pct",
3635
+ "space",
3636
+ "lengthVar",
3637
+ "calc"
3638
+ ],
3639
+ "nonStandaloneHelpers": [
3640
+ "plus"
3641
+ ],
3642
+ "shorthands": [],
3643
+ "canonicalShorthands": [],
3644
+ "exceptionalShorthands": [],
3645
+ "rawPolicy": "forbid",
3646
+ "examples": [
3647
+ "maxHeight={rem(14)}"
3648
+ ]
3649
+ },
3650
+ {
3651
+ "path": "minHeight",
3652
+ "grammar": "length",
3653
+ "helpers": [
3654
+ "px",
3655
+ "rem",
3656
+ "em",
3657
+ "pct",
3658
+ "space",
3659
+ "lengthVar",
3660
+ "calc"
3661
+ ],
3662
+ "nonStandaloneHelpers": [
3663
+ "plus"
3664
+ ],
3665
+ "shorthands": [],
3666
+ "canonicalShorthands": [],
3667
+ "exceptionalShorthands": [],
3668
+ "rawPolicy": "forbid",
3669
+ "examples": [
3670
+ "minHeight={rem(4.25)}"
3671
+ ]
3498
3672
  }
3499
3673
  ],
3500
3674
  "useWhen": [
@@ -3504,7 +3678,10 @@
3504
3678
  "Use a finite flex keyword or the flex() builder when List participates in flexible layout.",
3505
3679
  "Apply the standard text or control inset to selected physical sides without an application wrapper.",
3506
3680
  "Align children horizontally or distribute them vertically with the same physical alignment vocabulary as Row.",
3507
- "Use selectionMode=\"multiple\" and ariaLabel to group selectable rich ContentItem rows in a multi-select grid."
3681
+ "Use selectionMode=\"multiple\" and ariaLabel to group selectable rich ContentItem rows in a multi-select grid.",
3682
+ "Use scrollClearance on the scrollable List that reaches an edge overlaid by chrome (a DialogSurface floating footer) so rows scroll visibly beneath it while the first and last rows still rest clear of it.",
3683
+ "Render a bounded, framed result picker of ListItem rows (search results, duplicate candidates) with scrollable, frame, and typed maxHeight/minHeight instead of an app-owned bordered scroller.",
3684
+ "Call wireListFocusScroll(root) once when keyboard users move focus through a scrollable List's rows, so Firefox and Safari bring a partly hidden focused row and its ring fully into view as Chromium does."
3508
3685
  ],
3509
3686
  "avoidWhen": [
3510
3687
  "Do not use List as semantic list markup; use ul/ol when list semantics are required and apply layout deliberately.",
@@ -3516,7 +3693,9 @@
3516
3693
  "child semantics and content",
3517
3694
  "the bounded height needed for scrolling",
3518
3695
  "typed gap, flex, alignment, and divider choices",
3519
- "the accessible label and selection state of a multi-select grid"
3696
+ "the accessible label and selection state of a multi-select grid",
3697
+ "which one scroller opts into scroll clearance (the one reaching the covered edge)",
3698
+ "the result picker bounds (maxHeight/minHeight) and its rows"
3520
3699
  ],
3521
3700
  "variants": [
3522
3701
  "no gap",
@@ -3525,6 +3704,9 @@
3525
3704
  "typed CssLength gap",
3526
3705
  "boolean, finite-keyword, or typed CssFlex flex",
3527
3706
  "scrollable",
3707
+ "scrollClearance block-start, block-end, or both: clears overlaying chrome inside the scroll area",
3708
+ "frame: 1px neutral border, control radius, and a 4px focus-ring-safe inset",
3709
+ "typed CssLength maxHeight and minHeight bounds",
3528
3710
  "base or raised solid surface",
3529
3711
  "document reading inset",
3530
3712
  "left/center/right/full horizontal alignment",
@@ -3539,14 +3721,19 @@
3539
3721
  "accessibility": [
3540
3722
  "List adds layout only and no list role by default; selectionMode=\"multiple\" makes it an aria-multiselectable grid with a required ariaLabel for selectable ContentItem rows.",
3541
3723
  "Give a scrollable List a bounded block size and keep keyboard focus visible as its contents scroll.",
3542
- "A focused scrollable List (a keyboard-focusable scroller) draws the theme focus ring inset and rounded inside its own box, so a rounded or clipping parent never cuts it off; do not restyle its focus."
3724
+ "A focused scrollable List (a keyboard-focusable scroller) draws the theme focus ring inset and rounded inside its own box, so a rounded or clipping parent never cuts it off; do not restyle its focus.",
3725
+ "With wireListFocusScroll, a keyboard-focused (:focus-visible) element in a scrollable List whose focus ring crosses the clip is scrolled into view (block and inline nearest, honoring the ring-room scroll padding) in every engine; pointer focus never scrolls, so a click cannot move its row from under the pointer."
3543
3726
  ],
3544
3727
  "geometry": {
3545
3728
  "margin": "none",
3546
3729
  "border": "conditional",
3547
3730
  "padding": "conditional",
3548
3731
  "notes": [
3549
- "List adds no margin. dividerSides draws selected physical edges without changing geometry; textInsets adds the full 17px content inset and controlInsets adds 8px on selected sides, with text winning on overlap."
3732
+ "List adds no margin. dividerSides draws selected physical edges without changing geometry; textInsets adds the full 17px content inset and controlInsets adds 8px on selected sides, with text winning on overlap.",
3733
+ "scrollClearance adds the inherited --kui-scroll-clearance-block-start/end context, published by overlaying chrome, to the List block padding and scroll-padding on the opted-in edges; without it the context is ignored.",
3734
+ "frame draws a 1px --kui-color-neutral-border-normal border with --kui-radius-m and a 4px --kui-space-2xs inset on every side (replacing inset/textInsets/controlInsets), exactly the focus-ring reach, so the first and last rows' rings stay inside the clip at the scroll extremes; maxHeight/minHeight bound the List directly.",
3735
+ "Every scrollable List's block scroll padding is the focus-ring reach plus 2px of slack (6px, no change at rest), so any row focused or scrolled into view stops with its ring inside the clip; an unframed List's first and last rows still meet the clip at the scroll extremes, so use frame when they must show a whole ring.",
3736
+ "As a direct child of a Pane's scrolling content, a List that does not scroll itself never shrinks below its rows (flex-shrink 0), so the content's block-end padding (a bottom safe area, an overlay NavStack bottom toolbar's clearance) follows its last row."
3550
3737
  ]
3551
3738
  },
3552
3739
  "delivery": {
@@ -3571,8 +3758,18 @@
3571
3758
  "name": "data-scroll-divider",
3572
3759
  "on": "a List named as targets chrome",
3573
3760
  "meaning": "The sides, in t/r/b/l order, on which this chrome currently draws its scroll divider: the side facing the scroller while content is hidden beyond it. Re-applied if a re-render drops it."
3761
+ },
3762
+ {
3763
+ "name": "data-header-overlay",
3764
+ "on": "kui-pane",
3765
+ "meaning": "measured once the wiring has measured a Pane's overlay header (headerPresentation: overlay) and published its border-box height as --kui-scroll-clearance-block-start on the Pane root, plus a classic content scrollbar's inline size as --kui-pane-scrollbar-inline-size, which the header leaves uncovered. Re-applied if a re-render drops it."
3574
3766
  }
3575
3767
  ]
3768
+ },
3769
+ {
3770
+ "export": "wireListFocusScroll",
3771
+ "import": "@kerfjs/ui/wire-list-focus-scroll",
3772
+ "required": false
3576
3773
  }
3577
3774
  ],
3578
3775
  "publicClasses": [
@@ -3723,11 +3920,48 @@
3723
3920
  "examples": [
3724
3921
  "className=\"app-row\""
3725
3922
  ]
3923
+ },
3924
+ {
3925
+ "path": "iconTile.color",
3926
+ "grammar": "color",
3927
+ "helpers": [
3928
+ "fillColor",
3929
+ "uiColor",
3930
+ "colorVar"
3931
+ ],
3932
+ "shorthands": [],
3933
+ "canonicalShorthands": [],
3934
+ "exceptionalShorthands": [],
3935
+ "rawPolicy": "forbid",
3936
+ "examples": [
3937
+ "iconTile={{ color: fillColor(\"#e5484d\") }}",
3938
+ "iconTile={{ color: uiColor(\"brand-fill-loud\") }}",
3939
+ "iconTile={{ color: colorVar(\"--app-category-color\") }}"
3940
+ ]
3941
+ },
3942
+ {
3943
+ "path": "iconTile.foreground",
3944
+ "grammar": "color",
3945
+ "helpers": [
3946
+ "uiColor",
3947
+ "foregroundColorVar",
3948
+ "foregroundColor"
3949
+ ],
3950
+ "shorthands": [],
3951
+ "canonicalShorthands": [],
3952
+ "exceptionalShorthands": [],
3953
+ "rawPolicy": "forbid",
3954
+ "examples": [
3955
+ "iconTile={{ color: fillColor(\"#e5484d\"), foreground: foregroundColor(\"white\") }}",
3956
+ "iconTile={{ color: uiColor(\"brand-fill-loud\"), foreground: uiColor(\"brand-on-loud\") }}",
3957
+ "iconTile={{ color: colorVar(\"--app-tile\"), foreground: foregroundColorVar(\"--app-tile-ink\") }}"
3958
+ ]
3726
3959
  }
3727
3960
  ],
3728
3961
  "useWhen": [
3729
3962
  "A navigation or item row needs both a primary selectable action and an independently focusable trailing action.",
3730
- "A command row needs a trailing \"…\" overflow menu (trailingMenu), optionally also opened at the pointer from the row's contextmenu with openPopupMenuAt."
3963
+ "A command row needs a trailing \"…\" overflow menu (trailingMenu), optionally also opened at the pointer from the row's contextmenu with openPopupMenuAt.",
3964
+ "A settings or command row identifies each entry by a colored icon tile (iconTile) instead of a bare glyph."
3731
3965
  ],
3732
3966
  "avoidWhen": [
3733
3967
  "Use ListItem when trailing content is dormant metadata; use AppTab only for tablist semantics and ToolbarControlGroup only for toolbar controls.",
@@ -3767,7 +4001,8 @@
3767
4001
  "trailing overflow menu",
3768
4002
  "before, after, or paired group divider",
3769
4003
  "position-aware divided-list corners: flat wherever a divider line (this row's or a neighbor's) meets the edge",
3770
- "draggable row with dragging and drop-before / drop-after insertion states"
4004
+ "draggable row with dragging and drop-before / drop-after insertion states",
4005
+ "filled leading icon tile (iconTile): a quiet tone preset (neutral, brand, success, warning, danger) or an application fill with an optional foreground; a 32px rounded tile holding an 18px glyph"
3771
4006
  ],
3772
4007
  "accessibility": [
3773
4008
  "The noninteractive root contains two sibling native buttons in primary-then-trailing focus order; each button has its own action, item identity, accessible name, and disabled state.",
@@ -3850,7 +4085,21 @@
3850
4085
  "--kui-list-action-row-selected-color",
3851
4086
  "--kui-list-action-row-trailing-hover-background",
3852
4087
  "--kui-list-group-divider-color",
3853
- "--kui-font-xs"
4088
+ "--kui-list-row-padding-inline",
4089
+ "--kui-list-row-icon-size",
4090
+ "--kui-font-xs",
4091
+ "--kui-radius-m",
4092
+ "--kui-color-brand-fill-quiet",
4093
+ "--kui-color-brand-on-quiet",
4094
+ "--kui-color-success-fill-quiet",
4095
+ "--kui-color-success-border-quiet",
4096
+ "--kui-color-success-on-quiet",
4097
+ "--kui-color-warning-fill-quiet",
4098
+ "--kui-color-warning-border-quiet",
4099
+ "--kui-color-warning-on-quiet",
4100
+ "--kui-color-danger-fill-quiet",
4101
+ "--kui-color-danger-border-quiet",
4102
+ "--kui-color-danger-on-quiet"
3854
4103
  ],
3855
4104
  "links": {
3856
4105
  "catalogRoute": "?component=list-action-row",
@@ -3888,10 +4137,47 @@
3888
4137
  "examples": [
3889
4138
  "className=\"app-row\""
3890
4139
  ]
4140
+ },
4141
+ {
4142
+ "path": "iconTile.color",
4143
+ "grammar": "color",
4144
+ "helpers": [
4145
+ "fillColor",
4146
+ "uiColor",
4147
+ "colorVar"
4148
+ ],
4149
+ "shorthands": [],
4150
+ "canonicalShorthands": [],
4151
+ "exceptionalShorthands": [],
4152
+ "rawPolicy": "forbid",
4153
+ "examples": [
4154
+ "iconTile={{ color: fillColor(\"#e5484d\") }}",
4155
+ "iconTile={{ color: uiColor(\"brand-fill-loud\") }}",
4156
+ "iconTile={{ color: colorVar(\"--app-category-color\") }}"
4157
+ ]
4158
+ },
4159
+ {
4160
+ "path": "iconTile.foreground",
4161
+ "grammar": "color",
4162
+ "helpers": [
4163
+ "uiColor",
4164
+ "foregroundColorVar",
4165
+ "foregroundColor"
4166
+ ],
4167
+ "shorthands": [],
4168
+ "canonicalShorthands": [],
4169
+ "exceptionalShorthands": [],
4170
+ "rawPolicy": "forbid",
4171
+ "examples": [
4172
+ "iconTile={{ color: fillColor(\"#e5484d\"), foreground: foregroundColor(\"white\") }}",
4173
+ "iconTile={{ color: uiColor(\"brand-fill-loud\"), foreground: uiColor(\"brand-on-loud\") }}",
4174
+ "iconTile={{ color: colorVar(\"--app-tile\"), foreground: foregroundColorVar(\"--app-tile-ink\") }}"
4175
+ ]
3891
4176
  }
3892
4177
  ],
3893
4178
  "useWhen": [
3894
- "Render a selectable, disabled, trailing, or multiline sidebar action row whose descendants must remain clipped to the rounded row boundary; use ListItemLink when the destination has an href and needs native link activation."
4179
+ "Render a selectable, disabled, trailing, or multiline sidebar action row whose descendants must remain clipped to the rounded row boundary; use ListItemLink when the destination has an href and needs native link activation.",
4180
+ "A settings or command row identifies each entry by a colored icon tile (iconTile) instead of a bare glyph."
3895
4181
  ],
3896
4182
  "avoidWhen": [
3897
4183
  "Do not use for an ordinary inline link, form button, isolated ARIA menuitem, or an interactive trailing action; use ListActionRow for sibling row actions.",
@@ -3934,7 +4220,8 @@
3934
4220
  "description and status",
3935
4221
  "busy while retaining content",
3936
4222
  "before, after, or paired group divider",
3937
- "position-aware divided-list corners: flat wherever a divider line (this row's or a neighbor's) meets the edge"
4223
+ "position-aware divided-list corners: flat wherever a divider line (this row's or a neighbor's) meets the edge",
4224
+ "filled leading icon tile (iconTile): a quiet tone preset (neutral, brand, success, warning, danger) or an application fill with an optional foreground; a 32px rounded tile holding an 18px glyph"
3938
4225
  ],
3939
4226
  "accessibility": [
3940
4227
  "ListItem uses native button activation and pressed maps to aria-pressed; ListItemLink uses native anchor activation and external opens a new tab with safe rel and an announced default label. Both map selected to aria-current; disabled or loading links omit href and leave the tab order. rootAttributes cannot add role=menuitem or replace owned ARIA; trailing is dormant content and must not contain controls. A draggable row reorders by pointer drag or, with wireListReorder, Alt+Shift+ArrowUp/ArrowDown; a placeholder is never draggable."
@@ -4028,11 +4315,24 @@
4028
4315
  "--kui-list-item-selected-color",
4029
4316
  "--kui-list-item-trailing-color",
4030
4317
  "--kui-list-group-divider-color",
4318
+ "--kui-list-row-padding-inline",
4319
+ "--kui-list-row-icon-size",
4031
4320
  "--kui-font-xs",
4032
4321
  "--kui-layout-inline-margin",
4033
4322
  "--kui-layout-item-gap",
4034
4323
  "--kui-layout-item-padding",
4035
- "--kui-layout-rounded-radius"
4324
+ "--kui-layout-rounded-radius",
4325
+ "--kui-radius-m",
4326
+ "--kui-color-brand-on-quiet",
4327
+ "--kui-color-success-fill-quiet",
4328
+ "--kui-color-success-border-quiet",
4329
+ "--kui-color-success-on-quiet",
4330
+ "--kui-color-warning-fill-quiet",
4331
+ "--kui-color-warning-border-quiet",
4332
+ "--kui-color-warning-on-quiet",
4333
+ "--kui-color-danger-fill-quiet",
4334
+ "--kui-color-danger-border-quiet",
4335
+ "--kui-color-danger-on-quiet"
4036
4336
  ],
4037
4337
  "links": {
4038
4338
  "catalogRoute": "?component=list-item",
@@ -4266,7 +4566,7 @@
4266
4566
  },
4267
4567
  {
4268
4568
  "id": "application-tabs",
4269
- "name": "Application tabs",
4569
+ "name": "Application Tabs",
4270
4570
  "category": "Navigation",
4271
4571
  "kind": "composition",
4272
4572
  "source": "kerf",
@@ -4549,6 +4849,11 @@
4549
4849
  "name": "data-scroll-divider",
4550
4850
  "on": "chrome named in wireScrollDividers targets (a TabBar strip has none)",
4551
4851
  "meaning": "The sides, in t/r/b/l order, on which that chrome currently draws its scroll divider. Re-applied if a re-render drops it."
4852
+ },
4853
+ {
4854
+ "name": "data-header-overlay",
4855
+ "on": "kui-pane",
4856
+ "meaning": "measured once the wiring has measured a Pane's overlay header (headerPresentation: overlay) and published its border-box height as --kui-scroll-clearance-block-start on the Pane root, plus a classic content scrollbar's inline size as --kui-pane-scrollbar-inline-size, which the header leaves uncovered. Re-applied if a re-render drops it."
4552
4857
  }
4553
4858
  ]
4554
4859
  }
@@ -4691,21 +4996,50 @@
4691
4996
  "category": "Controls",
4692
4997
  "kind": "component",
4693
4998
  "source": "kerf",
4694
- "description": "An exclusive, wrapping set of separated pill chips backed by native radios, with optional leading color swatches or icons.",
4999
+ "description": "A wrapping set of separated pill chips backed by native radios (one exclusive value) or, with multiple, native checkboxes (any number of values), with optional leading color swatches or icons.",
4695
5000
  "uses": [
4696
5001
  "lucide-icon"
4697
5002
  ],
4698
- "purpose": "Choose one value from a visible set too large for a segmented track, such as a color palette with labeled swatches.",
5003
+ "purpose": "Choose one value, or with multiple any number of values, from a visible set too large for a segmented track, such as a color palette with labeled swatches or a set of annotation intents.",
4699
5004
  "publicExports": [
4700
- "ChoiceChips"
5005
+ "ChoiceChips",
5006
+ "fillColor"
5007
+ ],
5008
+ "publicExportImports": {
5009
+ "fillColor": "@kerfjs/ui/css-values"
5010
+ },
5011
+ "cssValueProps": [
5012
+ {
5013
+ "path": "choices[].swatch",
5014
+ "grammar": "color",
5015
+ "helpers": [
5016
+ "fillColor",
5017
+ "uiColor",
5018
+ "colorVar"
5019
+ ],
5020
+ "shorthands": [
5021
+ "transparent"
5022
+ ],
5023
+ "canonicalShorthands": [
5024
+ "transparent"
5025
+ ],
5026
+ "exceptionalShorthands": [],
5027
+ "rawPolicy": "forbid",
5028
+ "examples": [
5029
+ "swatch: fillColor(\"#3b82f6\")",
5030
+ "swatch: uiColor(\"brand-fill-loud\")",
5031
+ "swatch: colorVar(\"--app-label-color\")"
5032
+ ]
5033
+ }
4701
5034
  ],
4702
5035
  "useWhen": [
4703
- "Expose one exclusive choice among several visible options that must wrap onto more rows, such as a labeled color palette with swatches."
5036
+ "Expose one exclusive choice among several visible options that must wrap onto more rows, such as a labeled color palette with swatches.",
5037
+ "Set multiple when the person may turn any number of visible, wrapping options on or off, such as label filters or annotation intents."
4704
5038
  ],
4705
5039
  "avoidWhen": [
4706
5040
  "Use SegmentedControl for a few compact choices on one track.",
4707
- "Use Select when the choice list is long or space is tight.",
4708
- "Do not use it for removable tags (Chip) or for multiple selection."
5041
+ "Use Select when the choice list is long or space is tight; a multiple Select keeps a long multi-value list behind one trigger.",
5042
+ "Do not use it for removable tags (Chip)."
4709
5043
  ],
4710
5044
  "alternatives": [
4711
5045
  {
@@ -4731,13 +5065,16 @@
4731
5065
  ],
4732
5066
  "variants": [
4733
5067
  "color swatch, transparent (struck-through) swatch, icon, or text-only choices",
5068
+ "single (radios) or multiple (checkboxes) selection",
4734
5069
  "default or compact size",
4735
5070
  "disabled group or disabled choices",
4736
- "required"
5071
+ "required (single selection only)"
4737
5072
  ],
4738
5073
  "accessibility": [
4739
- "The group is a named role=\"radiogroup\" of native radios: one Tab stop, arrow keys move the selection, and the checked radio submits the form value.",
4740
- "Every choice keeps a visible text label; the swatch is decorative and the selection adds a heavier border, so neither relies on color alone."
5074
+ "The single group is a named role=\"radiogroup\" of native radios: one Tab stop, arrow keys move the selection, and the checked radio submits the form value.",
5075
+ "A multiple group is a named role=\"group\" of native checkboxes: each pill is a Tab stop, Space toggles it, its checked state is native, and every checked value submits under name.",
5076
+ "Every choice keeps a visible text label; the swatch is decorative and the selection adds a heavier border, so neither relies on color alone.",
5077
+ "Every color is a theme token, so a dark appearance scope (.wa-dark, .wa-invert, or any color-scheme: dark ancestor) restyles the chips for inverse chrome."
4741
5078
  ],
4742
5079
  "geometry": {
4743
5080
  "margin": "none",
@@ -4762,6 +5099,84 @@
4762
5099
  "recipe": "docs/accessibility.md#choicechips"
4763
5100
  }
4764
5101
  },
5102
+ {
5103
+ "id": "composer",
5104
+ "name": "Composer",
5105
+ "category": "Controls",
5106
+ "kind": "component",
5107
+ "source": "kerf",
5108
+ "description": "A raised chat or prompt composer: a framed message field that grows with its content above an action row with a hint and a send button.",
5109
+ "uses": [
5110
+ "text"
5111
+ ],
5112
+ "purpose": "Write a chat message or prompt in a raised frame whose border turns brand while focus is within, with a field that grows between row bounds and a trailing send action.",
5113
+ "publicExports": [
5114
+ "Composer",
5115
+ "wireComposers"
5116
+ ],
5117
+ "useWhen": [
5118
+ "Write a chat message, assistant prompt, or comment reply that is sent with a trailing action, especially in a DialogSurface floating footer over a transcript."
5119
+ ],
5120
+ "avoidWhen": [
5121
+ "Use wa-textarea with a FieldLabel for an ordinary form field that is submitted with the rest of a form.",
5122
+ "Do not wrap it in another framed ContentItem or card; it owns its frame, padding, and shadow."
5123
+ ],
5124
+ "alternatives": [
5125
+ {
5126
+ "id": "wa-textarea",
5127
+ "relationship": "prefer-over",
5128
+ "when": "Use Composer instead of a wa-textarea and a button in app-styled chrome for a chat or prompt composer; it owns the raised frame, focus-within border, auto-grow, and action row."
5129
+ }
5130
+ ],
5131
+ "appOwns": [
5132
+ "value",
5133
+ "send action",
5134
+ "keyboard shortcuts other than the opt-in Enter-to-send",
5135
+ "disabled and busy state of its actions",
5136
+ "placement"
5137
+ ],
5138
+ "variants": [
5139
+ "minRows and maxRows bounds for the growing field",
5140
+ "optional hint, described by the field when an id is given",
5141
+ "disabled field",
5142
+ "submitOnEnter: Enter or Cmd/Ctrl+Enter activates the first trailing action, Shift+Enter inserts a newline (with wireComposers)",
5143
+ "slotted into a DialogSurface floating footer"
5144
+ ],
5145
+ "accessibility": [
5146
+ "The field is a native textarea named by label; with an id, the hint is its accessible description.",
5147
+ "The frame's brand border shows focus within, and the trailing actions keep their own names and focus rings.",
5148
+ "With submitOnEnter the field announces aria-keyshortcuts=\"Enter\"; Shift+Enter keeps a newline, and an Enter that commits an IME composition never sends."
5149
+ ],
5150
+ "geometry": {
5151
+ "margin": "none",
5152
+ "border": "self",
5153
+ "padding": "self"
5154
+ },
5155
+ "delivery": {
5156
+ "browserImport": "@kerfjs/ui/composer",
5157
+ "manualCssImport": "@kerfjs/ui/composer.css",
5158
+ "sideEffects": [
5159
+ "browser-condition-css"
5160
+ ]
5161
+ },
5162
+ "wiring": [
5163
+ {
5164
+ "export": "wireComposers",
5165
+ "import": "@kerfjs/ui/wire-composers",
5166
+ "required": false,
5167
+ "reason": "Only for submitOnEnter: turns Enter (or Cmd/Ctrl+Enter) in the field into a click on the first trailing action, skipping Shift+Enter, IME composition, empty or whitespace-only messages, auto-repeat, and a disabled or loading action."
5168
+ }
5169
+ ],
5170
+ "publicClasses": [
5171
+ "kui-composer"
5172
+ ],
5173
+ "publicTokens": [],
5174
+ "links": {
5175
+ "catalogRoute": "?component=composer",
5176
+ "documentation": "docs/composer.md",
5177
+ "recipe": "docs/accessibility.md#composer"
5178
+ }
5179
+ },
4765
5180
  {
4766
5181
  "id": "token-search-field",
4767
5182
  "name": "TokenSearchField",
@@ -5365,13 +5780,19 @@
5365
5780
  "element anchor",
5366
5781
  "pointer anchor",
5367
5782
  "top or bottom placement",
5368
- "modal-dialog host"
5783
+ "modal-dialog host",
5784
+ "tone: 'dark' (the inverse tone of a dark ToolbarControlGroup, for popups anchored to media chrome)"
5369
5785
  ],
5370
5786
  "usageExamples": [
5371
5787
  {
5372
5788
  "title": "Interactive help",
5373
5789
  "description": "The trigger owns when to open; the returned handle closes when an action completes.",
5374
5790
  "code": "const handle = openAnchoredSurface(button, () => <HelpPanel />, { label: 'Field help' });\n// Close from the app's action handler: handle.close();"
5791
+ },
5792
+ {
5793
+ "title": "Popup anchored to dark media chrome",
5794
+ "description": "tone: 'dark' matches a ToolbarControlGroup tone=\"dark\": the surface takes the opposite of the anchor's color scheme (openAnchoredSurfaceAt reads it from point.context) and follows a live OS-preference or ancestor theme switch while open, so its content inherits the inverse text, border, and focus colors without overrides.",
5795
+ "code": "openAnchoredSurface(volumeButton, () => <VolumeControls />, {\n label: 'Volume',\n tone: 'dark',\n placement: 'top',\n});"
5375
5796
  }
5376
5797
  ],
5377
5798
  "accessibility": [
@@ -5468,16 +5889,16 @@
5468
5889
  {
5469
5890
  "title": "Flat selected choices",
5470
5891
  "description": "Headings separate sort dimensions; trailing safe content marks the active command without changing its accessible label.",
5471
- "code": "<PopupMenu\n label=\"Sort chat\"\n items={[\n { kind: 'heading', label: 'Sort by' },\n { label: 'Updated', action: 'sort-updated', details: sort === 'updated' ? tick : undefined },\n { label: 'Priority', action: 'sort-priority', details: sort === 'priority' ? tick : undefined },\n { kind: 'heading', label: 'Order' },\n { label: 'Newest first', action: 'order-newest', details: order === 'newest' ? tick : undefined },\n ]}\n/>"
5892
+ "code": "<PopupMenu\n label=\"Sort chat\"\n items={[\n { kind: 'heading', label: 'Sort By' },\n { label: 'Updated', action: 'sort-updated', details: sort === 'updated' ? tick : undefined },\n { label: 'Priority', action: 'sort-priority', details: sort === 'priority' ? tick : undefined },\n { kind: 'heading', label: 'Order' },\n { label: 'Newest First', action: 'order-newest', details: order === 'newest' ? tick : undefined },\n ]}\n/>"
5472
5893
  },
5473
5894
  {
5474
5895
  "title": "Pointer anchored context menu",
5475
5896
  "description": "Keep the row's visible disabled action separate from the context menu anchor. Find the menu root with a stable data attribute.",
5476
- "code": "<PopupMenu\n context\n label=\"Demand actions\"\n rootAttributes={{ 'data-demand-menu': '' }}\n items={[{ label: 'Open', action: 'open-demand' }]}\n/>\n// In the app's row wiring:\nrow.addEventListener('contextmenu', (event) => {\n event.preventDefault();\n const menu = row.querySelector('[data-demand-menu]') as PopupMenuElement;\n openPopupMenuAt(menu, event.clientX, event.clientY);\n});\n// Call closePopupMenu(menu) when the app needs to dismiss it."
5897
+ "code": "<PopupMenu\n context\n label=\"Demand Actions\"\n rootAttributes={{ 'data-demand-menu': '' }}\n items={[{ label: 'Open', action: 'open-demand' }]}\n/>\n// In the app's row wiring:\nrow.addEventListener('contextmenu', (event) => {\n event.preventDefault();\n const menu = row.querySelector('[data-demand-menu]') as PopupMenuElement;\n openPopupMenuAt(menu, event.clientX, event.clientY);\n});\n// Call closePopupMenu(menu) when the app needs to dismiss it."
5477
5898
  }
5478
5899
  ],
5479
5900
  "accessibility": [
5480
- "An icon-only trigger requires label, rendered as visually hidden slotted text because a Web Awesome button takes its accessible name from its content; a trigger with visible text is named by that text. The context anchor stays out of the accessibility tree. Web Awesome provides menu roles, nested arrow-key navigation, typeahead, and Escape.",
5901
+ "An icon-only trigger requires label, rendered as visually hidden slotted text because a Web Awesome button takes its accessible name from its content; a trigger with visible text is named by that text. The context anchor stays out of the accessibility tree. The open menu takes the trigger's name (the context or icon-only label, or the visible text), and each submenu takes its parent item's label, so a screen reader announces a named menu and getByRole('menu', { name }) finds it. Web Awesome provides menu roles, nested arrow-key navigation, typeahead, and Escape.",
5481
5902
  "Once registered, an icon-only trigger shows its label as an aria-hidden Web Awesome help tag after a 500ms hover and at once on keyboard focus; it hides while the menu is open, on a press, and on Escape, and never joins aria-labelledby. Do not add a title or another tooltip."
5482
5903
  ],
5483
5904
  "geometry": {
@@ -6095,7 +6516,7 @@
6095
6516
  "uses": [
6096
6517
  "state-banner"
6097
6518
  ],
6098
- "purpose": "Show ongoing app-level progress such as \"Loading…\" or \"Updating tickets… 3 of 12\" in a viewport corner above page chrome and any dialog opened before it, without a close button, light dismiss, Escape, or focus change.",
6519
+ "purpose": "Show ongoing app-level progress such as \"Loading…\" or \"Updating Tickets… 3 of 12\" in a viewport corner above page chrome and any dialog opened before it, without a close button, light dismiss, Escape, or focus change.",
6099
6520
  "publicExports": [
6100
6521
  "CornerStatus",
6101
6522
  "wireCornerStatus"
@@ -9350,7 +9771,7 @@
9350
9771
  },
9351
9772
  {
9352
9773
  "id": "recipe-app-shell",
9353
- "name": "Desktop application shell",
9774
+ "name": "Desktop Application Shell",
9354
9775
  "category": "Recipes",
9355
9776
  "kind": "recipe",
9356
9777
  "source": "kerf",
@@ -9395,7 +9816,7 @@
9395
9816
  },
9396
9817
  {
9397
9818
  "id": "recipe-navigation-sidebar",
9398
- "name": "Navigation sidebar",
9819
+ "name": "Navigation Sidebar",
9399
9820
  "category": "Recipes",
9400
9821
  "kind": "recipe",
9401
9822
  "source": "kerf",
@@ -9440,7 +9861,7 @@
9440
9861
  },
9441
9862
  {
9442
9863
  "id": "recipe-workspace-header",
9443
- "name": "Workspace header",
9864
+ "name": "Workspace Header",
9444
9865
  "category": "Recipes",
9445
9866
  "kind": "recipe",
9446
9867
  "source": "kerf",
@@ -9531,7 +9952,7 @@
9531
9952
  },
9532
9953
  {
9533
9954
  "id": "recipe-composer-form",
9534
- "name": "Composer form",
9955
+ "name": "Composer Form",
9535
9956
  "category": "Recipes",
9536
9957
  "kind": "recipe",
9537
9958
  "source": "kerf",
@@ -9579,7 +10000,7 @@
9579
10000
  },
9580
10001
  {
9581
10002
  "id": "recipe-list-workspace-states",
9582
- "name": "List workspace states",
10003
+ "name": "List Workspace States",
9583
10004
  "category": "Recipes",
9584
10005
  "kind": "recipe",
9585
10006
  "source": "kerf",
@@ -9624,7 +10045,7 @@
9624
10045
  },
9625
10046
  {
9626
10047
  "id": "recipe-compact-toolbar",
9627
- "name": "Compact toolbar choices and actions",
10048
+ "name": "Compact Toolbar Choices and Actions",
9628
10049
  "category": "Recipes",
9629
10050
  "kind": "recipe",
9630
10051
  "source": "kerf",
@@ -9670,7 +10091,7 @@
9670
10091
  },
9671
10092
  {
9672
10093
  "id": "recipe-navigation-stack",
9673
- "name": "Navigation stack",
10094
+ "name": "Navigation Stack",
9674
10095
  "category": "Recipes",
9675
10096
  "kind": "recipe",
9676
10097
  "source": "kerf",
@@ -9714,7 +10135,7 @@
9714
10135
  },
9715
10136
  {
9716
10137
  "id": "recipe-loading-inspector",
9717
- "name": "Loading inspector",
10138
+ "name": "Loading Inspector",
9718
10139
  "category": "Recipes",
9719
10140
  "kind": "recipe",
9720
10141
  "source": "kerf",
@@ -9763,7 +10184,7 @@
9763
10184
  },
9764
10185
  {
9765
10186
  "id": "recipe-collapsible-sidebar",
9766
- "name": "Collapsible sidebar",
10187
+ "name": "Collapsible Sidebar",
9767
10188
  "category": "Recipes",
9768
10189
  "kind": "recipe",
9769
10190
  "source": "kerf",