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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. package/README.md +63 -32
  2. package/ai/application-ui-diagnostic-ids-v1.json +9 -1
  3. package/ai/application-ui-profile-sync.cjs +1 -1
  4. package/ai/application-ui-profile.defaults.json +63 -8
  5. package/ai/application-ui-profile.mjs +1 -1
  6. package/ai/component-catalog.json +208 -32
  7. package/ai/component-catalog.schema.json +2 -0
  8. package/ai/component-class-owners.cjs +83 -0
  9. package/ai/component-composition-extension.d.ts +7 -0
  10. package/ai/component-composition-extension.schema.json +7 -0
  11. package/ai/{component-catalog-v2-overrides.json → component-composition-rules.json} +2 -1
  12. package/ai/{component-catalog-v2.d.ts → component-composition.d.ts} +9 -5
  13. package/ai/{component-catalog-v2.json → component-composition.json} +155 -24
  14. package/ai/{component-catalog-v2.schema.json → component-composition.schema.json} +21 -5
  15. package/ai/components/README.md +170 -0
  16. package/ai/components/application-tabs.md +65 -0
  17. package/ai/components/badge.md +72 -0
  18. package/ai/components/collapsible-panel.md +102 -0
  19. package/ai/components/content-item.md +90 -0
  20. package/ai/components/disclosure-arrow.md +77 -0
  21. package/ai/components/document-baseline.md +75 -0
  22. package/ai/components/empty-state.md +80 -0
  23. package/ai/components/feedback.md +71 -0
  24. package/ai/components/floating-toolbar.md +80 -0
  25. package/ai/components/foundation.md +65 -0
  26. package/ai/components/grid.md +93 -0
  27. package/ai/components/headers.md +63 -0
  28. package/ai/components/layout.md +75 -0
  29. package/ai/components/list-action-row.md +91 -0
  30. package/ai/components/list-header.md +89 -0
  31. package/ai/components/list-inset-control.md +74 -0
  32. package/ai/components/list-inset-text.md +72 -0
  33. package/ai/components/list-item.md +88 -0
  34. package/ai/components/list.md +103 -0
  35. package/ai/components/loading-spinner.md +72 -0
  36. package/ai/components/lucide-icon.md +66 -0
  37. package/ai/components/nav-stack.md +103 -0
  38. package/ai/components/pane.md +100 -0
  39. package/ai/components/popup-menu.md +82 -0
  40. package/ai/components/recipe-app-shell.md +57 -0
  41. package/ai/components/recipe-collapsible-sidebar.md +57 -0
  42. package/ai/components/recipe-compact-toolbar.md +57 -0
  43. package/ai/components/recipe-composer-form.md +57 -0
  44. package/ai/components/recipe-list-detail-dialog.md +57 -0
  45. package/ai/components/recipe-list-workspace-states.md +57 -0
  46. package/ai/components/recipe-loading-inspector.md +57 -0
  47. package/ai/components/recipe-navigation-sidebar.md +57 -0
  48. package/ai/components/recipe-navigation-stack.md +57 -0
  49. package/ai/components/recipe-workspace-header.md +57 -0
  50. package/ai/components/resize.md +101 -0
  51. package/ai/components/row.md +96 -0
  52. package/ai/components/segmented-control.md +82 -0
  53. package/ai/components/select.md +107 -0
  54. package/ai/components/skeleton.md +84 -0
  55. package/ai/components/spacer.md +86 -0
  56. package/ai/components/split-view.md +102 -0
  57. package/ai/components/state-banner.md +92 -0
  58. package/ai/components/sunken-panel.md +79 -0
  59. package/ai/components/surface-scaffold.md +78 -0
  60. package/ai/components/tab-bar.md +112 -0
  61. package/ai/components/tab-scaffold.md +94 -0
  62. package/ai/components/tabs.md +90 -0
  63. package/ai/components/text.md +82 -0
  64. package/ai/components/token-search-field.md +101 -0
  65. package/ai/components/toolbar-control-group.md +100 -0
  66. package/ai/components/toolbar-text.md +76 -0
  67. package/ai/components/toolbar.md +95 -0
  68. package/ai/components/value-table.md +72 -0
  69. package/ai/components/wa-accordion-item.md +55 -0
  70. package/ai/components/wa-accordion.md +65 -0
  71. package/ai/components/wa-animated-image.md +55 -0
  72. package/ai/components/wa-animation.md +55 -0
  73. package/ai/components/wa-avatar.md +55 -0
  74. package/ai/components/wa-badge.md +55 -0
  75. package/ai/components/wa-breadcrumb-item.md +53 -0
  76. package/ai/components/wa-breadcrumb.md +55 -0
  77. package/ai/components/wa-button-group.md +59 -0
  78. package/ai/components/wa-button.md +55 -0
  79. package/ai/components/wa-callout.md +58 -0
  80. package/ai/components/wa-card.md +59 -0
  81. package/ai/components/wa-carousel-item.md +53 -0
  82. package/ai/components/wa-carousel.md +55 -0
  83. package/ai/components/wa-checkbox-group.md +55 -0
  84. package/ai/components/wa-checkbox.md +55 -0
  85. package/ai/components/wa-color-picker.md +55 -0
  86. package/ai/components/wa-comparison.md +55 -0
  87. package/ai/components/wa-copy-button.md +55 -0
  88. package/ai/components/wa-details.md +61 -0
  89. package/ai/components/wa-dialog.md +59 -0
  90. package/ai/components/wa-divider.md +53 -0
  91. package/ai/components/wa-drawer.md +55 -0
  92. package/ai/components/wa-dropdown-item.md +60 -0
  93. package/ai/components/wa-dropdown.md +60 -0
  94. package/ai/components/wa-format-bytes.md +53 -0
  95. package/ai/components/wa-format-date.md +53 -0
  96. package/ai/components/wa-format-number.md +53 -0
  97. package/ai/components/wa-icon.md +58 -0
  98. package/ai/components/wa-include.md +53 -0
  99. package/ai/components/wa-input.md +59 -0
  100. package/ai/components/wa-intersection-observer.md +53 -0
  101. package/ai/components/wa-known-date.md +53 -0
  102. package/ai/components/wa-markdown.md +53 -0
  103. package/ai/components/wa-mutation-observer.md +53 -0
  104. package/ai/components/wa-number-input.md +55 -0
  105. package/ai/components/wa-option.md +59 -0
  106. package/ai/components/wa-otp-input.md +53 -0
  107. package/ai/components/wa-page.md +53 -0
  108. package/ai/components/wa-pagination.md +55 -0
  109. package/ai/components/wa-popover.md +55 -0
  110. package/ai/components/wa-popup.md +53 -0
  111. package/ai/components/wa-progress-bar.md +53 -0
  112. package/ai/components/wa-progress-ring.md +53 -0
  113. package/ai/components/wa-qr-code.md +53 -0
  114. package/ai/components/wa-radio-group.md +59 -0
  115. package/ai/components/wa-radio.md +55 -0
  116. package/ai/components/wa-random-content.md +53 -0
  117. package/ai/components/wa-rating.md +55 -0
  118. package/ai/components/wa-relative-time.md +53 -0
  119. package/ai/components/wa-resize-observer.md +53 -0
  120. package/ai/components/wa-scroller.md +53 -0
  121. package/ai/components/wa-select.md +63 -0
  122. package/ai/components/wa-skeleton.md +53 -0
  123. package/ai/components/wa-slider.md +55 -0
  124. package/ai/components/wa-spinner.md +58 -0
  125. package/ai/components/wa-split-panel.md +58 -0
  126. package/ai/components/wa-switch.md +53 -0
  127. package/ai/components/wa-tab-group.md +69 -0
  128. package/ai/components/wa-tab-panel.md +60 -0
  129. package/ai/components/wa-tab.md +59 -0
  130. package/ai/components/wa-tag.md +59 -0
  131. package/ai/components/wa-textarea.md +53 -0
  132. package/ai/components/wa-time-input.md +55 -0
  133. package/ai/components/wa-toast-item.md +60 -0
  134. package/ai/components/wa-toast.md +60 -0
  135. package/ai/components/wa-tooltip.md +55 -0
  136. package/ai/components/wa-tree-item.md +55 -0
  137. package/ai/components/wa-tree.md +55 -0
  138. package/ai/components/wa-zoomable-frame.md +55 -0
  139. package/ai/components/workbench.md +114 -0
  140. package/ai/public-api-signatures-v1.md +161 -32
  141. package/ai/skill.md +100 -48
  142. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  143. package/analyzer/component-ownership.d.mts +56 -0
  144. package/analyzer/component-ownership.mjs +184 -0
  145. package/analyzer/index.d.mts +3 -0
  146. package/analyzer/index.mjs +274 -20
  147. package/analyzer/selectors.d.mts +21 -0
  148. package/analyzer/selectors.mjs +212 -0
  149. package/dist/browser/catalog.js +25 -0
  150. package/dist/browser/collapsible-panel.js +7 -0
  151. package/dist/browser/nav-stack.js +8 -0
  152. package/dist/browser/split-view.js +10 -0
  153. package/dist/browser/tab-scaffold.js +4 -0
  154. package/dist/browser/workbench.js +10 -0
  155. package/dist/catalog-resources.d.ts +2 -2
  156. package/dist/catalog.d.ts +3 -3
  157. package/dist/catalog.js +7 -6
  158. package/dist/catalog.js.map +1 -1
  159. package/dist/{chunk-PK4N5QTO.js → chunk-553ASUK6.js} +2 -3
  160. package/dist/chunk-553ASUK6.js.map +1 -0
  161. package/dist/{chunk-G33XC2NB.js → chunk-6YFHCLHG.js} +2 -2
  162. package/dist/chunk-6YFHCLHG.js.map +1 -0
  163. package/dist/{chunk-T4UZTNZ4.js → chunk-EVYKTVBQ.js} +2 -11
  164. package/dist/chunk-EVYKTVBQ.js.map +1 -0
  165. package/dist/{chunk-AK67F6QN.js → chunk-EZVNC4J6.js} +4 -1
  166. package/dist/chunk-EZVNC4J6.js.map +1 -0
  167. package/dist/{chunk-MA6Z6EIM.js → chunk-F4QMLOXJ.js} +3 -2
  168. package/dist/chunk-F4QMLOXJ.js.map +1 -0
  169. package/dist/{chunk-QQOTQTDD.js → chunk-G2RKFVRB.js} +13 -10
  170. package/dist/chunk-G2RKFVRB.js.map +1 -0
  171. package/dist/chunk-JCV4GXWB.js +249 -0
  172. package/dist/chunk-JCV4GXWB.js.map +1 -0
  173. package/dist/chunk-K47P7QZC.js +17 -0
  174. package/dist/chunk-K47P7QZC.js.map +1 -0
  175. package/dist/{chunk-MOBRFZH3.js → chunk-OUK6QRDR.js} +2 -12
  176. package/dist/chunk-OUK6QRDR.js.map +1 -0
  177. package/dist/{chunk-O3EXIBEZ.js → chunk-PWXNJS2B.js} +7 -6
  178. package/dist/chunk-PWXNJS2B.js.map +1 -0
  179. package/dist/{chunk-VNPQDCQZ.js → chunk-QOWG4ZCL.js} +3 -2
  180. package/dist/chunk-QOWG4ZCL.js.map +1 -0
  181. package/dist/{chunk-V65EOWNF.js → chunk-XCO6YCYM.js} +5 -4
  182. package/dist/chunk-XCO6YCYM.js.map +1 -0
  183. package/dist/{chunk-K6UNVKDK.js → chunk-XDKAYSVD.js} +3 -1
  184. package/dist/chunk-XDKAYSVD.js.map +1 -0
  185. package/dist/collapsible-panel.d.ts +3 -3
  186. package/dist/collapsible-panel.js +2 -2
  187. package/dist/collapsible-panel.js.map +1 -1
  188. package/dist/index.d.ts +2 -1
  189. package/dist/index.js +10 -8
  190. package/dist/list-action-row.js +2 -1
  191. package/dist/list-header.js +1 -1
  192. package/dist/list-item.js +2 -1
  193. package/dist/nav-stack.d.ts +13 -1
  194. package/dist/nav-stack.js +1 -1
  195. package/dist/pane.d.ts +20 -3
  196. package/dist/pane.js +1 -1
  197. package/dist/{panel-toolbar-C8sF-YZC.d.ts → panel-toolbar-BN4x0rth.d.ts} +3 -2
  198. package/dist/select.js +1 -1
  199. package/dist/split-view.d.ts +3 -3
  200. package/dist/split-view.js +3 -2
  201. package/dist/split-view.js.map +1 -1
  202. package/dist/state-banner.js +1 -1
  203. package/dist/styles/app-tab.css +31 -0
  204. package/dist/styles/badge.css +19 -11
  205. package/dist/styles/collapsible-panel.css +13 -9
  206. package/dist/styles/floating-toolbar.css +25 -6
  207. package/dist/styles/list-header.css +0 -12
  208. package/dist/styles/list.css +4 -4
  209. package/dist/styles/nav-stack.css +46 -19
  210. package/dist/styles/pane.css +50 -0
  211. package/dist/styles/popup-menu.css +151 -0
  212. package/dist/styles/resizable-region.css +22 -10
  213. package/dist/styles/select.css +28 -14
  214. package/dist/styles/skeleton.css +30 -3
  215. package/dist/styles/split-view.css +10 -7
  216. package/dist/styles/state-banner.css +0 -19
  217. package/dist/styles/surface-scaffold.css +8 -3
  218. package/dist/styles/tab-bar.css +79 -28
  219. package/dist/styles/tab-scaffold.css +25 -1
  220. package/dist/styles/text.css +16 -0
  221. package/dist/styles/toolbar-control-group.css +121 -66
  222. package/dist/styles/toolbar-text.css +21 -0
  223. package/dist/styles/toolbar.css +8 -32
  224. package/dist/styles/workbench.css +18 -18
  225. package/dist/tab-scaffold.d.ts +11 -1
  226. package/dist/tab-scaffold.js +2 -0
  227. package/dist/tab-scaffold.js.map +1 -1
  228. package/dist/toolbar-text.d.ts +7 -1
  229. package/dist/toolbar-text.js +1 -1
  230. package/dist/toolbar.d.ts +8 -1
  231. package/dist/toolbar.js +1 -1
  232. package/dist/{types-DXAGogOS.d.ts → types-BuHELdXR.d.ts} +1 -1
  233. package/dist/wire-catalog.d.ts +3 -1
  234. package/dist/wire-catalog.js +2 -0
  235. package/dist/wire-catalog.js.map +1 -1
  236. package/dist/wire-scroll-dividers.d.ts +69 -0
  237. package/dist/wire-scroll-dividers.js +3 -0
  238. package/dist/wire-scroll-dividers.js.map +1 -0
  239. package/dist/workbench.d.ts +13 -12
  240. package/dist/workbench.js +1 -1
  241. package/docs/app-layouts.md +9 -1
  242. package/docs/catalog.md +10 -5
  243. package/docs/collapsible-panel.md +10 -6
  244. package/docs/component-contract.md +147 -21
  245. package/docs/component-selection.md +18 -6
  246. package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -1
  247. package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -1
  248. package/docs/design/templates/tab-bar-dark.svg +1 -1
  249. package/docs/design/templates/tab-bar.svg +1 -1
  250. package/docs/design-philosophy.md +30 -3
  251. package/docs/examples/application-ui-profile.json +4 -4
  252. package/docs/examples/{component-catalog-extension-v2.json → component-composition-extension.json} +3 -3
  253. package/docs/layout.md +82 -3
  254. package/docs/nav-stack.md +33 -3
  255. package/docs/split-view.md +10 -5
  256. package/docs/tab-scaffold.md +23 -1
  257. package/docs/type-contracts.md +4 -3
  258. package/docs/ui-analyzer.md +99 -5
  259. package/docs/ui-doctor.md +10 -0
  260. package/docs/workbench.md +19 -9
  261. package/doctor/index.mjs +6 -1
  262. package/llms.txt +85 -20
  263. package/package.json +17 -5
  264. package/ux-demo/recipes/collapsible-sidebar.tsx +0 -1
  265. package/ux-demo/recipes/composer-form.tsx +0 -1
  266. package/ux-demo/recipes/list-detail-dialog.tsx +0 -2
  267. package/ux-demo/recipes/list-workspace-states.tsx +0 -1
  268. package/ux-demo/recipes/loading-inspector.tsx +0 -1
  269. package/ux-demo/recipes/workspace-header.tsx +0 -1
  270. package/ai/component-catalog-extension-v2.d.ts +0 -7
  271. package/ai/component-catalog-extension-v2.schema.json +0 -7
  272. package/dist/chunk-AK67F6QN.js.map +0 -1
  273. package/dist/chunk-G33XC2NB.js.map +0 -1
  274. package/dist/chunk-K6UNVKDK.js.map +0 -1
  275. package/dist/chunk-MA6Z6EIM.js.map +0 -1
  276. package/dist/chunk-MOBRFZH3.js.map +0 -1
  277. package/dist/chunk-O3EXIBEZ.js.map +0 -1
  278. package/dist/chunk-PK4N5QTO.js.map +0 -1
  279. package/dist/chunk-QQOTQTDD.js.map +0 -1
  280. package/dist/chunk-T4UZTNZ4.js.map +0 -1
  281. package/dist/chunk-V65EOWNF.js.map +0 -1
  282. package/dist/chunk-VNPQDCQZ.js.map +0 -1
