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

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 (274) hide show
  1. package/README.md +14 -11
  2. package/ai/compile-time-contracts-v1.json +2 -2
  3. package/ai/component-catalog-v2.json +206 -39
  4. package/ai/component-catalog.json +306 -58
  5. package/ai/public-api-signatures-v1.md +671 -92
  6. package/ai/skill.md +43 -38
  7. package/ai/webawesome-jsx-signatures-v1.md +8 -2
  8. package/dist/app-tab.js +1 -1
  9. package/dist/badge.d.ts +35 -7
  10. package/dist/badge.js +1 -1
  11. package/dist/browser/content-item.js +3 -0
  12. package/dist/browser/popup-menu.js +3 -0
  13. package/dist/browser/select.js +1 -0
  14. package/dist/catalog-resources.d.ts +12 -1
  15. package/dist/catalog.d.ts +21 -4
  16. package/dist/catalog.js +260 -308
  17. package/dist/catalog.js.map +1 -1
  18. package/dist/{chunk-7IUSV4XG.js → chunk-24PHKUR3.js} +2 -2
  19. package/dist/chunk-24PHKUR3.js.map +1 -0
  20. package/dist/{chunk-WZ2GLEY4.js → chunk-2G2ZJQYK.js} +2 -14
  21. package/dist/chunk-2G2ZJQYK.js.map +1 -0
  22. package/dist/{chunk-D7GWXIAS.js → chunk-5I7QGQVT.js} +1 -1
  23. package/dist/chunk-5I7QGQVT.js.map +1 -0
  24. package/dist/{chunk-HJKRCKDR.js → chunk-63ZWBGE3.js} +6 -3
  25. package/dist/chunk-63ZWBGE3.js.map +1 -0
  26. package/dist/{chunk-44IG7PFV.js → chunk-6CINWX2E.js} +3 -3
  27. package/dist/{chunk-44IG7PFV.js.map → chunk-6CINWX2E.js.map} +1 -1
  28. package/dist/{chunk-C2FAYFDE.js → chunk-AGXQQFKZ.js} +2 -2
  29. package/dist/{chunk-C2FAYFDE.js.map → chunk-AGXQQFKZ.js.map} +1 -1
  30. package/dist/{chunk-ATHXW6RP.js → chunk-AHEG27M7.js} +2 -2
  31. package/dist/{chunk-ATHXW6RP.js.map → chunk-AHEG27M7.js.map} +1 -1
  32. package/dist/{chunk-7GUQYHKA.js → chunk-AK67F6QN.js} +4 -1
  33. package/dist/chunk-AK67F6QN.js.map +1 -0
  34. package/dist/chunk-BFPBS5Y4.js +250 -0
  35. package/dist/chunk-BFPBS5Y4.js.map +1 -0
  36. package/dist/chunk-DG6G5EPF.js +35 -0
  37. package/dist/chunk-DG6G5EPF.js.map +1 -0
  38. package/dist/{chunk-MTM43SJO.js → chunk-G33XC2NB.js} +1 -1
  39. package/dist/chunk-G33XC2NB.js.map +1 -0
  40. package/dist/{chunk-TZ5IHWB2.js → chunk-K6UNVKDK.js} +3 -3
  41. package/dist/{chunk-TZ5IHWB2.js.map → chunk-K6UNVKDK.js.map} +1 -1
  42. package/dist/chunk-KH6VUGHU.js +399 -0
  43. package/dist/chunk-KH6VUGHU.js.map +1 -0
  44. package/dist/{chunk-HMQ2ZDGG.js → chunk-KROD7KZK.js} +3 -2
  45. package/dist/chunk-KROD7KZK.js.map +1 -0
  46. package/dist/{chunk-5NDQABWK.js → chunk-M7QV3IHH.js} +3 -1
  47. package/dist/chunk-M7QV3IHH.js.map +1 -0
  48. package/dist/{chunk-RNZAKSME.js → chunk-MA6Z6EIM.js} +3 -3
  49. package/dist/{chunk-RNZAKSME.js.map → chunk-MA6Z6EIM.js.map} +1 -1
  50. package/dist/chunk-MA73TA6D.js +42 -0
  51. package/dist/chunk-MA73TA6D.js.map +1 -0
  52. package/dist/{chunk-ZMBU522F.js → chunk-MEY33VWB.js} +2 -2
  53. package/dist/{chunk-ZMBU522F.js.map → chunk-MEY33VWB.js.map} +1 -1
  54. package/dist/{chunk-T22EM4ET.js → chunk-MOBRFZH3.js} +81 -31
  55. package/dist/chunk-MOBRFZH3.js.map +1 -0
  56. package/dist/chunk-MP2GDBQZ.js +50 -0
  57. package/dist/chunk-MP2GDBQZ.js.map +1 -0
  58. package/dist/{chunk-3NBL3OUQ.js → chunk-NAPE7WUS.js} +2 -2
  59. package/dist/chunk-NAPE7WUS.js.map +1 -0
  60. package/dist/{chunk-CMUIXJZM.js → chunk-NBYTIVHS.js} +2 -2
  61. package/dist/{chunk-CMUIXJZM.js.map → chunk-NBYTIVHS.js.map} +1 -1
  62. package/dist/chunk-O3EXIBEZ.js +114 -0
  63. package/dist/chunk-O3EXIBEZ.js.map +1 -0
  64. package/dist/{chunk-KPNTVB7A.js → chunk-PK4N5QTO.js} +8 -7
  65. package/dist/chunk-PK4N5QTO.js.map +1 -0
  66. package/dist/chunk-QQOTQTDD.js +415 -0
  67. package/dist/chunk-QQOTQTDD.js.map +1 -0
  68. package/dist/{chunk-BJJKFVWW.js → chunk-T4UZTNZ4.js} +5 -5
  69. package/dist/chunk-T4UZTNZ4.js.map +1 -0
  70. package/dist/chunk-V65EOWNF.js +83 -0
  71. package/dist/chunk-V65EOWNF.js.map +1 -0
  72. package/dist/{chunk-GUIHMIT2.js → chunk-VNPQDCQZ.js} +3 -3
  73. package/dist/{chunk-GUIHMIT2.js.map → chunk-VNPQDCQZ.js.map} +1 -1
  74. package/dist/{chunk-5I22LMCV.js → chunk-VZOFZPSO.js} +2 -2
  75. package/dist/chunk-VZOFZPSO.js.map +1 -0
  76. package/dist/chunk-WLG6SSNT.js +94 -0
  77. package/dist/chunk-WLG6SSNT.js.map +1 -0
  78. package/dist/{chunk-NE5JAOQS.js → chunk-WOUF7YXM.js} +3 -3
  79. package/dist/{chunk-NE5JAOQS.js.map → chunk-WOUF7YXM.js.map} +1 -1
  80. package/dist/collapsible-panel.d.ts +51 -13
  81. package/dist/collapsible-panel.js +38 -10
  82. package/dist/collapsible-panel.js.map +1 -1
  83. package/dist/content-item.d.ts +46 -0
  84. package/dist/content-item.js +4 -0
  85. package/dist/content-item.js.map +1 -0
  86. package/dist/css-values.d.ts +5 -11
  87. package/dist/css-values.js +1 -1
  88. package/dist/disclosure-arrow.d.ts +4 -1
  89. package/dist/disclosure-arrow.js +1 -1
  90. package/dist/floating-toolbar.d.ts +17 -6
  91. package/dist/floating-toolbar.js +1 -1
  92. package/dist/grid.js +1 -1
  93. package/dist/help-tags-register.d.ts +13 -0
  94. package/dist/help-tags-register.js +9 -0
  95. package/dist/help-tags-register.js.map +1 -0
  96. package/dist/index.d.ts +7 -5
  97. package/dist/index.js +31 -29
  98. package/dist/list-action-row.js +1 -1
  99. package/dist/list-header.d.ts +14 -1
  100. package/dist/list-header.js +1 -1
  101. package/dist/list-inset-control.d.ts +1 -1
  102. package/dist/list-inset-control.js +1 -1
  103. package/dist/list-inset-text.d.ts +9 -10
  104. package/dist/list-inset-text.js +2 -1
  105. package/dist/list-item.js +1 -1
  106. package/dist/list.d.ts +10 -3
  107. package/dist/list.js +1 -1
  108. package/dist/nav-stack.d.ts +38 -5
  109. package/dist/nav-stack.js +4 -1
  110. package/dist/pane.d.ts +20 -2
  111. package/dist/pane.js +1 -1
  112. package/dist/panel-toolbar-C8sF-YZC.d.ts +63 -0
  113. package/dist/popup-menu-register.d.ts +9 -0
  114. package/dist/popup-menu-register.js +31 -0
  115. package/dist/popup-menu-register.js.map +1 -0
  116. package/dist/popup-menu.d.ts +71 -0
  117. package/dist/popup-menu.js +3 -0
  118. package/dist/popup-menu.js.map +1 -0
  119. package/dist/row.d.ts +1 -1
  120. package/dist/row.js +1 -1
  121. package/dist/select-register.js +70 -3
  122. package/dist/select-register.js.map +1 -1
  123. package/dist/select.d.ts +46 -8
  124. package/dist/select.js +2 -1
  125. package/dist/{divider-sides-BzB6rphT.d.ts → sides-BPSWde0A.d.ts} +1 -3
  126. package/dist/skeleton.js +1 -1
  127. package/dist/spacer.js +1 -1
  128. package/dist/split-view.d.ts +31 -3
  129. package/dist/split-view.js +33 -5
  130. package/dist/split-view.js.map +1 -1
  131. package/dist/state-banner.js +1 -1
  132. package/dist/styles/badge.css +13 -0
  133. package/dist/styles/catalog/components/catalog-example.css +1 -17
  134. package/dist/styles/catalog/components/catalog-stage.css +9 -14
  135. package/dist/styles/catalog/components/catalog.css +8 -18
  136. package/dist/styles/catalog.css +0 -5
  137. package/dist/styles/collapsible-panel.css +192 -39
  138. package/dist/styles/content-item.css +30 -0
  139. package/dist/styles/floating-toolbar.css +5 -0
  140. package/dist/styles/foundation.css +28 -19
  141. package/dist/styles/layout.css +1 -21
  142. package/dist/styles/list-action-row.css +13 -1
  143. package/dist/styles/list-inset-text.css +1 -2
  144. package/dist/styles/list-item.css +14 -1
  145. package/dist/styles/list.css +1 -1
  146. package/dist/styles/nav-stack.css +29 -64
  147. package/dist/styles/pane.css +33 -1
  148. package/dist/styles/popup-menu.css +90 -0
  149. package/dist/styles/resizable-region.css +53 -10
  150. package/dist/styles/select.css +39 -12
  151. package/dist/styles/split-view.css +21 -25
  152. package/dist/styles/state-banner.css +13 -4
  153. package/dist/styles/styles.css +1 -0
  154. package/dist/styles/tab-bar.css +31 -3
  155. package/dist/styles/tab-scaffold.css +36 -14
  156. package/dist/styles/text.css +1 -1
  157. package/dist/styles/token-search-field.css +4 -4
  158. package/dist/styles/toolbar-control-group.css +44 -12
  159. package/dist/styles/toolbar.css +57 -7
  160. package/dist/styles/value-table.css +19 -2
  161. package/dist/styles/webawesome.css +3 -1
  162. package/dist/styles/workbench.css +165 -31
  163. package/dist/tab-scaffold.d.ts +35 -1
  164. package/dist/tab-scaffold.js +50 -16
  165. package/dist/tab-scaffold.js.map +1 -1
  166. package/dist/text.js +1 -1
  167. package/dist/token-search-field.d.ts +13 -2
  168. package/dist/token-search-field.js +1 -1
  169. package/dist/toolbar-text.js +1 -1
  170. package/dist/toolbar.d.ts +12 -4
  171. package/dist/toolbar.js +1 -1
  172. package/dist/{types-CEsieBZi.d.ts → types-DXAGogOS.d.ts} +48 -0
  173. package/dist/value-table.js +1 -1
  174. package/dist/webawesome.d.ts +7 -1
  175. package/dist/wire-catalog.d.ts +24 -1
  176. package/dist/wire-catalog.js +26 -3
  177. package/dist/wire-catalog.js.map +1 -1
  178. package/dist/wire-sidebar.js +6 -3
  179. package/dist/wire-sidebar.js.map +1 -1
  180. package/dist/wire-token-search-fields.js +1 -1
  181. package/dist/wire-workbench.js +1 -350
  182. package/dist/wire-workbench.js.map +1 -1
  183. package/dist/workbench.d.ts +144 -6
  184. package/dist/workbench.js +11 -208
  185. package/dist/workbench.js.map +1 -1
  186. package/docs/accessibility.md +126 -6
  187. package/docs/app-layouts.md +9 -7
  188. package/docs/catalog.md +41 -9
  189. package/docs/collapsible-panel.md +79 -5
  190. package/docs/component-contract.md +38 -12
  191. package/docs/component-selection.md +64 -55
  192. package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
  193. package/docs/design/templates/empty-state/with-action.svg +1 -1
  194. package/docs/design/templates/empty-state-dark.svg +1 -1
  195. package/docs/design/templates/empty-state.svg +1 -1
  196. package/docs/design/templates/list/compact-dark.svg +1 -1
  197. package/docs/design/templates/list/compact.svg +1 -1
  198. package/docs/design/templates/list/stack-dark.svg +1 -1
  199. package/docs/design/templates/list/stack.svg +1 -1
  200. package/docs/design/templates/list-action-row/default-dark.svg +1 -1
  201. package/docs/design/templates/list-action-row/default.svg +1 -1
  202. package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
  203. package/docs/design/templates/list-action-row/selected.svg +1 -1
  204. package/docs/design/templates/list-action-row-dark.svg +1 -1
  205. package/docs/design/templates/list-action-row.svg +1 -1
  206. package/docs/design/templates/list-dark.svg +1 -1
  207. package/docs/design/templates/list-item/default-dark.svg +1 -1
  208. package/docs/design/templates/list-item/default.svg +1 -1
  209. package/docs/design/templates/list-item/selected-dark.svg +1 -1
  210. package/docs/design/templates/list-item/selected.svg +1 -1
  211. package/docs/design/templates/list-item/trailing-dark.svg +1 -1
  212. package/docs/design/templates/list-item/trailing.svg +1 -1
  213. package/docs/design/templates/list-item-dark.svg +1 -1
  214. package/docs/design/templates/list-item.svg +1 -1
  215. package/docs/design/templates/list.svg +1 -1
  216. package/docs/design/templates/state-banner/danger-dark.svg +1 -1
  217. package/docs/design/templates/state-banner/danger.svg +1 -1
  218. package/docs/design/templates/state-banner/info-dark.svg +1 -1
  219. package/docs/design/templates/state-banner/info.svg +1 -1
  220. package/docs/design/templates/state-banner/success-dark.svg +1 -1
  221. package/docs/design/templates/state-banner/success.svg +1 -1
  222. package/docs/design/templates/state-banner/warning-dark.svg +1 -1
  223. package/docs/design/templates/state-banner/warning.svg +1 -1
  224. package/docs/design/templates/state-banner-dark.svg +1 -1
  225. package/docs/design/templates/state-banner.svg +1 -1
  226. package/docs/design/templates/value-table/details-dark.svg +1 -1
  227. package/docs/design/templates/value-table/details.svg +1 -1
  228. package/docs/design/templates/value-table-dark.svg +1 -1
  229. package/docs/design/templates/value-table.svg +1 -1
  230. package/docs/design-philosophy.md +1 -1
  231. package/docs/examples/command-palette-adapter.tsx +3 -2
  232. package/docs/layout.md +74 -29
  233. package/docs/nav-stack.md +45 -1
  234. package/docs/recipes.md +48 -40
  235. package/docs/split-view.md +46 -2
  236. package/docs/surface-scaffold.md +1 -1
  237. package/docs/tab-scaffold.md +50 -1
  238. package/docs/type-contracts.md +17 -17
  239. package/docs/ux-demo.md +8 -4
  240. package/docs/webawesome-theme.md +1 -2
  241. package/docs/workbench.md +131 -10
  242. package/llms.txt +38 -9
  243. package/package.json +24 -2
  244. package/ux-demo/recipes/app-shell.tsx +141 -223
  245. package/ux-demo/recipes/collapsible-sidebar.tsx +47 -77
  246. package/ux-demo/recipes/list-detail-dialog.tsx +150 -54
  247. package/ux-demo/recipes/mount-recipe.ts +0 -5
  248. package/ux-demo/recipes/navigation-sidebar.tsx +3 -2
  249. package/ux-demo/recipes/navigation-stack.tsx +3 -2
  250. package/ux-demo/recipes/types.ts +0 -1
  251. package/dist/chunk-3NBL3OUQ.js.map +0 -1
  252. package/dist/chunk-5I22LMCV.js.map +0 -1
  253. package/dist/chunk-5NDQABWK.js.map +0 -1
  254. package/dist/chunk-7GUQYHKA.js.map +0 -1
  255. package/dist/chunk-7IUSV4XG.js.map +0 -1
  256. package/dist/chunk-BJJKFVWW.js.map +0 -1
  257. package/dist/chunk-D7GWXIAS.js.map +0 -1
  258. package/dist/chunk-DQA5FMOX.js +0 -85
  259. package/dist/chunk-DQA5FMOX.js.map +0 -1
  260. package/dist/chunk-HJKRCKDR.js.map +0 -1
  261. package/dist/chunk-HMQ2ZDGG.js.map +0 -1
  262. package/dist/chunk-KPNTVB7A.js.map +0 -1
  263. package/dist/chunk-MTM43SJO.js.map +0 -1
  264. package/dist/chunk-T22EM4ET.js.map +0 -1
  265. package/dist/chunk-WZ2GLEY4.js.map +0 -1
  266. package/dist/chunk-XD7DWYXG.js +0 -34
  267. package/dist/chunk-XD7DWYXG.js.map +0 -1
  268. package/dist/chunk-ZK5EGVFP.js +0 -27
  269. package/dist/chunk-ZK5EGVFP.js.map +0 -1
  270. package/dist/styles/catalog/components/catalog-detail.css +0 -35
  271. package/dist/styles/catalog/components/catalog-resource-footer.css +0 -37
  272. package/dist/styles/catalog/components/catalog-secondary-sections.css +0 -38
  273. package/dist/styles/catalog/components/catalog-section-list.css +0 -22
  274. package/dist/styles/catalog/components/catalog-sidebar.css +0 -82
