@kerfjs/ui 5.0.0-beta.105 → 5.0.0-beta.107

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 (227) hide show
  1. package/README.md +2 -1
  2. package/ai/application-ui-diagnostic-ids-v1.json +1 -0
  3. package/ai/application-ui-profile.defaults.json +6 -1
  4. package/ai/component-catalog.json +160 -27
  5. package/ai/component-composition-rules.json +20 -2
  6. package/ai/component-composition.d.ts +11 -0
  7. package/ai/component-composition.json +118 -19
  8. package/ai/component-composition.schema.json +32 -0
  9. package/ai/components/README.md +3 -2
  10. package/ai/components/button.md +4 -1
  11. package/ai/components/checkbox-group.md +89 -0
  12. package/ai/components/checkbox.md +3 -2
  13. package/ai/components/color-picker.md +10 -7
  14. package/ai/components/disclosure.md +6 -1
  15. package/ai/components/foundation.md +1 -1
  16. package/ai/components/list-detail-dialog.md +1 -1
  17. package/ai/components/message-composer.md +2 -1
  18. package/ai/components/radio-group.md +4 -3
  19. package/ai/components/split-button.md +5 -2
  20. package/ai/components/surface-scaffold.md +2 -1
  21. package/ai/components/switch.md +1 -1
  22. package/ai/components/text.md +2 -0
  23. package/ai/components/wa-checkbox-group.md +5 -5
  24. package/ai/components/workbench-dialog.md +1 -1
  25. package/ai/public-api-signatures-v1.md +198 -26
  26. package/ai/skill.md +73 -62
  27. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  28. package/dist/browser/checkbox-group.js +5 -0
  29. package/dist/button.d.ts +15 -2
  30. package/dist/button.js +1 -1
  31. package/dist/catalog.js +9 -8
  32. package/dist/catalog.js.map +1 -1
  33. package/dist/checkbox-group.d.ts +70 -0
  34. package/dist/checkbox-group.js +7 -0
  35. package/dist/checkbox-group.js.map +1 -0
  36. package/dist/{chunk-SQ2Q3OQI.js → chunk-2LM3PYHA.js} +2 -2
  37. package/dist/{chunk-SQ2Q3OQI.js.map → chunk-2LM3PYHA.js.map} +1 -1
  38. package/dist/{chunk-HYORKKYP.js → chunk-3VZ6SFD4.js} +1 -1
  39. package/dist/chunk-3VZ6SFD4.js.map +1 -0
  40. package/dist/{chunk-EKBMUXFV.js → chunk-3Z7N2NAZ.js} +141 -54
  41. package/dist/chunk-3Z7N2NAZ.js.map +1 -0
  42. package/dist/{chunk-FKKJHGN5.js → chunk-AZ3WT77F.js} +2 -2
  43. package/dist/{chunk-FKKJHGN5.js.map → chunk-AZ3WT77F.js.map} +1 -1
  44. package/dist/{chunk-FG6U7KQQ.js → chunk-DNWWF6UN.js} +2 -2
  45. package/dist/{chunk-FG6U7KQQ.js.map → chunk-DNWWF6UN.js.map} +1 -1
  46. package/dist/{chunk-C3RLKKFQ.js → chunk-EYDXFOSH.js} +13 -8
  47. package/dist/chunk-EYDXFOSH.js.map +1 -0
  48. package/dist/{chunk-TAHR457X.js → chunk-G4DRH4A5.js} +3 -1
  49. package/dist/chunk-G4DRH4A5.js.map +1 -0
  50. package/dist/{chunk-PE2KPZDW.js → chunk-HDXUHLTQ.js} +7 -2
  51. package/dist/chunk-HDXUHLTQ.js.map +1 -0
  52. package/dist/chunk-HU5IHXCI.js +73 -0
  53. package/dist/chunk-HU5IHXCI.js.map +1 -0
  54. package/dist/{chunk-DF2YKGIX.js → chunk-JCCN3U6X.js} +2 -2
  55. package/dist/{chunk-DF2YKGIX.js.map → chunk-JCCN3U6X.js.map} +1 -1
  56. package/dist/{chunk-GCAK23PU.js → chunk-MVKHSAKE.js} +2 -2
  57. package/dist/{chunk-GCAK23PU.js.map → chunk-MVKHSAKE.js.map} +1 -1
  58. package/dist/{chunk-DDSCVEO5.js → chunk-NLMEDZRM.js} +5 -5
  59. package/dist/{chunk-DDSCVEO5.js.map → chunk-NLMEDZRM.js.map} +1 -1
  60. package/dist/{chunk-ECFCAKWE.js → chunk-NR6O74ST.js} +5 -1
  61. package/dist/chunk-NR6O74ST.js.map +1 -0
  62. package/dist/{chunk-7W3GKMN4.js → chunk-OQP3PFKQ.js} +7 -4
  63. package/dist/chunk-OQP3PFKQ.js.map +1 -0
  64. package/dist/{chunk-WJKHLOP5.js → chunk-TI2GV36S.js} +8 -2
  65. package/dist/chunk-TI2GV36S.js.map +1 -0
  66. package/dist/{chunk-UTCAOOXU.js → chunk-TXRKCGT3.js} +8 -2
  67. package/dist/chunk-TXRKCGT3.js.map +1 -0
  68. package/dist/{chunk-ACUKTVS3.js → chunk-XWNXGFX3.js} +52 -42
  69. package/dist/chunk-XWNXGFX3.js.map +1 -0
  70. package/dist/{chunk-ZXZAECHZ.js → chunk-Z4DS77U2.js} +2 -2
  71. package/dist/{chunk-ZXZAECHZ.js.map → chunk-Z4DS77U2.js.map} +1 -1
  72. package/dist/collapsible-panel.js +2 -2
  73. package/dist/color-picker.d.ts +30 -5
  74. package/dist/color-picker.js +1 -1
  75. package/dist/disclosure.d.ts +13 -4
  76. package/dist/disclosure.js +1 -1
  77. package/dist/disclosure.js.map +1 -1
  78. package/dist/help-tags-register.js +1 -1
  79. package/dist/index.d.ts +2 -1
  80. package/dist/index.js +20 -19
  81. package/dist/list-action-row.js +1 -1
  82. package/dist/list-detail-dialog.d.ts +7 -1
  83. package/dist/list-detail-dialog.js +6 -4
  84. package/dist/list-detail-dialog.js.map +1 -1
  85. package/dist/list-header.d.ts +8 -1
  86. package/dist/list-header.js +1 -1
  87. package/dist/nav-stack.js +1 -1
  88. package/dist/popup-menu-register.js +2 -2
  89. package/dist/popup-menu.d.ts +15 -5
  90. package/dist/popup-menu.js +1 -1
  91. package/dist/select-register.js +3 -3
  92. package/dist/split-button.d.ts +14 -2
  93. package/dist/split-button.js +1 -1
  94. package/dist/split-view.js +1 -1
  95. package/dist/styles/anchored-surface.css +3 -0
  96. package/dist/styles/button.css +29 -0
  97. package/dist/styles/catalog/components/catalog-example.css +55 -18
  98. package/dist/styles/checkbox-group.css +63 -0
  99. package/dist/styles/checkbox.css +7 -6
  100. package/dist/styles/color-picker.css +69 -34
  101. package/dist/styles/components/actions/button/button.css +29 -0
  102. package/dist/styles/components/actions/split-button/split-button.css +51 -5
  103. package/dist/styles/components/collections/framed-list/framed-list.css +4 -0
  104. package/dist/styles/components/collections/list/list.css +6 -0
  105. package/dist/styles/components/collections/list-header/list-header.css +7 -0
  106. package/dist/styles/components/feedback/anchored-surface/anchored-surface.css +3 -0
  107. package/dist/styles/components/forms/checkbox/checkbox.css +7 -6
  108. package/dist/styles/components/forms/checkbox-group/checkbox-group.css +63 -0
  109. package/dist/styles/components/forms/color-picker/color-picker.css +69 -34
  110. package/dist/styles/components/forms/radio-group/radio-group.css +7 -5
  111. package/dist/styles/components/forms/select/select.css +6 -2
  112. package/dist/styles/components/forms/switch/switch.css +3 -3
  113. package/dist/styles/components/layout/pane/pane.css +9 -0
  114. package/dist/styles/components/layout/workbench/workbench.css +4 -0
  115. package/dist/styles/components/navigation/nav-stack/nav-stack.css +64 -1
  116. package/dist/styles/components/navigation/tab-navigator/tab-navigator.css +1 -0
  117. package/dist/styles/components/surfaces/content-item/content-item.css +30 -0
  118. package/dist/styles/components/surfaces/disclosure/disclosure.css +38 -0
  119. package/dist/styles/components/surfaces/sunken-panel/sunken-panel.css +3 -0
  120. package/dist/styles/components/surfaces/surface-scaffold/surface-scaffold.css +6 -0
  121. package/dist/styles/components/typography/text/text.css +10 -0
  122. package/dist/styles/content-item.css +30 -0
  123. package/dist/styles/disclosure.css +38 -0
  124. package/dist/styles/foundation.css +21 -0
  125. package/dist/styles/framed-list.css +4 -0
  126. package/dist/styles/list-header.css +7 -0
  127. package/dist/styles/list.css +6 -0
  128. package/dist/styles/nav-stack.css +64 -1
  129. package/dist/styles/pane.css +9 -0
  130. package/dist/styles/radio-group.css +7 -5
  131. package/dist/styles/select.css +6 -2
  132. package/dist/styles/split-button.css +51 -5
  133. package/dist/styles/styles.css +1 -0
  134. package/dist/styles/sunken-panel.css +3 -0
  135. package/dist/styles/surface-scaffold.css +6 -0
  136. package/dist/styles/switch.css +3 -3
  137. package/dist/styles/tab-navigator.css +1 -0
  138. package/dist/styles/text.css +10 -0
  139. package/dist/styles/webawesome.css +45 -9
  140. package/dist/styles/workbench.css +4 -0
  141. package/dist/surface-scaffold.d.ts +7 -1
  142. package/dist/surface-scaffold.js +1 -1
  143. package/dist/wire-color-fields.js +2 -2
  144. package/dist/wire-color-pickers.d.ts +4 -3
  145. package/dist/wire-color-pickers.js +1 -1
  146. package/dist/wire-comboboxes.js +1 -1
  147. package/dist/workbench-dialog.d.ts +11 -2
  148. package/dist/workbench-dialog.js +5 -2
  149. package/dist/workbench-dialog.js.map +1 -1
  150. package/dist/workbench.js +1 -1
  151. package/docs/accessibility.md +40 -1
  152. package/docs/anchored-surface.md +6 -1
  153. package/docs/catalog.md +26 -1
  154. package/docs/color-picker.md +39 -8
  155. package/docs/component-contract.md +33 -2
  156. package/docs/component-selection.md +20 -9
  157. package/docs/design/templates/button/full-width-dark.svg +1 -0
  158. package/docs/design/templates/button/full-width.svg +1 -0
  159. package/docs/design/templates/button-dark.svg +1 -1
  160. package/docs/design/templates/button.svg +1 -1
  161. package/docs/design/templates/checkbox/error-dark.svg +1 -1
  162. package/docs/design/templates/checkbox/error.svg +1 -1
  163. package/docs/design/templates/checkbox/states-dark.svg +1 -1
  164. package/docs/design/templates/checkbox/states.svg +1 -1
  165. package/docs/design/templates/checkbox-dark.svg +1 -1
  166. package/docs/design/templates/checkbox-group/horizontal-dark.svg +1 -0
  167. package/docs/design/templates/checkbox-group/horizontal.svg +1 -0
  168. package/docs/design/templates/checkbox-group/vertical-dark.svg +1 -0
  169. package/docs/design/templates/checkbox-group/vertical.svg +1 -0
  170. package/docs/design/templates/checkbox-group-dark.svg +1 -0
  171. package/docs/design/templates/checkbox-group.svg +1 -0
  172. package/docs/design/templates/checkbox.svg +1 -1
  173. package/docs/design/templates/color-picker/gray-dark.svg +1 -1
  174. package/docs/design/templates/color-picker/gray.svg +1 -1
  175. package/docs/design/templates/color-picker/hsb-dark.svg +1 -0
  176. package/docs/design/templates/color-picker/hsb.svg +1 -0
  177. package/docs/design/templates/color-picker/rgb-dark.svg +1 -1
  178. package/docs/design/templates/color-picker/rgb.svg +1 -1
  179. package/docs/design/templates/color-picker-dark.svg +1 -1
  180. package/docs/design/templates/color-picker.svg +1 -1
  181. package/docs/design/templates/disclosure/embedded-dark.svg +1 -0
  182. package/docs/design/templates/disclosure/embedded.svg +1 -0
  183. package/docs/design/templates/disclosure-dark.svg +1 -1
  184. package/docs/design/templates/disclosure.svg +1 -1
  185. package/docs/design/templates/radio-group/horizontal-dark.svg +1 -1
  186. package/docs/design/templates/radio-group/horizontal.svg +1 -1
  187. package/docs/design/templates/radio-group/vertical-dark.svg +1 -1
  188. package/docs/design/templates/radio-group/vertical.svg +1 -1
  189. package/docs/design/templates/radio-group-dark.svg +1 -1
  190. package/docs/design/templates/radio-group.svg +1 -1
  191. package/docs/design/templates/split-button/full-width-dark.svg +1 -0
  192. package/docs/design/templates/split-button/full-width.svg +1 -0
  193. package/docs/design/templates/split-button/pill-dark.svg +1 -0
  194. package/docs/design/templates/split-button/pill.svg +1 -0
  195. package/docs/design/templates/split-button/states-dark.svg +1 -0
  196. package/docs/design/templates/split-button/states.svg +1 -0
  197. package/docs/design/templates/split-button/tones-dark.svg +1 -0
  198. package/docs/design/templates/split-button/tones.svg +1 -0
  199. package/docs/design/templates/split-button-dark.svg +1 -0
  200. package/docs/design/templates/split-button.svg +1 -0
  201. package/docs/design/templates/switch/states-dark.svg +1 -1
  202. package/docs/design/templates/switch/states.svg +1 -1
  203. package/docs/design/templates/switch-dark.svg +1 -1
  204. package/docs/design/templates/switch.svg +1 -1
  205. package/docs/design/templates.md +10 -3
  206. package/docs/disclosure.md +34 -0
  207. package/docs/list-detail-dialog.md +4 -0
  208. package/docs/nav-stack.md +6 -2
  209. package/docs/surface-scaffold.md +6 -2
  210. package/docs/ui-doctor.md +16 -4
  211. package/docs/webawesome-migration.md +1 -1
  212. package/docs/webawesome-theme.md +48 -16
  213. package/docs/workbench-dialog.md +4 -1
  214. package/docs/writing.md +3 -3
  215. package/doctor/copy-capitalization-checks.mjs +10 -7
  216. package/llms.txt +50 -20
  217. package/package.json +7 -1
  218. package/dist/chunk-7W3GKMN4.js.map +0 -1
  219. package/dist/chunk-ACUKTVS3.js.map +0 -1
  220. package/dist/chunk-C3RLKKFQ.js.map +0 -1
  221. package/dist/chunk-ECFCAKWE.js.map +0 -1
  222. package/dist/chunk-EKBMUXFV.js.map +0 -1
  223. package/dist/chunk-HYORKKYP.js.map +0 -1
  224. package/dist/chunk-PE2KPZDW.js.map +0 -1
  225. package/dist/chunk-TAHR457X.js.map +0 -1
  226. package/dist/chunk-UTCAOOXU.js.map +0 -1
  227. package/dist/chunk-WJKHLOP5.js.map +0 -1