@@ -88,3 +88,154 @@
88
88
  letter-spacing: 0.04em;
89
89
  text-transform: uppercase;
90
90
  }
91
+
92
+ /* In a ToolbarControlGroup a PopupMenu sizes itself in the group's context:
93
+ the group lays out its own native and raw Web Awesome children and names a
94
+ PopupMenu only to key its own state on it. The trigger takes the group's
95
+ control height (40px, or 32px in a compact group). A mixed-content trigger
96
+ in a nested-dropdown group grows for its label plus the caret; a fixed 32px
97
+ base would center both outside its host, painting the label across the
98
+ separator and the caret beyond the group border. */
99
+ /* The trigger button takes the group's control metrics, as the group's own
100
+ raw wa-button children do (toolbar-control-group.css excludes this
101
+ trigger). The PopupMenu ancestor sits in `:where()` so each rule keeps the
102
+ specificity of the group's matching raw-child rule and resolves against the
103
+ group's attribute-keyed variants exactly as they do. */
104
+ .kui-toolbar-control-group :where(wa-dropdown.kui-popup-menu) > wa-button {
105
+ --wa-form-control-height: 2.5rem;
106
+ display: inline-flex;
107
+ line-height: 0;
108
+ align-items: center;
109
+ justify-content: center;
110
+ --wa-color-fill-quiet: transparent;
111
+ }
112
+ .kui-toolbar-control-group[data-size="compact"]
113
+ :where(wa-dropdown.kui-popup-menu)
114
+ > wa-button {
115
+ --wa-form-control-height: 2rem;
116
+ }
117
+ .kui-toolbar-control-group[data-content="mixed"]
118
+ :where(wa-dropdown.kui-popup-menu)
119
+ > wa-button {
120
+ line-height: normal;
121
+ }
122
+ .kui-toolbar-control-group
123
+ :where(wa-dropdown.kui-popup-menu)
124
+ > wa-button
125
+ > svg {
126
+ display: block;
127
+ width: 1rem;
128
+ height: 1rem;
129
+ }
130
+ /* Toolbar controls never wrap: a slotted icon and its label share one row. */
131
+ .kui-toolbar-control-group
132
+ :where(wa-dropdown.kui-popup-menu)
133
+ > wa-button::part(label) {
134
+ display: inline-flex;
135
+ align-items: center;
136
+ gap: var(--kui-space-xs);
137
+ white-space: nowrap;
138
+ }
139
+ /* At least a circle around an icon-only trigger, with the group's item radius;
140
+ hover lifts the trigger like a group button, except in a `single` group,
141
+ whose whole surface shows the hover (toolbar-control-group.css). */
142
+ .kui-toolbar-control-group
143
+ :where(wa-dropdown.kui-popup-menu)
144
+ > wa-button::part(base) {
145
+ min-width: 2.5rem;
146
+ min-height: 2.5rem;
147
+ box-sizing: border-box;
148
+ border: 1px solid transparent;
149
+ border-radius: var(
150
+ --kui-toolbar-item-radius,
151
+ var(--kui-layout-pill-radius, calc(1px + 1.3125rem))
152
+ );
153
+ }
154
+ .kui-toolbar-control-group
155
+ :where(wa-dropdown.kui-popup-menu)
156
+ > wa-button:hover::part(base) {
157
+ border-color: var(--kui-toolbar-control-border);
158
+ background-color: var(--kui-toolbar-control-hover-background);
159
+ }
160
+ .kui-toolbar-control-group[data-single="true"]
161
+ :where(wa-dropdown.kui-popup-menu)
162
+ > wa-button:hover::part(base) {
163
+ border-color: transparent;
164
+ background: transparent;
165
+ }
166
+ .kui-toolbar-control-group > wa-dropdown.kui-popup-menu {
167
+ display: inline-flex;
168
+ flex: 0 0 auto;
169
+ }
170
+ .kui-toolbar-control-group > wa-dropdown.kui-popup-menu,
171
+ .kui-toolbar-control-group > wa-dropdown.kui-popup-menu > wa-button,
172
+ .kui-toolbar-control-group
173
+ > wa-dropdown.kui-popup-menu
174
+ > wa-button::part(base) {
175
+ min-width: 2.5rem;
176
+ height: 2.5rem;
177
+ }
178
+ .kui-toolbar-control-group[data-size="compact"] > wa-dropdown.kui-popup-menu,
179
+ .kui-toolbar-control-group[data-size="compact"]
180
+ > wa-dropdown.kui-popup-menu
181
+ > wa-button,
182
+ .kui-toolbar-control-group[data-size="compact"]
183
+ > wa-dropdown.kui-popup-menu
184
+ > wa-button::part(base),
185
+ .kui-toolbar-control-group[data-size="compact"][data-nested-dropdown="true"]
186
+ wa-dropdown.kui-popup-menu
187
+ wa-button,
188
+ .kui-toolbar-control-group[data-size="compact"][data-nested-dropdown="true"]
189
+ wa-dropdown.kui-popup-menu
190
+ wa-button::part(base) {
191
+ min-width: 2rem;
192
+ height: 2rem;
193
+ min-height: 2rem;
194
+ }
195
+ .kui-toolbar-control-group[data-size="compact"][data-content="mixed"]
196
+ > wa-dropdown.kui-popup-menu {
197
+ margin: -2px;
198
+ }
199
+ .kui-toolbar-control-group[data-content="mixed"][data-nested-dropdown="true"]
200
+ > wa-dropdown.kui-popup-menu
201
+ > wa-button,
202
+ .kui-toolbar-control-group[data-content="mixed"][data-nested-dropdown="true"]
203
+ > wa-dropdown.kui-popup-menu
204
+ > wa-button::part(base) {
205
+ min-width: max-content;
206
+ }
207
+ .kui-toolbar-control-group[data-content="mixed"][data-nested-dropdown="true"]
208
+ > wa-dropdown.kui-popup-menu
209
+ > wa-button::part(base) {
210
+ width: max-content;
211
+ }
212
+ .kui-toolbar-control-group[data-single="true"]
213
+ > wa-dropdown.kui-popup-menu
214
+ > wa-button::part(base) {
215
+ width: max-content;
216
+ }
217
+
218
+ /* The menu insets a composing parent asks for. A PopupMenu applies them to
219
+ itself; its default is the Select listbox inset above, which a
220
+ ToolbarControlGroup's `standard` inset keeps. A PopupSurface's inset follows
221
+ the group's, so a surface wins when both apply. */
222
+ .kui-toolbar-control-group[data-menu-inset="compact"]
223
+ wa-dropdown.kui-popup-menu::part(menu) {
224
+ padding: 0.25rem;
225
+ }
226
+ .kui-toolbar-control-group[data-menu-inset="list-zero"]
227
+ wa-dropdown.kui-popup-menu::part(menu) {
228
+ padding: 0;
229
+ }
230
+ .kui-popup-surface[data-inset="standard"]
231
+ > wa-dropdown.kui-popup-menu::part(menu) {
232
+ padding: var(--kui-wa-surface-inset, 0.5rem);
233
+ }
234
+ .kui-popup-surface[data-inset="compact"]
235
+ > wa-dropdown.kui-popup-menu::part(menu) {
236
+ padding: 0.25rem;
237
+ }
238
+ .kui-popup-surface[data-inset="list-zero"]
239
+ > wa-dropdown.kui-popup-menu::part(menu) {
240
+ padding: 0;
241
+ }
@@ -6,14 +6,22 @@
6
6
  --kui-resizable-region-handle-active-color: var(--kui-color-text-link);