@@ -66,18 +66,16 @@
66
66
  scroll-padding-block-start: var(--kui-edge-inset-block-start);
67
67
  }
68
68
 
69
- .kui-tab-scaffold__scene:not(
70
- :has(
71
- > :is(
72
- [data-component="pane"],
73
- [data-component="nav-stack"],
74
- [data-component="split-view"],
75
- [data-component="workbench"],
76
- [data-component="tab-scaffold"]
77
- ):only-child
78
- )
79
- )
80
- > * {
69
+ .kui-tab-scaffold__scene
70
+ > :not(
71
+ :is(
72
+ [data-component="pane"],
73
+ [data-component="nav-stack"],
74
+ [data-component="split-view"],
75
+ [data-component="workbench"],
76
+ [data-component="tab-scaffold"]
77
+ ):only-child
78
+ ) {
81
79
  --kui-edge-inset-block-start: 0px;
82
80
  --kui-edge-inset-block-end: 0px;
83
81
  --kui-edge-inset-inline-start: 0px;
@@ -98,7 +96,7 @@
98
96
  );
99
97
  padding-inline: var(--_kui-tab-scaffold-safe-inline-start)
100
98
  var(--_kui-tab-scaffold-safe-inline-end);
101
- border-block-start: 1px solid var(--kui-color-border);
99
+ border-block-start: 1px solid var(--kui-color-neutral-border-normal);
102
100
  background: var(--kui-color-surface);
103
101
  }