@@ -11,10 +11,14 @@
11
11
  border: 1px solid var(--kui-framed-list-border);
12
12
  border-radius: var(--kui-layout-rounded-radius, calc(1px + 0.6875rem));
13
13
  background: var(--kui-color-surface-lowered);
14
+ --kui-color-surface-current-tint: var(--kui-color-surface-lowered);
14
15
  list-style: none;
15
16
  }
16
17
 
17
18
  .kui-framed-list[data-surface="base"] {
19
+ --kui-color-surface-current: var(--kui-color-surface);
20
+ --kui-color-surface-current-region: transparent;
21
+ --kui-color-surface-current-tint: transparent;
18
22
  background: var(--kui-color-surface);
19
23
  }
20
24
 
@@ -29,6 +29,13 @@
29
29
  padding-block: var(--kui-list-header-title-padding-block, 0.25rem);
30
30
  }
31
31
 
32
+ /* Wrapped label lines keep the compact header's 4px block inset off the
33
+ header edges; a one-line label still centers in the unchanged minimum
34
+ height. */
35
+ .kui-list-header[data-wrap="true"] .kui-list-header__title {
36
+ padding-block: var(--kui-list-header-title-padding-block, 0.25rem);
37
+ }
38
+
32
39
  .kui-list-header[data-divider="before"],
