@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
@@ -1,8 +1,10 @@
1
- /* ColorPicker: a saturation and brightness area, hue and opacity sliders, a
2
- color-model menu with its tools, channel fields, a hex and opacity row,
3
- then preset and sample swatches. The surface's custom properties
4
- (--_kui-color-picker-h/s/v/a and the opaque color) place the thumbs and
5
- paint the tracks; the wiring updates them while a person drags. */
1
+ /* ColorPicker: a saturation and brightness area, a slider per channel of the
2
+ color model plus an opacity slider, a color-model menu with its tools,
3
+ channel fields, a hex and opacity row, then preset and sample swatches.
4
+ The surface's custom properties (--_kui-color-picker-h/s/v/a and the
5
+ opaque color) place the area thumb and paint the opacity slider; each
6
+ channel slider carries its own track gradient and thumb color inline. The
7
+ wiring updates both while a person drags. */
6
8
  .kui-color-picker {
7
9
  display: grid;
8
10
  width: 100%;
@@ -18,7 +20,18 @@
18
20
  font-size: var(--kui-font-m, 1rem);
19
21
  }
20
22
 
23
+ /* The area and every slider track carry an inner edge halfway to the text
24
+ color, so an area or track as dark (or as light) as the surface behind it
25
+ keeps a visible boundary in either scheme. Every thumb draws a two-tone
26
+ ring, white inside a dark outline, so it keeps a 3:1 boundary over light
27
+ and dark colors alike. */
21
28
  .kui-color-picker__surface {
29
+ --_kui-color-picker-track-edge: color-mix(
30
+ in srgb,
31
+ var(--kui-color-text) 50%,
32
+ transparent
33
+ );
34
+ --_kui-color-picker-thumb-outline: rgb(0 0 0 / 0.6);
22
35
  --_kui-color-picker-checker: repeating-conic-gradient(
23
36
  var(--kui-color-neutral-fill-normal) 0% 25%,
24
37
  var(--kui-color-surface) 0% 50%
@@ -38,6 +51,7 @@
38
51
  background:
39
52
  linear-gradient(to top, #000, transparent),
40
53
  linear-gradient(to right, #fff, hsl(var(--_kui-color-picker-h) 100% 50%));
54
+ box-shadow: inset 0 0 0 1px var(--_kui-color-picker-track-edge);
41
55
  cursor: crosshair;
42
56
  touch-action: none;
43
57
  }
@@ -58,17 +72,28 @@
58
72
  border-radius: 50%;
59
73
  background: var(--_kui-color-picker-color);
60
74
  box-shadow:
61
- 0 0 0 1px rgb(0 0 0 / 0.3),
75
+ 0 0 0 1px var(--_kui-color-picker-thumb-outline),
62
76
  var(--kui-shadow-s);
63
77
  pointer-events: none;
64
78
  translate: -50% -50%;
65
79
  }
66
80
 
67
- /* The hue and opacity sliders: native ranges drawn as 12px tracks with a
68
- round thumb that shows the color at that point. */
69
- .kui-color-picker__hue,
81
+ /* The channel and opacity sliders, one group: native ranges drawn as 12px
82
+ tracks with a round thumb that shows the color at that point. A channel
83
+ slider's inline style carries its track (the colors its channel produces
84
+ while the others hold, or the full rainbow for hue) and its thumb color.
85
+ Every track runs in the writing direction, as the native range does, and
86
+ carries the surface's inner edge. */
87
+ .kui-color-picker__sliders {
88
+ display: grid;
89
+ min-width: 0;
90
+ gap: var(--kui-space-xs, 0.5rem);
91
+ }
92
+
93
+ .kui-color-picker__slider,
70
94
  .kui-color-picker__opacity {
71
95
  --_kui-color-picker-thumb: 1.25rem;
96
+ --_kui-color-picker-track-direction: to right;
72
97
 
73
98
  display: block;
74
99
  width: 100%;
@@ -81,23 +106,22 @@
81
106
  appearance: none;
82
107
  }
83
108
 
84
- .kui-color-picker__hue {
85
- --_kui-color-picker-track: linear-gradient(
86
- to right,
87
- #f00,
88
- #ff0,
89
- #0f0,
90
- #0ff,
91
- #00f,
92
- #f0f,
93
- #f00
94
- );
95
- --_kui-color-picker-thumb-color: hsl(var(--_kui-color-picker-h) 100% 50%);
109
+ .kui-color-picker__slider[hidden] {
110
+ display: none;
111
+ }
112
+
113
+ .kui-color-picker__slider:dir(rtl),
114
+ .kui-color-picker__opacity:dir(rtl) {
115
+ --_kui-color-picker-track-direction: to left;
96
116
  }
97
117
 
98
118
  .kui-color-picker__opacity {
99
119
  --_kui-color-picker-track:
100
- linear-gradient(to right, transparent, var(--_kui-color-picker-color)),
120
+ linear-gradient(
121
+ var(--_kui-color-picker-track-direction),
122
+ transparent,
123
+ var(--_kui-color-picker-color)
124
+ ),
101
125
  var(--_kui-color-picker-checker);
102
126
  --_kui-color-picker-thumb-color: color-mix(
103
127
  in srgb,
@@ -106,23 +130,23 @@
106
130
  );
107
131
  }
108
132
 
109
- .kui-color-picker__hue::-webkit-slider-runnable-track,
133
+ .kui-color-picker__slider::-webkit-slider-runnable-track,
110
134
  .kui-color-picker__opacity::-webkit-slider-runnable-track {
111
135
  height: 0.75rem;
112
136
  border-radius: var(--kui-radius-pill);
113
137
  background: var(--_kui-color-picker-track);
114
- box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.1);
138
+ box-shadow: inset 0 0 0 1px var(--_kui-color-picker-track-edge);
115
139
  }
116
140
 
117
- .kui-color-picker__hue::-moz-range-track,
141
+ .kui-color-picker__slider::-moz-range-track,
118
142
  .kui-color-picker__opacity::-moz-range-track {
119
143
  height: 0.75rem;
120
144
  border-radius: var(--kui-radius-pill);
121
145
  background: var(--_kui-color-picker-track);
122
- box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.1);
146
+ box-shadow: inset 0 0 0 1px var(--_kui-color-picker-track-edge);
123
147
  }
124
148
 
125
- .kui-color-picker__hue::-webkit-slider-thumb,
149
+ .kui-color-picker__slider::-webkit-slider-thumb,
126
150
  .kui-color-picker__opacity::-webkit-slider-thumb {
127
151
  width: var(--_kui-color-picker-thumb);
128
152
  height: var(--_kui-color-picker-thumb);
@@ -132,12 +156,12 @@
132
156
  border-radius: 50%;
133
157
  background: var(--_kui-color-picker-thumb-color);
134
158
  box-shadow:
135
- 0 0 0 1px rgb(0 0 0 / 0.2),
159
+ 0 0 0 1px var(--_kui-color-picker-thumb-outline),
136
160
  var(--kui-shadow-s);
137
161
  appearance: none;
138
162
  }
139
163
 
140
- .kui-color-picker__hue::-moz-range-thumb,
164
+ .kui-color-picker__slider::-moz-range-thumb,
141
165
  .kui-color-picker__opacity::-moz-range-thumb {
142
166
  width: var(--_kui-color-picker-thumb);
143
167
  height: var(--_kui-color-picker-thumb);
@@ -146,22 +170,22 @@
146
170
  border-radius: 50%;
147
171
  background: var(--_kui-color-picker-thumb-color);
148
172
  box-shadow:
149
- 0 0 0 1px rgb(0 0 0 / 0.2),
173
+ 0 0 0 1px var(--_kui-color-picker-thumb-outline),
150
174
  var(--kui-shadow-s);
151
175
  }
152
176
 
153
- .kui-color-picker__hue:focus-visible,
177
+ .kui-color-picker__slider:focus-visible,
154
178
  .kui-color-picker__opacity:focus-visible {
155
179
  outline: none;
156
180
  }
157
181
 
158
- .kui-color-picker__hue:focus-visible::-webkit-slider-thumb,
182
+ .kui-color-picker__slider:focus-visible::-webkit-slider-thumb,
159
183
  .kui-color-picker__opacity:focus-visible::-webkit-slider-thumb {
160
184
  outline: var(--kui-focus-ring);
161
185
  outline-offset: 1px;
162
186
  }
163
187
 
164
- .kui-color-picker__hue:focus-visible::-moz-range-thumb,
188
+ .kui-color-picker__slider:focus-visible::-moz-range-thumb,
165
189
  .kui-color-picker__opacity:focus-visible::-moz-range-thumb {
166
190
  outline: var(--kui-focus-ring);
167
191
  outline-offset: 1px;
@@ -317,10 +341,21 @@
317
341
  cursor: not-allowed;
318
342
  }
319
343
 
344
+ /* Increased contrast draws the area and track edge in the full text color. */
345
+ @media (prefers-contrast: more) {
346
+ .kui-color-picker__surface {
347
+ --_kui-color-picker-track-edge: var(--kui-color-text);
348
+ }
349
+ }
350
+
320
351
  @media (forced-colors: active) {
352
+ .kui-color-picker__surface {
353
+ --_kui-color-picker-track-edge: CanvasText;
354
+ }
355
+
321
356
  .kui-color-picker__area,
322
357
  .kui-color-picker__area-thumb,
323
- .kui-color-picker__hue,
358
+ .kui-color-picker__slider,
324
359
  .kui-color-picker__opacity {
325
360
  forced-color-adjust: none;
326
361
  }
@@ -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,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
  );
@@ -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
 
@@ -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"] {
@@ -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
  }