104
102
 
@@ -120,7 +118,7 @@
120
118
  }
121
119
 
122
120
  .kui-tab-scaffold__tab[aria-selected="true"] {
123
- color: var(--kui-color-accent-text);
121
+ color: var(--kui-color-brand-on-quiet);
124
122
  }
125
123
 
126
124
  .kui-tab-scaffold__tab:focus-visible {
@@ -129,10 +127,34 @@
129
127
  }
130
128
 
131
129
  .kui-tab-scaffold__tab-icon {
130
+ position: relative;
132
131
  display: grid;
133
132
  place-items: center;
134
133
  }
135
134
 
135
+ /* The iOS tab-bar badge: over the icon's top-trailing corner, its leading
136
+ edge just past the icon's center line so a longer count grows outward. The
137
+ Badge keeps its own geometry; only this anchor is positioned. Without an
138
+ icon the badge stays in flow above the label. */
139
+ .kui-tab-scaffold__tab-badge {
140
+ display: flex;
141
+ pointer-events: none;
142
+ }
143
+
144
+ .kui-tab-scaffold__tab-icon > .kui-tab-scaffold__tab-badge {
145
+ position: absolute;
146
+ inset-block-start: -0.4375rem;
147
+ inset-inline-start: calc(50% + 0.1875rem);
148
+ }
149
+
150
+ /* The text-free dot never grows, so it centers on the icon's top-trailing
151
+ corner instead: half over the glyph, half outside it. */
152
+ .kui-tab-scaffold__tab-icon
153
+ > .kui-tab-scaffold__tab-badge[data-badge-kind="dot"] {
154
+ inset-block-start: -0.125rem;
155
+ inset-inline-start: calc(100% - 0.3125rem);
156
+ }
157
+
136
158
  .kui-tab-scaffold__tab-icon svg {
137
159
  width: 1.375rem;
138
160
  height: 1.375rem;
@@ -10,7 +10,7 @@
10
10
  }