7
7
  /* Extra track a horizontal region adds when it reaches an unsafe screen edge,
8
8
  so its surface paints through the unsafe area while its committed size
9
- stays the content width. A composing layout sets it on the region (a
10
- SplitView list does); it never inherits into a nested region. */
9
+ stays the content width. The region sets it itself from the context of a
10
+ layout that places it at an edge (a SplitView list); it never inherits
11
+ into a nested region. */
11
12
  --kui-resizable-region-edge-extent: 0px;
12
13
  position: relative;
13
14
  display: flex;
14
15
  min-width: 0;
15
16
  min-height: 0;
16
17
  }
18
+ /* As a split SplitView's list, the region's track grows by the unsafe
19
+ inline-start inset the SplitView provides, while its committed size stays
20
+ the content width. A collapsed region stays shut. */
21
+ .kui-split-view[data-split-mode="split"]
22
+ > .kui-resizable-region:not([data-collapsed="true"]) {
23
+ --kui-resizable-region-edge-extent: var(--_kui-split-view-safe-inline-start);
24
+ }
17
25
  .kui-resizable-region[data-axis="horizontal"] {
18
26
  width: calc(
19
27
  var(--kui-resizable-region-size) + var(--kui-resizable-region-edge-extent)
@@ -218,8 +226,9 @@
218
226
  hidden, not merely stacked beneath it: they never paint over the overlay
219
227
  whatever stacking context an app puts them in, and hidden they leave the
220
228
  tab order and the accessibility tree. They come back as the overlay
221
- closes. The flag is read by FloatingToolbar and the layouts' restore
222
- corners. It is set on the overlay's container and cleared again on the
229
+ closes. The ResizableRegion's own covered context,
230
+ `--_kui-resizable-region-covered`, is read by FloatingToolbar and the
231
+ layouts' restore corners. It is set on the overlay's container and cleared again on the
223
232
  overlay regions in it, so it reaches the overlay's siblings only. It is
224
233
  never set by a universal selector below the :has() container (`:has(…) >
225
234
  :not(…)`): Chromium then restyles every child of every ancestor of a DOM
@@ -231,7 +240,7 @@
231
240
  )
232
241
  )