@@ -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
@@ -126,6 +126,36 @@
126
126
  --kui-content-item-foreground: var(--kui-color-brand-on-fill);
127
127
  }
128
128
 
129
+ /* The surface context follows the fill an item paints: a quiet appearance,
130
+ a hover, press, or selection. A transparent item keeps its parent's
131
+ context; a brand-loud fill shares the focus ring's hue, so a control on it
132
+ keeps the surface line. A surface appearance is opaque, so it resets. */
133
+ .kui-content-item:is(
134
+ [data-appearance]:not(
135
+ [data-appearance="transparent"],
136
+ [data-appearance="brand-loud"]
137
+ ),
138
+ [data-interactive="true"]:hover:not([data-disabled="true"]),
139
+ [data-interactive="true"]:is(
140
+ [data-kui-pressed="true"],
141
+ [data-selected="true"]
142
+ )
143
+ ) {
144
+ --kui-color-surface-current-tint: var(--kui-content-item-background);
145
+ }
146
+
147
+ .kui-content-item[data-appearance="surface"]:not(
148
+ [data-interactive="true"]:is(
149
+ :hover,
150
+ [data-kui-pressed="true"],
151
+ [data-selected="true"]
152
+ )
153
+ ) {
154
+ --kui-color-surface-current: var(--kui-color-surface);
155
+ --kui-color-surface-current-region: transparent;
156
+ --kui-color-surface-current-tint: transparent;
157
+ }
158
+
129
159
  .kui-content-item:is(:focus-visible, [data-outlined="true"]) {
130
160
  outline: var(--kui-focus-ring);
131
161
  outline-offset: 1px;
@@ -24,6 +24,7 @@
24
24
  .kui-disclosure[data-appearance="sunken"] {
25
25
  --_kui-disclosure-border: var(--kui-color-neutral-border-normal);
26
26
  --_kui-disclosure-background: var(--kui-sunken-surface);
27
+ --kui-color-surface-current-tint: var(--kui-color-surface-lowered);
27
28
  }
28
29
 
29
30
  .kui-disclosure__summary {
@@ -90,6 +91,43 @@
90
91
  0;
91
92
  }
92
93
 
94
+ /* Embedded: inside owner chrome, such as a ContentItem, that already draws
95
+ the margin, border, and padding. The root adds none of its own, so the
96
+ arrow sits on the owner's content inset (icons align to icons), and the
97
+ summary is a compact inline row. The content expects no inset of its own
98
+ (a flush Text, inline copy) and starts on the title's text column, one
99
+ item gap below the summary. A hover fill would touch the arrow and text at
100
+ the owner's content edge, so the embedded summary keeps only its pointer
101
+ cursor and draws its focus ring just outside the row. */
102
+ .kui-disclosure[data-appearance="embedded"] {
103
+ margin: 0;
104
+ border: 0;
105
+ border-radius: 0;
106
+ }
107
+
108
+ .kui-disclosure[data-appearance="embedded"] > .kui-disclosure__summary {
109
+ min-height: 1.5rem;
110
+ padding: 0;
111
+ border-radius: var(--kui-radius-s, 0.1875rem);
112
+ }
113
+
114
+ .kui-disclosure[data-appearance="embedded"] > .kui-disclosure__summary:hover {
115
+ background: none;
116
+ }
117
+
118
+ .kui-disclosure[data-appearance="embedded"]
119
+ > .kui-disclosure__summary:focus-visible {
120
+ outline-offset: 0.125rem;
121
+ }
122
+
123
+ .kui-disclosure[data-appearance="embedded"] > .kui-disclosure__content {
124
+ padding-block: var(--kui-layout-item-gap, 0.5rem) 0;
125
+ padding-inline: calc(
126
+ var(--kui-disclosure-arrow-size, 1.125rem) + var(--kui-space-xs)
127
+ )
128
+ 0;
129
+ }
130
+
93
131
  @media (forced-colors: active) {
94
132
  .kui-disclosure[data-appearance="framed"],
95
133
  .kui-disclosure[data-appearance="sunken"] {
@@ -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
  }
@@ -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;
@@ -126,6 +126,36 @@
126
126
  --kui-content-item-foreground: var(--kui-color-brand-on-fill);
127
127
  }
128
128
 
129
+ /* The surface context follows the fill an item paints: a quiet appearance,
130
+ a hover, press, or selection. A transparent item keeps its parent's
131
+ context; a brand-loud fill shares the focus ring's hue, so a control on it
132
+ keeps the surface line. A surface appearance is opaque, so it resets. */
133
+ .kui-content-item:is(
134
+ [data-appearance]:not(
135
+ [data-appearance="transparent"],
136
+ [data-appearance="brand-loud"]
137
+ ),
138
+ [data-interactive="true"]:hover:not([data-disabled="true"]),
139
+ [data-interactive="true"]:is(
140
+ [data-kui-pressed="true"],
141
+ [data-selected="true"]
142
+ )
143
+ ) {
144
+ --kui-color-surface-current-tint: var(--kui-content-item-background);
145
+ }
146
+
147
+ .kui-content-item[data-appearance="surface"]:not(
148
+ [data-interactive="true"]:is(
149
+ :hover,
150
+ [data-kui-pressed="true"],
151
+ [data-selected="true"]
152
+ )
153
+ ) {
154
+ --kui-color-surface-current: var(--kui-color-surface);
155
+ --kui-color-surface-current-region: transparent;
156
+ --kui-color-surface-current-tint: transparent;
157
+ }
158
+
129
159
  .kui-content-item:is(:focus-visible, [data-outlined="true"]) {
130
160
  outline: var(--kui-focus-ring);
131
161
  outline-offset: 1px;
@@ -24,6 +24,7 @@
24
24
  .kui-disclosure[data-appearance="sunken"] {
25
25
  --_kui-disclosure-border: var(--kui-color-neutral-border-normal);
26
26
  --_kui-disclosure-background: var(--kui-sunken-surface);
27
+ --kui-color-surface-current-tint: var(--kui-color-surface-lowered);
27
28
  }
28
29
 
29
30
  .kui-disclosure__summary {
@@ -90,6 +91,43 @@
90
91
  0;
91
92
  }
92
93
 
94
+ /* Embedded: inside owner chrome, such as a ContentItem, that already draws
95
+ the margin, border, and padding. The root adds none of its own, so the
96
+ arrow sits on the owner's content inset (icons align to icons), and the
97
+ summary is a compact inline row. The content expects no inset of its own
98
+ (a flush Text, inline copy) and starts on the title's text column, one
99
+ item gap below the summary. A hover fill would touch the arrow and text at
100
+ the owner's content edge, so the embedded summary keeps only its pointer
101
+ cursor and draws its focus ring just outside the row. */
102
+ .kui-disclosure[data-appearance="embedded"] {
103
+ margin: 0;
104
+ border: 0;
105
+ border-radius: 0;
106
+ }
107
+
108
+ .kui-disclosure[data-appearance="embedded"] > .kui-disclosure__summary {
109
+ min-height: 1.5rem;
110
+ padding: 0;
111
+ border-radius: var(--kui-radius-s, 0.1875rem);
112
+ }
113
+
114
+ .kui-disclosure[data-appearance="embedded"] > .kui-disclosure__summary:hover {
115
+ background: none;
116
+ }
117
+
118
+ .kui-disclosure[data-appearance="embedded"]
119
+ > .kui-disclosure__summary:focus-visible {
120
+ outline-offset: 0.125rem;
121
+ }
122
+
123
+ .kui-disclosure[data-appearance="embedded"] > .kui-disclosure__content {
124
+ padding-block: var(--kui-layout-item-gap, 0.5rem) 0;
125
+ padding-inline: calc(
126
+ var(--kui-disclosure-arrow-size, 1.125rem) + var(--kui-space-xs)
127
+ )
128
+ 0;
129
+ }
130
+
93
131
  @media (forced-colors: active) {
94
132
  .kui-disclosure[data-appearance="framed"],
95
133
  .kui-disclosure[data-appearance="sunken"] {
@@ -178,6 +178,23 @@
178
178
  --kui-sunken-surface:
179
179
  var(--kui-sunken-texture) 0 0 / 100px 100px repeat,
180
180
  var(--kui-color-surface-lowered);
181
+ /* The surface context: what a region paints behind its children, for a
182
+ control that must match it (an inset focus ring's inner line). Left
183
+ undeclared here, so a reader falls back to the base surface:
184
+ --kui-color-surface-current: the opaque surface beneath (default
185
+ --kui-color-surface); an opaque surface (a raised dialog or popup, a
186
+ base or raised List) sets it and clears the tint.
187
+ --kui-color-surface-current-region: a layout region's translucent
188
+ fill over it (a sunken Pane, Workbench area, or TabNavigator scene;
189
+ default transparent).
190
+ --kui-color-surface-current-tint: a content surface's translucent
191
+ fill over that (a SunkenPanel, a sunken Disclosure, a lowered
192
+ FramedList, a quiet ContentItem; default transparent).
193
+ A reader layers the tint over the region over the color, so a content
194
+ surface inside a sunken region (the common nesting) composes exactly;
195
+ custom properties cannot fold an inherited value into a new one, so a
196
+ third translucent level keeps only the innermost content tint. A surface sets both on its own
197
+ painted element, never on a child; a scoped tint resets them below. */
181
198
  /* Translucent chrome material: a bar laid over scrolling content (a Pane's
182
199
  overlay header) lets the content show through, blurred, beneath it.
183
200
  80% of the surface keeps --kui-color-text at AA over any content
@@ -573,6 +590,10 @@
573
590
  [data-kui-tint] {
574
591
  color: var(--kui-color-text);
575
592
  --kui-chrome-material-filter: blur(20px);
593
+ /* The scope re-derives its surface, so an outer surface context ends here. */
594
+ --kui-color-surface-current: initial;
595
+ --kui-color-surface-current-region: initial;
596
+ --kui-color-surface-current-tint: initial;
576
597
  }
577
598
 
578
599
  @supports (color: oklch(from red l c h)) {