11
11
 
12
12
  .kui-text[data-tone="danger"] {
13
- color: var(--kui-color-danger-text);
13
+ color: var(--kui-color-danger-on-quiet);
14
14
  }
15
15
 
16
16
  .kui-text[data-size="compact"] {
@@ -1,8 +1,8 @@
1
1
  .kui-token-search {
2
2
  --kui-token-search-background: var(--kui-color-surface);
3
- --kui-token-search-border: var(--kui-color-border);
4
- --kui-token-search-token-background: var(--kui-color-accent);
5
- --kui-token-search-token-foreground: var(--kui-color-accent-text);
3
+ --kui-token-search-border: var(--kui-color-neutral-border-normal);
4
+ --kui-token-search-token-background: var(--kui-color-brand-fill-normal);
5
+ --kui-token-search-token-foreground: var(--kui-color-brand-on-quiet);
6
6
  --kui-token-search-line-size: 2.125rem;
7
7
 
8
8
  display: grid;
@@ -53,7 +53,7 @@
53
53
  padding-block: calc((var(--kui-token-search-line-size) - 1.35em) / 2) 0;
54
54
  box-sizing: border-box;
55
55
  outline: 0;
56
- caret-color: var(--kui-color-accent-text);
56
+ caret-color: var(--kui-color-brand-on-quiet);
57
57
  font-size: var(--kui-font-s);
58
58
  line-height: 1.35;
59
59
  white-space: pre-wrap;
@@ -254,6 +254,19 @@
254
254
  white-space: nowrap;
255
255
  }
256
256
 
257
+ /* An icon tile: a non-interactive icon placed directly in a group (a panel
258
+ heading's identity glyph) takes the same 40px slot and 16px visual as an
259
+ icon button, so it centers in the group and lines up with button icons,
260
+ without a hover surface or a focusable control that does nothing. */
261
+ .kui-toolbar-control-group > svg {
262
+ display: block;
263
+ width: 1rem;
264
+ height: 1rem;
265
+ padding: 0.75rem;
266
+ box-sizing: content-box;
267
+ flex: 0 0 auto;
268
+ }
269
+
257
270
  .kui-toolbar-control-group > button svg,
258
271
  .kui-toolbar-control-group wa-button > svg,
259
272
  .kui-toolbar-control-group > .kui-toolbar-action-link svg {
@@ -304,7 +317,12 @@
304
317
  padding-inline: 0;
305
318
  }
306
319
 
307
- .kui-toolbar-control-group[data-menu-inset="standard"] wa-dropdown::part(menu) {
320
+ /* `standard` keeps each menu's own standard inset: a raw wa-dropdown takes the
321
+ 8px surface inset, while a PopupMenu keeps the Select listbox inset it
322
+ shares (popup-menu.css). The explicit compact and list-zero choices apply to
323
+ every nested menu. */
324
+ .kui-toolbar-control-group[data-menu-inset="standard"]
325
+ wa-dropdown:not([data-component="popup-menu"])::part(menu) {
308
326
  padding: var(--kui-wa-surface-inset, 0.5rem);
309
327
  }
310
328
  .kui-toolbar-control-group[data-menu-inset="compact"] wa-dropdown::part(menu) {
@@ -465,35 +483,49 @@
465
483
 
466
484
  /* With per-control rings, a composed Select paints its own ring even when it
467
485
  was told the group owns it: nothing else would show focus. It matches the
468
- sibling controls' ring and offset. */
486
+ sibling controls' ring and offset. While its listbox is open the popup shows
487
+ focus instead, so the trigger ring stays off, as a PopupMenu trigger's does. */
469
488
  .kui-toolbar-control-group[data-focus-ring="control"]
470
- > wa-select:focus-within::part(combobox) {
489
+ > wa-select:not([open]):focus-within::part(combobox) {
471
490
  outline: var(--kui-focus-ring);
472
491
  outline-offset: 1px;
473
492
  }
474
493
 
475
- .kui-toolbar-control-group[data-focus-ring="outline"]:focus-within {
494
+ .kui-toolbar-control-group[data-focus-ring="outline"]:focus-within:not(
495
+ :where(:has(wa-select[open], wa-dropdown[open]))
496
+ ) {
476
497
  outline: var(--kui-focus-ring);
477
498
  outline-offset: 1px;
478
499
  }
479
500
 
480
- .kui-toolbar-control-group[data-focus-ring="halo"]:focus-within {
501
+ .kui-toolbar-control-group[data-focus-ring="halo"]:focus-within:not(
502
+ :where(:has(wa-select[open], wa-dropdown[open]))
503
+ ) {
481
504
  border-color: var(--kui-color-text-link);
482
505
  box-shadow: 0 0 0 3px
483
506
  color-mix(in srgb, var(--kui-color-text-link) 22%, transparent);
484
507
  }
485
508
 
486
- /* Chromium and WebKit do not propagate :focus-within from a focused
487
- light-DOM child (an open wa-select's active wa-option) through the host's
488
- popup shadow tree, so the group ring vanished while its Select listbox was
489
- open. A focused light-DOM descendant still owns the group ring. Kept as
490
- separate rules so an engine without :has() keeps the :focus-within ring. */
491
- .kui-toolbar-control-group[data-focus-ring="outline"]:has(:focus) {
509
+ /* A group-owned ring (outline or halo) is off while a Select listbox or a
510
+ PopupMenu inside the group is open: the open popup shows focus, as the
511
+ per-control Select and PopupMenu triggers already do, and the ring returns
512
+ when the popup closes with focus still in the group. The exclusion sits in
513
+ a forgiving :where(), so an engine without :has() keeps the ring.
514
+
515
+ Chromium and WebKit do not propagate :focus-within from a focused
516
+ light-DOM child through a host's popup shadow tree, so a focused light-DOM
517
+ descendant also owns the group ring. Kept as separate rules so an engine
518
+ without :has() keeps the :focus-within ring. */
519
+ .kui-toolbar-control-group[data-focus-ring="outline"]:has(:focus):not(
520
+ :where(:has(wa-select[open], wa-dropdown[open]))
521
+ ) {
492
522
  outline: var(--kui-focus-ring);
493
523
  outline-offset: 1px;
494
524
  }
495
525
 
496
- .kui-toolbar-control-group[data-focus-ring="halo"]:has(:focus) {
526
+ .kui-toolbar-control-group[data-focus-ring="halo"]:has(:focus):not(
527
+ :where(:has(wa-select[open], wa-dropdown[open]))
528
+ ) {
497
529
  border-color: var(--kui-color-text-link);
498
530
  box-shadow: 0 0 0 3px
499
531
  color-mix(in srgb, var(--kui-color-text-link) 22%, transparent);
@@ -5,8 +5,12 @@
5
5
  box-sizing: border-box;
6
6
  color: var(--kui-color-text);
7
7
  background: transparent;
8
- grid-template-columns: auto minmax(0, 1fr) auto;
9
- align-items: center;
8
+ /* The center track's minimum is `auto`, not 0, so it resolves to the center
9
+ zone's own min-width (its content width, below): when the zones do not all
10
+ fit, the auto leading track is what shrinks and its title truncates, and
11
+ the center group never overflows its track onto the leading identity. */
12
+ grid-template-columns: auto 1fr auto;
13
+ align-items: start;
10
14
  gap: var(--kui-toolbar-gap, 0.5rem);
11
15
  container: kui-toolbar / inline-size;
12
16
  font-family: var(--kui-font-sans);
@@ -103,40 +107,81 @@
103
107
  .kui-toolbar[divider-sides*="t"] {
104
108
  --_kui-toolbar-divider-top: var(
105
109
  --kui-toolbar-divider-color,
106
- var(--kui-color-border)
110
+ var(--kui-color-neutral-border-normal)
107
111
  );
108
112
  }
109
113
 
110
114
  .kui-toolbar[divider-sides*="r"] {
111
115
  --_kui-toolbar-divider-right: var(
112
116
  --kui-toolbar-divider-color,
113
- var(--kui-color-border)
117
+ var(--kui-color-neutral-border-normal)
114
118
  );
115
119
  }
116
120
 
117
121
  .kui-toolbar[divider-sides*="b"] {
118
122
  --_kui-toolbar-divider-bottom: var(
119
123
  --kui-toolbar-divider-color,
120
- var(--kui-color-border)
124
+ var(--kui-color-neutral-border-normal)
121
125
  );
122
126
  }
123
127
 
124
128
  .kui-toolbar[divider-sides*="l"] {
125
129
  --_kui-toolbar-divider-left: var(
126
130
  --kui-toolbar-divider-color,
127
- var(--kui-color-border)
131
+ var(--kui-color-neutral-border-normal)
128
132
  );
129
133
  }
130
134
 
135
+ /* The control band. Every zone reserves one group-height row at the top of
136
+ the toolbar, and each item is centered in that band by its own size, not by
137
+ its siblings: a group or title shorter than the band takes half the
138
+ difference as a top margin, and anything taller (a wrapped title, a
139
+ multi-line search, a second trailing row) starts at the band's top and grows
140
+ down. A growing item therefore never moves the other items or its own top.
141
+ Centering the zones in the toolbar row instead dropped every control to the
142
+ middle of a two-line title. The band is resolved here, on the toolbar, so a
143
+ compact group's own smaller group size never redefines it. */
144
+ .kui-toolbar {
145
+ --_kui-toolbar-band: var(--kui-toolbar-group-size, calc(2px + 2.625rem));
146
+ }
147
+
131
148
  .kui-toolbar__leading,
132
149
  .kui-toolbar__center,
133
150
  .kui-toolbar__trailing {
134
151
  display: flex;
135
152
  min-width: 0;
136
- align-items: center;
153
+ min-height: var(--_kui-toolbar-band);
154
+ align-items: flex-start;
137
155
  gap: var(--kui-toolbar-gap, 0.5rem);
138
156
  }
139
157
 
158
+ :is(.kui-toolbar__leading, .kui-toolbar__center, .kui-toolbar__trailing)
159
+ > [data-component="toolbar-control-group"] {
160
+ margin-block-start: max(
161
+ 0px,
162
+ calc(
163
+ (
164
+ var(--_kui-toolbar-band) -
165
+ var(--kui-toolbar-group-size, calc(2px + 2.625rem))
166
+ ) /
167
+ 2
168
+ )
169
+ );
170
+ }
171
+
172
+ /* A title fills the band and centers its first line in it; further lines of a
173
+ wrapped title continue below the band. */
174
+ :is(.kui-toolbar__leading, .kui-toolbar__center, .kui-toolbar__trailing)
175
+ > [data-component="toolbar-text"] {
176
+ height: auto;
177
+ min-height: var(--_kui-toolbar-band);
178
+ }
179
+
180
+ :is(.kui-toolbar__leading, .kui-toolbar__center, .kui-toolbar__trailing)
181
+ > [data-component="toolbar-text"][data-wrap="true"] {
182
+ padding-block: max(0px, calc((var(--_kui-toolbar-band) - 1.25em) / 2));
183
+ }
184
+
140
185
  /* Pin each zone to its column so a display:none (empty) leading or center zone
141
186
  doesn't let the trailing zone auto-place into the first column — which left an
142
187
  extra gap + empty track to the trailing zone's right (KF-5BEF2M). The trailing
@@ -149,6 +194,11 @@
149
194
  }
150
195
 
151
196
  .kui-toolbar__center {
197
+ /* The center content never compresses below its own width (a group cannot
198
+ shrink or clip its controls). The track above takes this as its minimum, so
199
+ the leading identity gives way first, the way a platform toolbar truncates
200
+ its title before it overlaps the centered controls. */
201
+ min-width: min-content;
152
202
  justify-content: center;
153
203
  grid-column: 2;
154
204
  }
@@ -1,6 +1,6 @@
1
1
  .kui-value-table {
2
2
  --kui-value-table-background: var(--kui-color-surface-lowered);
3
- --kui-value-table-border: var(--kui-color-border);
3
+ --kui-value-table-border: var(--kui-color-neutral-border-normal);
4
4
  --_kui-value-table-icon-size: var(--kui-value-table-icon-size, 1.5rem);
5
5
  display: grid;
6
6
  margin-block: 0;
@@ -22,7 +22,14 @@
22
22
  padding-block: 0.5rem;
23
23
  padding-inline: var(--_kui-value-table-inline-padding);
24
24
  box-sizing: border-box;
25
- grid-template-columns: minmax(6rem, auto) minmax(0, 1fr);
25
+ /* Two content-sized tracks share the free space equally, and each stops
26
+ growing once its content fits. A short value keeps its whole width and a
27
+ long label takes the rest (ending a word that still does not fit in an
28
+ ellipsis); a short label keeps its width beside a long, wrapping value;
29
+ when both are long they split the row. A `1fr` value track would get
30
+ nothing until the label reached its full width, starving the value to 0px
31
+ beside a long single-word label. */
32
+ grid-template-columns: minmax(0, auto) minmax(0, auto);
26
33
  align-items: center;
27
34
  gap: var(--kui-layout-item-gap, 0.5rem);
28
35
  }
@@ -42,7 +49,12 @@
42
49
  }
43
50
  .kui-value-table__row dt {
44
51
  display: flex;
52
+ /* The label hugs its content (up to its column) rather than stretching, so
53
+ its box does not change with the value's width — a placeholder row keeps
54
+ the live row's label geometry beside its skeleton value. */
55
+ max-width: 100%;
45
56
  min-width: 0;
57
+ justify-self: start;
46
58
  color: var(--kui-color-text-quiet);
47
59
  align-items: center;
48
60
  gap: var(--kui-layout-item-gap, 0.5rem);
@@ -60,6 +72,11 @@
60
72
  }
61
73
  .kui-value-table__label {
62
74
  min-width: 0;
75
+ overflow: hidden;
76
+ /* A multi-word label wraps at spaces; a single word wider than the label
77
+ column (a long component or file name) ends in an ellipsis instead of
78
+ running under the value. */
79
+ text-overflow: ellipsis;
63
80
  }
64
81
  .kui-value-table__row dd {
65
82
  display: flex;
@@ -499,7 +499,9 @@
499
499
  padding-inline: var(--kui-wa-control-inset) !important;
500
500
  }
501
501
 
502
- wa-dropdown-item {
502
+ /* A PopupMenu item owns the Select option geometry instead (popup-menu.css),
503
+ so a command menu and a value list draw identical rows. */
504
+ wa-dropdown-item:not([data-component="popup-menu"] > *) {
503
505
  padding-inline: var(--kui-wa-control-inset) !important;
504
506
  }
505
507
 
@@ -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,36 +157,52 @@
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;
187
189
  --kui-edge-inset-inline-end: 0px;
188
190
  }
189
191
 
192
+ /* A region whose only child is a Pane or layout lets it fill the region, so a
193
+ composed toolbar's footer (or the app's own) sits at the region's bottom
194
+ edge rather than under short content. */
195
+ :is(.kui-workbench__main, .kui-workbench__panel-content)
196
+ > :is(
197
+ [data-component="pane"],
198
+ [data-component="nav-stack"],
199
+ [data-component="split-view"],
200
+ [data-component="workbench"],
201
+ [data-component="tab-scaffold"]
202
+ ):only-child {
203
+ height: 100%;
204
+ }
205
+
190
206
  /* Bottom drawer — the vertical analogue of a rail. */
191
207
  .kui-workbench__drawer {
192
208
  --kui-edge-inset-block-start: 0px;
@@ -199,7 +215,7 @@
199
215
  flex: 0 0 var(--_kui-workbench-drawer-extent);
200
216
  min-height: 0;
201
217
  overflow: hidden;
202
- border-block-start: 1px solid var(--kui-color-border);
218
+ border-block-start: 1px solid var(--kui-color-neutral-border-normal);
203
219
  background: var(--kui-color-surface);
204
220
  }
205
221
 
@@ -373,10 +389,64 @@
373
389
  display: none;
374
390
  }
375
391
 
376
- /* Where the engine can extend a clip past the panel's edge, an expanded
377
- panel lets exactly the handle's outer half through, so the hit target
378
- straddles the separator like a ResizableRegion handle does. Collapsing drops
379
- the margin again before the content slides out. */
392
+ /* An expanded panel lets exactly the handle's outer half through its clip, so
393
+ the hit target straddles the separator like a ResizableRegion handle does
394
+ and the grip is drawn centered on the separator line. Collapsing drops the
395
+ extension again before the content slides out. Engines that can extend a
396
+ clip past the panel's edge do it with `overflow-clip-margin`; the rest
397
+ (WebKit) clip with a `clip-path` that reaches past the panel's edges. That
398
+ also makes the panel a stacking context, so the panel stacks at the
399
+ handle's own level to keep the handle's outer half above the work area
400
+ beside it. The clip and the stacking level sit at low specificity, so a
401
+ responsive overlay presentation (below) replaces both. */
402
+ @supports not (overflow-clip-margin: 10px) {
403
+ .kui-workbench__rail[data-resizable="true"][data-presentation="inline"]:not(
404
+ [data-collapsed="true"],
405
+ [data-content-overflow="visible"]
406
+ ),
407
+ .kui-workbench__drawer[data-resizable="true"][data-presentation="inline"]:not(
408
+ [data-collapsed="true"],
409
+ [data-content-overflow="visible"]
410
+ ) {
411
+ overflow: visible;
412
+ }
413
+
414
+ .kui-workbench__rail:where(
415
+ [data-resizable="true"][data-presentation="inline"]:not(
416
+ [data-collapsed="true"],
417
+ [data-content-overflow="visible"]
418
+ )
419
+ ) {
420
+ z-index: 3;
421
+ clip-path: inset(0 -10px);
422
+ }
423
+
424
+ .kui-workbench__drawer:where(
425
+ [data-resizable="true"][data-presentation="inline"]:not(
426
+ [data-collapsed="true"],
427
+ [data-content-overflow="visible"]
428
+ )
429
+ ) {
430
+ z-index: 3;
431
+ clip-path: inset(-10px 0 0);
432
+ }
433
+
434
+ .kui-workbench__rail--left[data-resizable="true"][data-presentation="inline"]
435
+ > .kui-workbench__handle {
436
+ inset-inline-end: -10px;
437
+ }
438
+
439
+ .kui-workbench__rail--right[data-resizable="true"][data-presentation="inline"]
440
+ > .kui-workbench__handle {
441
+ inset-inline-start: -10px;
442
+ }
443
+
444
+ .kui-workbench__drawer[data-resizable="true"][data-presentation="inline"]
445
+ > .kui-workbench__handle {
446
+ inset-block-start: -10px;
447
+ }
448
+ }
449
+
380
450
  @supports (overflow-clip-margin: 10px) {
381
451
  .kui-workbench__rail[data-resizable="true"]:not(
382
452
  [data-collapsed="true"],
@@ -528,6 +598,7 @@
528
598
  max-width: var(--kui-workbench-overlay-max-width, 85vw);
529
599
  inset-block: 0;
530
600
  box-shadow: var(--kui-shadow-l);
601
+ clip-path: none;
531
602
  }
532
603
 
533
604
  .kui-workbench__rail--left[data-responsive-overlay-at="narrow"] {
@@ -578,6 +649,7 @@
578
649
  inset-inline: 0;
579
650
  inset-block-end: 0;
580
651
  box-shadow: var(--kui-shadow-l);
652
+ clip-path: none;
581
653
  }
582
654
 
583
655
  .kui-workbench__drawer[data-responsive-overlay-at="narrow"][data-collapsed="true"] {
@@ -612,6 +684,7 @@
612
684
  max-width: var(--kui-workbench-overlay-max-width, 85vw);
613
685
  inset-block: 0;
614
686
  box-shadow: var(--kui-shadow-l);
687
+ clip-path: none;
615
688
  }
616
689
 
617
690
  .kui-workbench__rail--left[data-responsive-overlay-at="compact"] {
@@ -662,6 +735,7 @@
662
735
  inset-inline: 0;
663
736
  inset-block-end: 0;
664
737
  box-shadow: var(--kui-shadow-l);
738
+ clip-path: none;
665
739
  }
666
740
 
667
741
  .kui-workbench__drawer[data-responsive-overlay-at="compact"][data-collapsed="true"] {
@@ -707,6 +781,8 @@
707
781
  from this point instead of adding its own inset on top. */
708
782
  --kui-floating-toolbar-inset: 0px;
709
783
  position: absolute;
784
+ /* Hidden while an open rail overlay covers the work area (see below). */
785
+ visibility: var(--_kui-floating-covered, inherit);
710
786
  z-index: var(
711
787
  --kui-workbench-restore-z,
712
788
  calc(var(--kui-workbench-overlay-z, 41) - 2)
@@ -774,8 +850,66 @@
774
850
  );
775
851
  }
776
852
 
853
+ /* An open rail overlay — static or a responsive one whose breakpoint applies —
854
+ covers the work area, so the work area's floating controls (a
855
+ FloatingToolbar in main, the drawer's restore corner, the other rail's
856
+ restore corner) are hidden, not merely stacked beneath it: they never paint
857
+ over the overlay whatever stacking context an app puts them in, and hidden
858
+ they leave the tab order and the accessibility tree. They come back as the
859
+ overlay closes. The flag is set on the rail's siblings only (never on the
860
+ open rail), so the overlay's own floating controls stay, and it is read by
861
+ FloatingToolbar and the layouts' restore corners. 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-floating-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-floating-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-floating-covered: hidden;
891
+ }
892
+ }
893
+
777
894
  @media (prefers-reduced-motion: reduce) {
778
895
  .kui-workbench__panel-content {
779
896
  transition: none;
780
897
  }
781
898
  }
899
+
900
+ /* On a compact (phone-sized) Workbench an overlay rail fills the Workbench
901
+ less a dismiss margin on the side away from its edge, so a press beside it
902
+ closes it (the wiring's outside press); `compactOverlay: "full"` fills the
903
+ Workbench. The rail's resize and configured size stop applying there. */
904
+ @container kui-workbench (max-width: 28rem) {
905
+ .kui-workbench__rail[data-responsive-overlay-at] {
906
+ width: calc(
907
+ 100% - var(--kui-workbench-overlay-dismiss-margin, 2.75rem)
908
+ );
909
+ max-width: none;
910
+ }
911
+
912
+ .kui-workbench__rail[data-responsive-overlay-at][data-compact-overlay="full"] {
913
+ width: 100%;
914
+ }
915
+ }