33
40
  .kui-list-header[data-divider="both"] {
34
41
  border-block-start: 1px solid
@@ -273,10 +273,16 @@
273
273
 
274
274
  /* `surface`: a solid background behind the stack and its insets. */
275
275
  .kui-list[data-surface="base"] {
276
+ --kui-color-surface-current: var(--kui-color-surface);
277
+ --kui-color-surface-current-region: transparent;
278
+ --kui-color-surface-current-tint: transparent;
276
279
  background: var(--kui-color-surface);
277
280
  }
278
281
 
279
282
  .kui-list[data-surface="raised"] {
283
+ --kui-color-surface-current: var(--kui-color-surface-raised);
284
+ --kui-color-surface-current-region: transparent;
285
+ --kui-color-surface-current-tint: transparent;
280
286
  background: var(--kui-color-surface-raised);
281
287
  }
282
288
 
@@ -291,6 +291,63 @@
291
291
  }
292
292
  }
293
293
 
294
+ /* An overlay bar cross-fades its contents, never its material. Fading the
295
+ bar itself would fade its backdrop filter with it (WebKit drops the blur
296
+ outright), so mid push or pop the sliding views would show through the
297
+ chrome. Instead the live bar keeps its material at full opacity while its
298
+ contents fade in, and the copy cross-fading out above it carries no
299
+ material of its own (nor a clear bar's scroll edge), only the old
300
+ contents and divider. */
301
+ .kui-nav-stack[data-chrome-presentation="overlay"] > .kui-nav-stack__chrome,
302
+ .kui-nav-stack[data-bottom-toolbar-presentation="overlay"]
303
+ > .kui-nav-stack__bottom {
304
+ opacity: 1;
305
+ transition: none;
306
+ }
307
+
308
+ .kui-nav-stack[data-chrome-presentation="overlay"]
309
+ > .kui-nav-stack__chrome:not(.kui-nav-stack__chrome-copy)
310
+ > *,
311
+ .kui-nav-stack[data-bottom-toolbar-presentation="overlay"]
312
+ > .kui-nav-stack__bottom:not(.kui-nav-stack__chrome-copy)
313
+ > * {
314
+ transition: opacity var(--kui-nav-stack-transition-duration, 200ms) ease;
315
+ }
316
+
317
+ .kui-nav-stack[data-chrome-presentation="overlay"]
318
+ > .kui-nav-stack__chrome--entering:not(.kui-nav-stack__chrome-copy)
319
+ > *,
320
+ .kui-nav-stack[data-bottom-toolbar-presentation="overlay"]
321
+ > .kui-nav-stack__chrome--entering:not(.kui-nav-stack__chrome-copy)
322
+ > * {
323
+ transition: none;
324
+ opacity: 0;
325
+ }
326
+
327
+ .kui-nav-stack[data-chrome-presentation="overlay"]
328
+ > .kui-nav-stack__chrome.kui-nav-stack__chrome-copy,
329
+ .kui-nav-stack[data-bottom-toolbar-presentation="overlay"]
330
+ > .kui-nav-stack__bottom.kui-nav-stack__chrome-copy {
331
+ -webkit-backdrop-filter: none;
332
+ backdrop-filter: none;
333
+ background: transparent;
334
+ transition: opacity var(--kui-nav-stack-transition-duration, 200ms) ease;
335
+ }
336
+
337
+ .kui-nav-stack[data-chrome-presentation="overlay"]
338
+ > .kui-nav-stack__chrome.kui-nav-stack__chrome-copy--exiting,
339
+ .kui-nav-stack[data-bottom-toolbar-presentation="overlay"]
340
+ > .kui-nav-stack__bottom.kui-nav-stack__chrome-copy--exiting {
341
+ opacity: 0;
342
+ }
343
+
344
+ .kui-nav-stack[data-chrome-material="clear"][data-scroll-edge]
345
+ > .kui-nav-stack__chrome.kui-nav-stack__chrome-copy::before,
346
+ .kui-nav-stack[data-bottom-toolbar-material="clear"][data-scroll-edge]
347
+ > .kui-nav-stack__bottom.kui-nav-stack__chrome-copy::before {
348
+ content: none;
349
+ }
350
+
294
351
  /* `clear` chrome and bottom toolbar: overlay bars (the same measuring,
295
352
  placement, and edge insets as above) that are fully transparent, for
296
353
  chrome over imagery. With `scrollEdge="material"` a pseudo-element
@@ -521,7 +578,13 @@
521
578
  .kui-nav-stack__view,
522
579
  .kui-nav-stack__chrome,
523
580
  .kui-nav-stack__bottom,
524
- .kui-nav-stack__chrome-copy {
581
+ .kui-nav-stack__chrome-copy,
582
+ .kui-nav-stack[data-chrome-presentation="overlay"]
583
+ > .kui-nav-stack__chrome
584
+ > *,
585
+ .kui-nav-stack[data-bottom-toolbar-presentation="overlay"]
586
+ > .kui-nav-stack__bottom
587
+ > * {
525
588
  transition: none;
526
589
  }
527
590
  }
@@ -45,10 +45,12 @@
45
45
  root scroll in its short mode, while its content remains transparent. */