233
242
  ) {
234
- --_kui-floating-covered: hidden;
243
+ --_kui-resizable-region-covered: hidden;
235
244
  }
236
245
  :where(
237
246
  :has(
@@ -241,7 +250,7 @@
241
250
  )
242
251
  )
243
252
  > .kui-resizable-region[data-presentation="overlay"] {
244
- --_kui-floating-covered: initial;
253
+ --_kui-resizable-region-covered: initial;
245
254
  }
246
255
 
247
256
  @container (max-width: 44rem) {
@@ -311,12 +320,15 @@
311
320
  --kui-resizable-region-restore-inset,
312
321
  1rem
313
322
  );
314
- /* The corner owns the inset, so a FloatingToolbar composed here floats
315
- from this point instead of adding its own inset on top. */
316
- --kui-floating-toolbar-inset: 0px;
317
323
  position: absolute;
318
324
  /* Hidden while an open side overlay covers the content (see above). */
319
- visibility: var(--_kui-floating-covered, inherit);
325
+ visibility: var(
326
+ --_kui-workbench-covered,
327
+ var(
328
+ --_kui-collapsible-panel-covered,
329
+ var(--_kui-resizable-region-covered, inherit)
330
+ )
331
+ );
320
332
  z-index: var(
321
333
  --kui-resizable-region-restore-z,
322
334
  calc(var(--kui-resizable-region-overlay-z, 41) - 2)
@@ -49,10 +49,10 @@
49
49
  caret wa-button): symmetric 8px inline padding, 12px from the icon to the