46
46
  .kui-pane[data-appearance="sunken"] > .kui-pane__content {
47
47
  background: var(--kui-sunken-panel-background, var(--kui-sunken-surface));
48
+ --kui-color-surface-current-region: var(--kui-color-surface-lowered);
48
49
  }
49
50
 
50
51
  .kui-pane[data-appearance="sunken"][data-chrome-placement="auto"] {
51
52
  background: var(--kui-sunken-panel-background, var(--kui-sunken-surface));
53
+ --kui-color-surface-current-region: var(--kui-color-surface-lowered);
52
54
  }
53
55
 
54
56
  .kui-pane[data-appearance="sunken"][data-chrome-placement="auto"]
@@ -56,8 +58,15 @@
56
58
  background: transparent;
57
59
  }
58
60
 
61
+ /* The surface context follows the paint: the auto chrome is opaque again. */
59
62
  .kui-pane[data-appearance="sunken"][data-chrome-placement="auto"]
60
63
  > :is(.kui-pane__header, .kui-pane__footer) {
64
+ --kui-color-surface-current: var(
65
+ --kui-pane-chrome-background,
66
+ var(--kui-color-surface)
67
+ );
68
+ --kui-color-surface-current-region: transparent;
69
+ --kui-color-surface-current-tint: transparent;
61
70
  background: var(--kui-pane-chrome-background, var(--kui-color-surface));
62
71
  }
63
72
 