50
50
  caret's 20px box, the caret glyph size, and the control height, so the icon
51
51
  sits left of center to balance the caret. Inside a ToolbarControlGroup the
52
- trigger takes the group's control-slot height, overlap, and radius
53
- (`--_kui-toolbar-slot-*`) so it is inset evenly on every side, the group
54
- sizes to the trigger (wider than tall), and the group-owned focus ring
55
- stays concentric with it. */
52
+ trigger takes the control-slot height, overlap, and radius the group
53
+ provides (`--_kui-toolbar-control-group-slot-*`) so it is inset evenly on
54
+ every side, the group sizes to the trigger (wider than tall), and the
55
+ group-owned focus ring stays concentric with it. */
56
56
  .kui-select[data-selected-presentation="icon-only"] {
57
57
  --_kui-select-height: 2.75rem;
58
58
  width: max-content;
@@ -61,7 +61,10 @@
61
61
  --_kui-select-height: 2rem;
62
62
  }
63
63
  .kui-select[data-selected-presentation="icon-only"]::part(combobox) {
64
- min-height: var(--_kui-toolbar-slot-height, var(--_kui-select-height));
64
+ min-height: var(
65
+ --_kui-toolbar-control-group-slot-height,
66
+ var(--_kui-select-height)
67
+ );
65
68
  padding-inline: 0.5rem;
66
69
  border-radius: var(
67
70
  --kui-toolbar-item-radius,
@@ -72,14 +75,32 @@
72
75
  sibling controls it keeps the group's gap, end insets, and item radius, as
73
76
  they do. */
74
77
  .kui-select[data-selected-presentation="icon-only"]:only-child {
75
- margin-inline: calc(var(--_kui-toolbar-slot-overlap, 0px) * -1);
78
+ margin-inline: calc(var(--_kui-toolbar-control-group-slot-overlap, 0px) * -1);
76
79
  }
77
80
  .kui-select[data-selected-presentation="icon-only"]:only-child::part(combobox) {
78
81
  border-radius: var(
79
- --_kui-toolbar-slot-radius,
82
+ --_kui-toolbar-control-group-slot-radius,
80
83
  var(--kui-layout-rounded-radius, calc(1px + 0.6875rem))
81
84
  );
82
85
  }
86
+ /* In a ToolbarControlGroup, a Select beside other controls highlights its own
87
+ pill on hover, like its button and dropdown siblings; a lone Select instead
88
+ lifts the whole group (toolbar-control-group.css). */
89
+ .kui-toolbar-control-group:not([data-single="true"])
90
+ > .kui-select:not(:only-child):hover::part(combobox) {
91
+ border-color: var(--kui-toolbar-control-border);
92
+ background: var(--kui-toolbar-control-hover-background);
93
+ }
94
+ /* With the group's per-control rings, a composed Select paints its own ring
95
+ even when it was told the group owns it: nothing else would show focus. It
96
+ matches the sibling controls' ring and offset. While its listbox is open the
97
+ popup shows focus instead, so the trigger ring stays off, as a PopupMenu
98
+ trigger's does. */
99
+ .kui-toolbar-control-group[data-focus-ring="control"]
100
+ > .kui-select:not([open]):focus-within::part(combobox) {
101
+ outline: var(--kui-focus-ring);
102
+ outline-offset: 1px;
103
+ }
83
104
  /* The popup-menu wa-button draws the same chevron glyph at 0.875em inside a
84
105
  20px box; match its box, spacing, and glyph size rather than the smaller
85
106
  form-field disclosure scale. */
@@ -99,13 +120,6 @@
99
120
  .kui-select__icon[slot="start"] {
100
121
  margin-inline-end: 0 !important;
101
122
  }
102
- /* A multiple icon-only trigger: its fixed icon, then a count badge while any
103
- choice is chosen, 4px from the icon (the caret keeps its 12px after it).
104
- The summary that ends its label (and accessible name) stays inline text, so
105
- a visible label reads "Labels: Bug, Docs" in place of the hidden value. */
106
- .kui-select__count {
107
- margin-inline-start: 0.25rem;
108
- }
109
123
  .kui-select::part(start),
110
124
  .kui-select::part(end),
111
125
  .kui-select::part(expand-icon) {
@@ -7,9 +7,10 @@
7
7
  height: 1em;
8
8
  border-radius: var(--kui-skeleton-radius);
9
9
  /* Deliberately unanimated: a flat, subtle fill that reads as "not yet loaded"
10
- without drawing the eye or implying progress. A host with its own solid
11
- fill (a solid Badge) supplies `--_kui-skeleton-fill` derived from its
12
- foreground, since a text-color tint vanishes on a saturated fill. */
10
+ without drawing the eye or implying progress. On a host with its own
11
+ solid fill (a solid Badge) the skeleton derives `--_kui-skeleton-fill`
12
+ from the host's foreground, since a text-color tint vanishes on a
13
+ saturated fill. */
13
14
  background: var(
14
15
  --_kui-skeleton-fill,
15
16
  color-mix(in srgb, var(--kui-color-text) 12%, transparent)
@@ -17,6 +18,19 @@
17
18
  vertical-align: middle;
18
19
  }
19
20
 
21
+ /* A placeholder's skeleton inside a solid badge: the generic text-color tint is
22
+ nearly invisible on the saturated fill, so derive it from the on-solid
23
+ foreground the badge provides, which contrasts with the fill in every tone
24
+ and color scheme. Quiet and outline badges sit on a pale fill and keep the
25
+ generic tint. */
26
+ .kui-badge[data-appearance="solid"] .kui-skeleton {
27
+ --_kui-skeleton-fill: color-mix(
28
+ in srgb,
29
+ var(--_kui-badge-on-solid) 45%,
30
+ transparent
31
+ );
32
+ }
33
+
20
34
  .kui-skeleton[data-block="true"] {
21
35
  display: block;
22
36
  }
@@ -63,3 +77,16 @@
63
77
  background: GrayText;
64
78
  }
65
79
  }
80
+
81
+ /* A placeholder StateBanner's badge holds this skeleton instead of text. With
82
+ no text, the skeleton's baseline would be synthesized from its bottom edge,
83
+ sitting the badge higher than the live one by a font-dependent amount. A
84
+ zero-width character gives it a text baseline in the badge's own font and
85
+ line height, exactly where the live badge's text baseline falls on every
86
+ platform. */
87
+ .kui-state-banner[data-placeholder="true"]
88
+ .kui-state-banner__copy
89
+ > .kui-badge
90
+ > .kui-skeleton::before {
91
+ content: "\200b";
92
+ }
@@ -51,13 +51,6 @@
51
51
  min-height: 0;
52
52
  }
53
53
 
54
- /* A resizable list keeps its committed size as content width; its region's
55
- track grows by the unsafe inset it reaches. A collapsed region stays shut. */
56
- .kui-split-view[data-split-mode="split"]
57
- > [data-component="resizable-region"]:not([data-collapsed="true"]) {
58
- --kui-resizable-region-edge-extent: var(--_kui-split-view-safe-inline-start);
59
- }
60
-
61
54
  .kui-split-view__list,
62
55
  .kui-split-view__detail {
63
56
  --kui-edge-inset-block-start: var(--_kui-split-view-safe-block-start);
@@ -135,3 +128,13 @@
135
128
  display: block;
136
129
  height: 100%;
137
130
  }
131
+
132
+ /* As the only child of a Workbench region (its main area or a panel's
133
+ content, which the Workbench marks with `data-workbench-main` /
134
+ `data-workbench-panel-content`), a SplitView fills the region, so a
135
+ composed toolbar's footer (or the app's own) sits at the region's bottom
136
+ edge rather than under short content. */
137
+ :is([data-workbench-main], [data-workbench-panel-content])
138
+ > [data-component="split-view"]:only-child {
139
+ height: 100%;
140
+ }
@@ -160,25 +160,6 @@
160
160
  margin-inline-end: var(--kui-layout-item-gap, 0.5rem);