@@ -1,6 +1,9 @@
1
- /* RadioGroup: the group label, the choices on the text column (each a drawn
2
- circle beside its label, the native radio invisibly over the circle), and
3
- hint and error text below. */
1
+ /* RadioGroup: the group label, the choices (each a drawn circle beside its
2
+ label, the native radio invisibly over the circle), and hint and error text
3
+ below. Each circle sits on the group's inline-start edge, where a
4
+ Checkbox draws its box, so stacked checkboxes and radios share one control
5
+ column, and stacked choices sit 8px apart: the same 28px pitch as Checkboxes
6
+ in a List gap="xs". */
4
7
  .kui-radio-group {
5
8
  --_kui-radio-group-size: 1.25rem;
6
9
  --_kui-radio-group-gap: 0.5rem;
@@ -36,8 +39,7 @@
36
39
  .kui-radio-group__choices {
37
40
  display: flex;
38
41
  flex-direction: column;
39
- gap: 0.75rem;
40
- padding-inline: var(--kui-layout-item-padding, 0.5rem);
42
+ gap: var(--kui-space-xs);
41
43
  }
42
44
  .kui-radio-group[data-orientation="horizontal"] .kui-radio-group__choices {
43
45
  flex-direction: row;
@@ -67,8 +67,12 @@
67
67
  outline-color: transparent;
68
68
  }
69
69
  /* Focus shows on the control (pointer or keyboard), but not while its
70
- listbox is open: the listbox shows where focus is then. */
71
- .kui-select:not([open]):focus-within > .kui-select__trigger {
70
+ listbox is open: the listbox shows where focus is then. A Select whose
71
+ enclosing group owns the ring (`focusRingOwner="group"`) never paints its
72
+ own here: the exclusion lives in this selector, not in a later override,
73
+ because the focus state outranks any plain owner rule. */
74
+ .kui-select:not([data-focus-ring-owner="group"]):not([open]):focus-within
75
+ > .kui-select__trigger {
72
76
  outline: var(--kui-focus-ring);
73
77
  outline-offset: 1px;
74
78
  }
@@ -1,20 +1,32 @@
1
1
  /* One loud semantic fill split into a primary half and a narrow options
2
2
  trigger, with a hairline divider in the foreground color. Both halves are
3
- native buttons on the shared fill; each brightens on its own hover. */
3
+ native buttons on the shared fill; each brightens on its own hover. The
4
+ outer corners take the shared control radius, or full round ends as a
5
+ pill; the divider seam between the halves stays square. */
4
6
  .kui-split-button {
5
7
  --_kui-split-button-fill: var(--kui-color-brand-fill-loud);
6
8
  --_kui-split-button-on: var(--kui-color-brand-on-loud);
9
+ --_kui-split-button-radius: var(
10
+ --kui-layout-rounded-radius,
11
+ calc(1px + 0.6875rem)
12
+ );
7
13
  display: inline-grid;
8
14
  min-width: 0;
9
15
  min-height: 2.75rem;
10
- overflow: hidden;
11
- border-radius: var(--kui-layout-rounded-radius, calc(1px + 0.6875rem));
16
+ border-radius: var(--_kui-split-button-radius);
12
17
  color: var(--_kui-split-button-on);
13
18
  background: var(--_kui-split-button-fill);
14
19
  grid-template-columns: minmax(0, auto) 2.5rem;
15
20
  font-weight: var(--kui-font-weight-semibold);
16
21
  }
17
22
 
23
+ .kui-split-button[data-shape="pill"] {
24
+ --_kui-split-button-radius: var(
25
+ --kui-layout-pill-radius,
26
+ calc(1px + 1.3125rem)
27
+ );
28
+ }
29
+
18
30
  .kui-split-button[data-tone="neutral"] {
19
31
  --_kui-split-button-fill: var(--kui-color-neutral-fill-loud);
20
32
  --_kui-split-button-on: var(--kui-color-neutral-on-loud);
@@ -50,6 +62,7 @@
50
62
  padding-inline: var(--kui-space-s);
51
63
  border: 0;
52
64
  border-radius: 0;
65
+ appearance: none;
53
66
  color: inherit;
54
67
  background: transparent;
55
68
  cursor: pointer;
@@ -69,11 +82,44 @@
69
82
  background: color-mix(in srgb, currentColor 12%, transparent);
70
83
  }
71
84
 
72
- /* The group clips outer outlines at its rounded corners, so the ring sits
73
- inside each half. */
85
+ /* Each half rounds its outer corners with the group, so its hover fill and
86
+ focus ring follow the rounded or pill end. The group does not clip, so
87
+ these radii are what keep a half's fill inside the group's corners. */
88
+ .kui-split-button > .kui-split-button__primary {
89
+ border-start-start-radius: var(--_kui-split-button-radius);
90
+ border-end-start-radius: var(--_kui-split-button-radius);
91
+ }
92
+
93
+ .kui-split-button > .kui-split-button__options {
94
+ border-start-end-radius: var(--_kui-split-button-radius);
95
+ border-end-end-radius: var(--_kui-split-button-radius);
96
+ }
97
+
98
+ /* The ring sits outside the focused half, offset like Button's, so it is
99
+ drawn against the surrounding surface rather than the loud fill, whose
100
+ brand color can match the ring's own (an inset ring vanished there). The
101
+ segment along the divider overlaps the neighboring half, painted above it. */
102
+ .kui-split-button > button:focus {
103
+ outline: none;
104
+ }
105
+
74
106
  .kui-split-button > button:focus-visible {
75
107
  outline: var(--kui-focus-ring);
108
+ outline-offset: 1px;
109
+ }
110
+
111
+ /* focusRingInset: inside an ancestor that clips overflow, each half's ring
112
+ moves inside its box. The loud fill can share the ring's hue (brand), so a
113
+ surface-colored line runs inside the ring: the ring then meets the surface
114
+ on both edges, as the outside ring does, on every tone. The line runs 3px
115
+ past the ring, wide enough to stay solid at a fractional position. It
116
+ paints the surface context, as Button's does (foundation.css). */
117
+ .kui-split-button[data-focus-ring-inset="true"] > button:focus-visible {
76
118
  outline-offset: -3px;
119
+ box-shadow:
120
+ inset 0 0 0 6px var(--kui-color-surface-current-tint, transparent),
121
+ inset 0 0 0 6px var(--kui-color-surface-current-region, transparent),
122
+ inset 0 0 0 6px var(--kui-color-surface-current, var(--kui-color-surface));
77
123
  }
78
124
 
79
125
  .kui-split-button > button:disabled {
@@ -44,6 +44,7 @@
44
44
  @import "./file-picker.css";
45
45
  @import "./text-field.css";
46
46
  @import "./checkbox.css";
47
+ @import "./checkbox-group.css";
47
48
  @import "./slider.css";
48
49
  @import "./radio-group.css";
49
50
  @import "./switch.css";
@@ -13,6 +13,9 @@
13
13
  );
14
14
  color: var(--kui-sunken-panel-foreground, var(--kui-color-text));
15
15
  background: var(--kui-sunken-panel-background, var(--kui-sunken-surface));
16
+ /* The surface-context tint: an inset focus ring's line matches the lowered
17
+ color its controls sit on (foundation.css). */
18
+ --kui-color-surface-current-tint: var(--kui-color-surface-lowered);
16
19
  flex-direction: column;
17
20
  gap: var(--kui-sunken-panel-gap, 0.5rem);
18
21
  }
@@ -29,6 +29,9 @@
29
29
  color: var(--kui-color-text, inherit);
30
30
  border: none;
31
31
  border-radius: var(--_kui-dialog-surface-radius);
32
+ --kui-color-surface-current: var(--kui-color-surface-raised);
33
+ --kui-color-surface-current-region: transparent;
34
+ --kui-color-surface-current-tint: transparent;
32
35
  background-color: var(--kui-color-surface-raised);
33
36
  box-shadow: var(--kui-shadow-l);
34
37
  /* Sizes apply at once: a theme's transition on bare dialog elements would
@@ -637,6 +640,9 @@ h2.kui-dialog-surface__title {
637
640
  var(--kui-layout-pill-radius, calc(1px + 1.3125rem)) +
638
641
  var(--kui-wa-surface-inset, 0.5rem)
639
642
  );
643
+ --kui-color-surface-current: var(--kui-color-surface-raised);
644
+ --kui-color-surface-current-region: transparent;
645
+ --kui-color-surface-current-tint: transparent;
640
646
  background: var(--kui-color-surface-raised);
641
647
  box-shadow: var(--kui-shadow-l);
642
648
  }
@@ -1,5 +1,6 @@
1
- /* Switch: a track and thumb beside its label, with a hint on the label's
2
- column. The native input sits invisibly over the track. */
1
+ /* Switch: a track and thumb beside its label, with a hint directly under
2
+ the label on its column, as a Checkbox hint sits. The native input sits
3
+ invisibly over the track. */
3
4
  .kui-switch {
4
5
  --_kui-switch-height: 1.25rem;
5
6
  --_kui-switch-gap: 0.5rem;
@@ -99,7 +100,6 @@
99
100
  }
100
101
  .kui-switch__hint {
101
102
  display: block;
102
- margin-block-start: 0.4375rem;
103
103
  padding-inline-start: calc(
104
104
  var(--_kui-switch-height) * 1.75 + var(--_kui-switch-gap)
105
105
  );
@@ -53,6 +53,7 @@
53
53
 
54
54
  .kui-tab-scaffold__scene[data-appearance="sunken"] {
55
55
  background: var(--kui-sunken-panel-background, var(--kui-sunken-surface));
56
+ --kui-color-surface-current-region: var(--kui-color-surface-lowered);
56
57
  }
57
58
 
58
59
  /* `background`: the navigator's color paints the root and a docked bar (the
@@ -175,6 +175,16 @@ span.kui-text {
175
175
  white-space: nowrap;
176
176
  }
177
177
 
178
+ /* A wrapping header keeps the whole label: it breaks onto further lines
179
+ instead of ellipsizing, and `anywhere` lets a single long word break too, so
180
+ the label's minimum width never pushes the header past its column. */
181
+ .kui-list-header[data-wrap="true"] .kui-list-header__title > .kui-text {
182
+ overflow: visible;
183
+ overflow-wrap: anywhere;
184
+ text-overflow: clip;
185
+ white-space: normal;
186
+ }
187
+
178
188
  .kui-list-header[data-size="xs"] .kui-list-header__title > .kui-text {
179
189
  font-size: var(--kui-font-2xs);
180
190
  text-transform: capitalize;
@@ -583,6 +583,7 @@
583
583
  wa-number-input,
584
584
  wa-radio-group,
585
585
  wa-select,
586
+ wa-tag-input,
586
587
  wa-textarea,
587
588
  wa-time-input
588
589
  ):not([size="small"]) {
@@ -600,6 +601,7 @@
600
601
  wa-number-input,
601
602
  wa-radio-group,
602
603
  wa-select,
604
+ wa-tag-input,
603
605
  wa-textarea,
604
606
  wa-time-input
605
607
  )::part(form-control-label),
@@ -617,27 +619,46 @@
617
619
  text-transform: uppercase;
618
620
  }
619
621
 
620
- /* Checkbox/radio groups and the color picker have no bordered field shell,
621
- so their control regions need the content-item's 8px inline outer inset. */
622
- :is(wa-checkbox-group, wa-color-picker, wa-radio-group)::part(
623
- form-control-input
624
- ) {
622
+ /* Checkbox and radio groups and the color picker keep their control region
623
+ flush: each box, circle, or swatch trigger sits on the host's
624
+ inline-start edge, where a Kerf Checkbox, RadioGroup, or ColorField draws
625
+ it, while the label and hint stay on the 9px text column. The slider
626
+ alone insets its complete interactive region by the shared 8px. */
627
+ wa-slider::part(slider) {
625
628
  margin-inline: var(--kui-layout-inline-margin, 0.5rem);
626
629
  }
627
630
 
628
- wa-slider::part(slider) {
629
- margin-inline: var(--kui-layout-inline-margin, 0.5rem);
631
+ /* Stacked radios sit 8px apart (0.25em on each side at the 16px default)
632
+ instead of Web Awesome's 12px, the 28px pitch Kerf's RadioGroup and a
633
+ Checkbox List share. The first and last radio keep their flush outer
634
+ edges, and horizontal and button radios keep their own spacing. */
635
+ wa-radio[appearance="default"]:not(
636
+ [data-wa-radio-horizontal],
637
+ [data-wa-radio-first]
638
+ ) {
639
+ margin-block-start: 0.25em;
640
+ }
641
+
642
+ wa-radio[appearance="default"]:not(
643
+ [data-wa-radio-horizontal],
644
+ [data-wa-radio-last]
645
+ ) {
646
+ margin-block-end: 0.25em;
630
647
  }
631
648
 
632
649
  /* Secondary captions and hints align with the value inside bordered fields:
633
- 1px border + 8px field padding = a 9px logical inset. */
650
+ 1px border + 8px field padding = a 9px logical inset. Checkbox and radio
651
+ group hints share that text column with their group label. */
634
652
  wa-known-date::part(field-label),
635
653
  :is(
654
+ wa-checkbox-group,
636
655
  wa-input,
637
656
  wa-known-date,
638
657
  wa-number-input,
639
658
  wa-otp-input,
659
+ wa-radio-group,
640
660
  wa-select,
661
+ wa-tag-input,
641
662
  wa-textarea,
642
663
  wa-time-input
643
664
  )::part(hint) {
@@ -646,6 +667,21 @@
646
667
  var(--wa-form-control-padding-inline)
647
668
  );
648
669
  }
670
+
671
+ /* An OTP input reserves its segments' focus-ring bleed with padding and an
672
+ equal negative margin, then caps the padded box at 100% of the host. In a
673
+ shrink-to-fit host (a start-aligned grid or flex item, an inline layout)
674
+ the host is only the segments' width minus that bleed, so the cap clips
675
+ the last cell's inline-end edge inside the scroll container. Cap the box
676
+ at the host's width plus the bleed instead, which is the space its
677
+ negative margins actually give it: the segments still scroll inside a
678
+ host narrower than the code, and never clip one that fits. The contained
679
+ appearance has no bleed and keeps upstream's cap. */
680
+ wa-otp-input:not([appearance="contained"])::part(segments) {
681
+ max-width: calc(
682
+ 100% + 2 * (var(--wa-focus-ring-offset) + var(--wa-focus-ring-width))
683
+ );
684
+ }
649
685
  }
650
686
 
651
687
  /* Small Web Awesome fields have 14px hosts by default. Raise only the editable
@@ -653,7 +689,7 @@
653
689
  their compact chrome and desktop typography keep their normal sizes. */
654
690
  @media (hover: none) and (pointer: coarse) {
655
691
  @layer wa-theme-overrides {
656
- :is(wa-input, wa-number-input, wa-time-input):is(
692
+ :is(wa-input, wa-number-input, wa-tag-input, wa-time-input):is(
657
693
  [size="xs"],
658
694
  [size="s"],
659
695
  [size="small"]
@@ -136,6 +136,7 @@
136
136
  .kui-workbench__main[data-appearance="sunken"],
137
137
  :is(.kui-workbench__rail, .kui-workbench__drawer)[data-appearance="sunken"] {
138
138
  background: var(--kui-sunken-panel-background, var(--kui-sunken-surface));
139
+ --kui-color-surface-current-region: var(--kui-color-surface-lowered);
139
140
  }
140
141
 
141
142
  :is(
@@ -143,6 +144,8 @@
143
144
  .kui-workbench__drawer
144
145
  )[data-appearance="sunken"][data-resizable="true"][data-content-overflow="auto"] {
145
146
  background: transparent;
147
+ /* Only the content paints; the root keeps the inherited context. */
148
+ --kui-color-surface-current-region: inherit;
146
149
  }
147
150
 
148
151
  :is(
@@ -151,6 +154,7 @@
151
154
  )[data-appearance="sunken"][data-resizable="true"][data-content-overflow="auto"]
152
155
  > .kui-workbench__panel-content {
153
156
  background: var(--kui-sunken-panel-background, var(--kui-sunken-surface));
157
+ --kui-color-surface-current-region: var(--kui-color-surface-lowered);
154
158
  }
155
159
 
156
160
  .kui-workbench__main[data-drawer-inline-expanded="true"] {
@@ -82,6 +82,12 @@ type DialogSurfaceProps = DialogSurfaceName & DialogSurfaceOptions;
82
82
  interface DialogSurfaceOptions {
83
83
  /** The dialog's id, for `openDialog(document.getElementById(id))`. */
84
84
  id?: string;
85
+ /**
86
+ * Id of the element whose text is the dialog's accessible description,
87
+ * such as the `heading` ToolbarText's `descriptionId` or app-owned summary
88
+ * copy in the body; rendered as `aria-describedby` on the `<dialog>`.
89
+ */
90
+ describedBy?: string;
85
91
  /** The body content. */
86
92
  children: KerfUiContent;
87
93
  /**
@@ -196,7 +202,7 @@ interface DialogSurfaceOptions {
196
202
  * floating header and footer measurement, the bottom sheet's keyboard
197
203
  * clearance and grabber, and re-render resilience while open.
198
204
  */
199
- declare function DialogSurface({ id, label, labelledBy, heading, headerActions, footer, withoutHeader, lightDismiss, closeLabel, children, size, presentation, preferredWidth, bodyInset, footerInset, viewportGutter, maxHeight, height, minHeight, resizable, enterMotion, exitMotion, bodyLayout, headerPresentation, footerPresentation, footerOffset, rootAttributes, className, slot, }: DialogSurfaceProps): kerfjs.SafeHtml;
205
+ declare function DialogSurface({ id, label, labelledBy, describedBy, heading, headerActions, footer, withoutHeader, lightDismiss, closeLabel, children, size, presentation, preferredWidth, bodyInset, footerInset, viewportGutter, maxHeight, height, minHeight, resizable, enterMotion, exitMotion, bodyLayout, headerPresentation, footerPresentation, footerOffset, rootAttributes, className, slot, }: DialogSurfaceProps): kerfjs.SafeHtml;
200
206
  /** Where a PopoverDialogSurface appears: the top layer, or in flow. */
201
207
  type PopoverDialogSurfacePresentation = 'overlay' | 'embedded';
202
208
  /** Application `data-*` metadata on the surface root. */
@@ -1,4 +1,4 @@
1
- export { DialogSurface, PopoverDialogSurface, PopupSurface } from './chunk-TAHR457X.js';
1
+ export { DialogSurface, PopoverDialogSurface, PopupSurface } from './chunk-G4DRH4A5.js';
2
2
  export { closeDialog, openDialog } from './chunk-ATGAJVZ6.js';
3
3
 
4
4
 
@@ -1,5 +1,5 @@
1
- import { wireColorPickers } from './chunk-ACUKTVS3.js';
2
- import { ColorPicker } from './chunk-EKBMUXFV.js';
1
+ import { wireColorPickers } from './chunk-XWNXGFX3.js';
2
+ import { ColorPicker } from './chunk-3Z7N2NAZ.js';
3
3
 
4
4
 
5
5
  import { openAnchoredSurface } from './chunk-3WYREXW4.js';
@@ -19,9 +19,10 @@ interface WireColorPickersOptions {
19
19
  }
20
20
  /**
21
21
  * Make every ColorPicker under `root` interactive. The area takes pointer
22
- * drags and the arrow keys (Shift for steps of 10%); the hue and opacity
23
- * sliders are native ranges; channel, hex, and opacity fields commit on Enter
24
- * or blur; the model menu switches the channel fields; the screen sampler
22
+ * drags and the arrow keys (Shift for steps of 10%); the model's channel
23
+ * sliders and the opacity slider are native ranges, each changing only its
24
+ * own channel; channel, hex, and opacity fields commit on Enter or blur; the
25
+ * model menu switches the channel sliders and fields; the screen sampler
25
26
  * opens the EyeDropper where the browser has it; preset and sample swatches
26
27
  * apply their color. Each change updates the picker at once, dispatches a
27
28
  * bubbling `kui-color-input` (or `kui-color-change` when committed) event
@@ -1,4 +1,4 @@
1
- export { wireColorPickers } from './chunk-ACUKTVS3.js';
1
+ export { wireColorPickers } from './chunk-XWNXGFX3.js';
2
2
 
3
3
 
4
4
 
@@ -1,4 +1,4 @@
1
- export { wireComboboxes } from './chunk-GCAK23PU.js';
1
+ export { wireComboboxes } from './chunk-MVKHSAKE.js';
2
2
 
3
3
 
4
4
  //# sourceMappingURL=wire-comboboxes.js.map
@@ -34,8 +34,17 @@ interface WorkbenchDialogProps {
34
34
  label: string;
35
35
  /** The dialog's primary title: an xl heading in the work area's toolbar. */
36
36
  title: string;
37
- /** A short supporting line under the title. */
37
+ /**
38
+ * A short supporting line under the title. It is the dialog's accessible
39
+ * description (`aria-describedby` to its `<id>-description`) unless
40
+ * `describedBy` names other content.
41
+ */
38
42
  description?: string;
43
+ /**
44
+ * Id of the element whose text is the dialog's accessible description, in
45
+ * place of `description`, such as app-owned summary copy in `main`.
46
+ */
47
+ describedBy?: string;
39
48
  /** Groups after the title in the work area's toolbar. */
40
49
  leading?: KerfUiContent;
41
50
  /** Header controls before the close control, such as a `ToolbarControlGroup`. */
@@ -92,6 +101,6 @@ interface WorkbenchDialogProps {
92
101
  * Escape or a press outside it before the dialog sees the Escape. Built from
93
102
  * `DialogSurface` and `Workbench`.
94
103
  */
95
- declare function WorkbenchDialog({ id, label, title, description, leading, actions, main, mainFooter, mainBottomToolbar, leftRail, rightRail, bottomDrawer, compact, closeLabel, lightDismiss, size, preferredWidth, height, maxHeight, viewportGutter, mainMinSize, rootAttributes, className, slot, }: WorkbenchDialogProps): kerfjs.SafeHtml;
104
+ declare function WorkbenchDialog({ id, label, title, description, describedBy, leading, actions, main, mainFooter, mainBottomToolbar, leftRail, rightRail, bottomDrawer, compact, closeLabel, lightDismiss, size, preferredWidth, height, maxHeight, viewportGutter, mainMinSize, rootAttributes, className, slot, }: WorkbenchDialogProps): kerfjs.SafeHtml;
96
105
 
97
106
  export { WorkbenchDialog, type WorkbenchDialogProps, type WorkbenchDialogRootAttributes };
@@ -1,7 +1,7 @@
1
- import { DialogSurface } from './chunk-TAHR457X.js';
1
+ import { DialogSurface } from './chunk-G4DRH4A5.js';
2
2
  export { closeDialog, openDialog } from './chunk-ATGAJVZ6.js';
3
3
 
4
- import { Workbench } from './chunk-DDSCVEO5.js';
4
+ import { Workbench } from './chunk-NLMEDZRM.js';
5
5
 
6
6
 
7
7
 
@@ -33,6 +33,7 @@ function WorkbenchDialog({
33
33
  label,
34
34
  title,
35
35
  description,
36
+ describedBy,
36
37
  leading,
37
38
  actions,
38
39
  main,
@@ -59,6 +60,7 @@ function WorkbenchDialog({
59
60
  {
60
61
  id,
61
62
  label,
63
+ describedBy: describedBy ?? (description === void 0 ? void 0 : `${id}-description`),
62
64
  withoutHeader: true,
63
65
  lightDismiss,
64
66
  closeLabel,
@@ -88,6 +90,7 @@ function WorkbenchDialog({
88
90
  {
89
91
  text: title,
90
92
  description,
93
+ descriptionId: description === void 0 ? void 0 : `${id}-description`,
91
94
  size: "xlarge",
92
95
  id: `${id}-title`,
93
96
  headingLevel: 2