161
161
  font-size: var(--kui-font-xs);
162
162
  }
163
- /* The badge is taller than the title's line. Negative block margins keep it
164
- out of the line-height calculation, so a wrapped title's lines stay evenly
165
- spaced whichever line the badge lands on. */
166
- .kui-state-banner__badge {
167
- margin-block: -0.5em;
168
- margin-inline-end: var(--kui-layout-item-gap, 0.5rem);
169
- vertical-align: baseline;
170
- }
171
- /* A placeholder badge holds a skeleton instead of text. With no text, the
172
- skeleton's baseline would be synthesized from its bottom edge, sitting the
173
- badge higher than the live one by a font-dependent amount. A zero-width
174
- character gives it a text baseline in the badge's own font and line
175
- height, exactly where the live badge's text baseline falls on every
176
- platform. */
177
- .kui-state-banner[data-placeholder="true"]
178
- .kui-state-banner__badge
179
- > *::before {
180
- content: "\200b";
181
- }
182
163
  /* The clip lives on an inner span, not on the detail itself. WebKit still
183
164
  applies the CSS 2.1 rule that an inline-block whose overflow is not
184
165
  `visible` takes its baseline from its bottom margin edge, so a clipped
@@ -40,12 +40,17 @@
40
40
  .kui-popup-surface {
41
41
  display: inline-flex;
42
42
  }
43
- .kui-popup-surface[data-inset="standard"] > wa-dropdown::part(menu) {
43
+ /* The surface insets the menu of a raw wa-dropdown it wraps. A PopupMenu
44
+ applies the surface's inset to itself (popup-menu.css). */
45
+ .kui-popup-surface[data-inset="standard"]
46
+ > wa-dropdown:not(.kui-popup-menu)::part(menu) {
44
47
  padding: var(--kui-wa-surface-inset, 0.5rem);
45
48
  }
46
- .kui-popup-surface[data-inset="compact"] > wa-dropdown::part(menu) {
49
+ .kui-popup-surface[data-inset="compact"]
50
+ > wa-dropdown:not(.kui-popup-menu)::part(menu) {
47
51
  padding: 0.25rem;
48
52
  }
49
- .kui-popup-surface[data-inset="list-zero"] > wa-dropdown::part(menu) {
53
+ .kui-popup-surface[data-inset="list-zero"]
54
+ > wa-dropdown:not(.kui-popup-menu)::part(menu) {
50
55
  padding: 0;
51
56
  }
@@ -38,32 +38,17 @@
38
38
  --kui-tab-bar-background: var(--kui-color-neutral-fill-quiet);
39
39
  --kui-tab-bar-border: var(--kui-color-neutral-border-quiet);
40
40
  }
41
- /* A segmented strip's outer ends follow the pill track. The first tab's
42
- leading corners, and a filled strip's last tab's trailing corners, are
43
- pill-rounded, and a compact tab is inset from the track's ends by the same
44
- distance as from its top and bottom, so each end is concentric with the
45
- track. Only fill allocation carries the last tab to the track's trailing
46
- end; an intrinsic strip's last tab stops short of it and keeps the segment
47
- radius, as do the corners between tabs. */
41
+ /* A segmented strip's outer ends follow the pill track: a compact tab is inset
42
+ from the track's ends by the same distance as from its top and bottom, so
43
+ each end is concentric with the track. AppTab rounds its own outer corners
44
+ to match in this context (see app-tab.css); TabBar never styles AppTab. */
48
45
  .kui-tab-bar[data-presentation="segmented"]
49
- .kui-tab-bar__tabs:has(> [data-component="app-tab"][data-size="compact"]) {
46
+ .kui-tab-bar__tabs:has(> .kui-app-tab[data-size="compact"]) {
50
47
  padding-inline: calc(
51
48
  (var(--kui-toolbar-group-size, calc(2px + 2.625rem)) - 2rem) /
52
49
  2 - 1px
53
50
  );
54
51
  }
55
- .kui-tab-bar[data-presentation="segmented"]
56
- .kui-tab-bar__tabs
57
- > [data-component="app-tab"]:first-child {
58
- border-start-start-radius: var(--kui-radius-pill);
59
- border-end-start-radius: var(--kui-radius-pill);
60
- }
61
- .kui-tab-bar[data-presentation="segmented"][data-allocation="fill"]
62
- .kui-tab-bar__tabs
63
- > [data-component="app-tab"]:last-child {
64
- border-start-end-radius: var(--kui-radius-pill);
65
- border-end-end-radius: var(--kui-radius-pill);
66
- }
67
52
  .kui-tab-bar[data-presentation="inspector"] {
68
53
  min-height: 2.125rem;
69
54
  padding: 0;
@@ -72,14 +57,6 @@
72
57
  min-height: 2.125rem;
73
58
  border-radius: var(--kui-radius-s);
74
59
  }
75
- .kui-tab-bar[data-allocation="fill"] [data-component="app-tab"] {
76
- min-width: 0;
77
- flex: 1 1 0;
78
- }
79
- .kui-tab-bar[data-allocation="fill"] [data-component="app-tab"] > [role="tab"] {
80
- width: 100%;
81
- justify-content: center;
82
- }
83
60
  .kui-tab-bar[data-trailing-placement="adjacent"] .kui-tab-bar__tabs {
84
61
  flex: 0 1 auto;
85
62
  }
@@ -100,3 +77,77 @@
100
77
  .kui-tab-bar__end {
101
78
  margin-inline-start: auto;
102
79
  }
80
+
81
+ /* Overflow dividers: a line on each side of the tab strip beyond which tabs
82
+ are scrolled out of view, as `wireScrollDividers` reports through the
83
+ strip's `data-scroll-overflow` (physical sides). A rail strip has no
84
+ visible track, so the bar draws the line with its own pseudo-elements,
85
+ ordered onto the strip's edges: `::before` between the leading zone and the
86
+ strip, `::after` between the strip and the trailing zone. Each is 1px wide
87
+ and gives back its width and one gap through a negative margin, so it
88
+ overlaps the strip's edge and never moves a tab or an action; hidden, it is
89
+ transparent. A segmented or inspector strip already draws a bordered track,
90
+ so its overflowing side takes the divider color on that border instead of
91
+ a straight line across its rounded end. */
92
+ .kui-tab-bar > .kui-tab-bar__leading {
93
+ order: -2;
94
+ }
95
+
96
+ .kui-tab-bar > :is(.kui-tab-bar__trailing, .kui-tab-bar__end) {
97
+ order: 1;
98
+ }
99
+
100
+ .kui-tab-bar::before,
101
+ .kui-tab-bar::after {
102
+ content: "";
103
+ position: relative;
104
+ z-index: 1;
105
+ width: 1px;
106
+ background: transparent;
107
+ pointer-events: none;
108
+ align-self: stretch;
109
+ flex: none;
110
+ }
111
+
112
+ .kui-tab-bar::before {
113
+ order: -1;
114
+ margin-inline-end: calc(-1px - var(--kui-toolbar-gap, 0.5rem));
115
+ }
116
+
117
+ .kui-tab-bar::after {
118
+ margin-inline-start: calc(-1px - var(--kui-toolbar-gap, 0.5rem));
119
+ }
120
+
121
+ .kui-tab-bar[data-presentation="rail"]:dir(ltr):has(
122
+ > .kui-tab-bar__tabs[data-scroll-overflow*="l"]
123
+ )::before,
124
+ .kui-tab-bar[data-presentation="rail"]:dir(rtl):has(
125
+ > .kui-tab-bar__tabs[data-scroll-overflow*="r"]
126
+ )::before,
127
+ .kui-tab-bar[data-presentation="rail"]:dir(ltr):has(
128
+ > .kui-tab-bar__tabs[data-scroll-overflow*="r"]
129
+ )::after,
130
+ .kui-tab-bar[data-presentation="rail"]:dir(rtl):has(
131
+ > .kui-tab-bar__tabs[data-scroll-overflow*="l"]
132
+ )::after {
133
+ background: var(
134
+ --kui-tab-bar-divider-color,
135
+ var(--kui-color-neutral-border-normal)
136
+ );
137
+ }
138
+
139
+ .kui-tab-bar:not([data-presentation="rail"])
140
+ > .kui-tab-bar__tabs[data-scroll-overflow*="l"] {
141
+ border-left-color: var(
142
+ --kui-tab-bar-divider-color,
143
+ var(--kui-color-neutral-border-normal)
144
+ );
145
+ }
146
+
147
+ .kui-tab-bar:not([data-presentation="rail"])
148
+ > .kui-tab-bar__tabs[data-scroll-overflow*="r"] {
149
+ border-right-color: var(
150
+ --kui-tab-bar-divider-color,
151
+ var(--kui-color-neutral-border-normal)
152
+ );
153
+ }
@@ -96,10 +96,24 @@
96
96
  );
97
97
  padding-inline: var(--_kui-tab-scaffold-safe-inline-start)
98
98
  var(--_kui-tab-scaffold-safe-inline-end);
99
- border-block-start: 1px solid var(--kui-color-neutral-border-normal);
99
+ /* Chrome divider: with `chromeDividers="scroll"` (the default, no
100
+ attribute) the bar's 1px top border shows only while the active scene's
101
+ content continues below it — never at the scroll end or when the content
102
+ fits. `wireScrollDividers` reports that state through
103
+ `data-scroll-divider`; `always` shows it without the wiring, and `none`
104
+ never. The border is always there and only its color changes, so
105
+ showing it never moves the bar or a tab. */
106
+ border-block-start: 1px solid
107
+ var(--_kui-tab-scaffold-bar-divider, transparent);
100
108
  background: var(--kui-color-surface);
101
109
  }
102
110
 
111
+ .kui-tab-scaffold:not([data-chrome-dividers])
112
+ > .kui-tab-scaffold__bar[data-scroll-divider*="t"],
113
+ .kui-tab-scaffold[data-chrome-dividers="always"] > .kui-tab-scaffold__bar {
114
+ --_kui-tab-scaffold-bar-divider: var(--kui-color-neutral-border-normal);
115
+ }
116
+
103
117
  .kui-tab-scaffold__tab {
104
118
  display: flex;
105
119
  flex: 1 1 0;
@@ -168,3 +182,13 @@
168
182
  text-overflow: ellipsis;
169
183
  white-space: nowrap;
170
184
  }
185
+
186
+ /* As the only child of a Workbench region (its main area or a panel's
187
+ content, which the Workbench marks with `data-workbench-main` /
188
+ `data-workbench-panel-content`), a TabScaffold fills the region, so a
189
+ composed toolbar's footer (or the app's own) sits at the region's bottom
190
+ edge rather than under short content. */
191
+ :is([data-workbench-main], [data-workbench-panel-content])
192
+ > [data-component="tab-scaffold"]:only-child {
193
+ height: 100%;
194
+ }
@@ -30,3 +30,19 @@ span.kui-text {
30
30
  border: 0;
31
31
  padding: 0;
32
32
  }
33
+
34
+ /* A ListHeader's label: the title's single text child, set as a compact,
35
+ uppercase, single-line label that truncates with an ellipsis. The title is
36
+ a div around a heading or, for a toggle header, the toggle button around
37
+ an inline span. */
38
+ .kui-list-header__title > .kui-text {
39
+ min-width: 0;
40
+ margin: 0;
41
+ overflow: hidden;
42
+ font-size: var(--kui-font-xs);
43
+ font-weight: 650;
44
+ letter-spacing: 0.04em;
45
+ text-overflow: ellipsis;
46
+ text-transform: uppercase;
47
+ white-space: nowrap;
48
+ }