@xsynaptic/sonic-ui 0.1.0 → 0.3.0

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 (128) hide show
  1. package/README.md +8 -1
  2. package/dist/default/define/dial.js +7 -0
  3. package/dist/default/define/key.js +7 -0
  4. package/dist/default/define/meter.js +7 -0
  5. package/dist/default/define/number.js +7 -0
  6. package/dist/default/define/segmented.js +7 -0
  7. package/dist/default/define/slider.js +7 -0
  8. package/dist/{define.js → default/define.js} +1 -0
  9. package/dist/default/elements/define-once.js +7 -0
  10. package/dist/default/elements/dial.js +81 -0
  11. package/dist/default/elements/form-element.js +56 -0
  12. package/dist/default/elements/key.js +144 -0
  13. package/dist/{elements → default/elements}/meter.js +27 -16
  14. package/dist/default/elements/number.js +46 -0
  15. package/dist/default/elements/range-element.js +433 -0
  16. package/dist/{elements → default/elements}/range-entry.js +5 -4
  17. package/dist/default/elements/segmented.js +173 -0
  18. package/dist/default/elements/slider.js +99 -0
  19. package/dist/default/elements/sonic-element.js +153 -0
  20. package/dist/{index.js → default/index.js} +3 -1
  21. package/dist/default/lib/copy-node.js +30 -0
  22. package/dist/default/lib/percent.js +12 -0
  23. package/dist/default/lib/read-px-property.js +8 -0
  24. package/dist/{lib → default/lib}/render.js +9 -2
  25. package/dist/{lib → default/lib}/taper.js +4 -2
  26. package/dist/default/lib/write-attribute.js +11 -0
  27. package/dist/dev/define/dial.js.map +1 -0
  28. package/dist/dev/define/key.js.map +1 -0
  29. package/dist/dev/define/meter.js.map +1 -0
  30. package/dist/dev/define/number.d.ts +2 -0
  31. package/dist/dev/define/number.js +8 -0
  32. package/dist/dev/define/number.js.map +1 -0
  33. package/dist/dev/define/segmented.js.map +1 -0
  34. package/dist/dev/define/slider.js.map +1 -0
  35. package/dist/{define.d.ts → dev/define.d.ts} +3 -1
  36. package/dist/dev/define.js +6 -0
  37. package/dist/dev/elements/define-once.js.map +1 -0
  38. package/dist/{elements → dev/elements}/dial.d.ts +7 -0
  39. package/dist/{elements → dev/elements}/dial.js +31 -6
  40. package/dist/dev/elements/dial.js.map +1 -0
  41. package/dist/dev/elements/form-element.d.ts +22 -0
  42. package/dist/dev/elements/form-element.js +57 -0
  43. package/dist/dev/elements/form-element.js.map +1 -0
  44. package/dist/dev/elements/key.d.ts +30 -0
  45. package/dist/{elements → dev/elements}/key.js +71 -25
  46. package/dist/dev/elements/key.js.map +1 -0
  47. package/dist/{elements → dev/elements}/meter.d.ts +6 -0
  48. package/dist/dev/elements/meter.js +131 -0
  49. package/dist/dev/elements/meter.js.map +1 -0
  50. package/dist/dev/elements/number.d.ts +16 -0
  51. package/dist/dev/elements/number.js +47 -0
  52. package/dist/dev/elements/number.js.map +1 -0
  53. package/dist/dev/elements/range-element.d.ts +56 -0
  54. package/dist/{elements → dev/elements}/range-element.js +153 -67
  55. package/dist/dev/elements/range-element.js.map +1 -0
  56. package/dist/dev/elements/range-entry.js +75 -0
  57. package/dist/dev/elements/range-entry.js.map +1 -0
  58. package/dist/{elements → dev/elements}/segmented.d.ts +5 -2
  59. package/dist/dev/elements/segmented.js +174 -0
  60. package/dist/dev/elements/segmented.js.map +1 -0
  61. package/dist/{elements → dev/elements}/slider.d.ts +8 -0
  62. package/dist/{elements → dev/elements}/slider.js +37 -7
  63. package/dist/dev/elements/slider.js.map +1 -0
  64. package/dist/dev/elements/sonic-element.d.ts +33 -0
  65. package/dist/dev/elements/sonic-element.js +169 -0
  66. package/dist/dev/elements/sonic-element.js.map +1 -0
  67. package/dist/{index.d.ts → dev/index.d.ts} +3 -1
  68. package/dist/dev/index.js +9 -0
  69. package/dist/dev/lib/copy-node.js +31 -0
  70. package/dist/dev/lib/copy-node.js.map +1 -0
  71. package/dist/dev/lib/percent.d.ts +5 -0
  72. package/dist/dev/lib/percent.js +13 -0
  73. package/dist/dev/lib/percent.js.map +1 -0
  74. package/dist/dev/lib/read-px-property.js.map +1 -0
  75. package/dist/dev/lib/render.js +27 -0
  76. package/dist/dev/lib/render.js.map +1 -0
  77. package/dist/dev/lib/taper.js +36 -0
  78. package/dist/dev/lib/taper.js.map +1 -0
  79. package/dist/dev/lib/write-attribute.js.map +1 -0
  80. package/dist/skins/ivory.css +3 -3
  81. package/dist/skins/slate.css +4 -4
  82. package/dist/styles/controls.css +2 -1
  83. package/dist/styles/dial.css +70 -16
  84. package/dist/styles/key.css +71 -11
  85. package/dist/styles/led.css +75 -0
  86. package/dist/styles/material.css +154 -25
  87. package/dist/styles/meter.css +44 -8
  88. package/dist/styles/number.css +81 -0
  89. package/dist/styles/screen.css +6 -33
  90. package/dist/styles/segmented.css +45 -7
  91. package/dist/styles/slider.css +68 -4
  92. package/package.json +16 -13
  93. package/dist/define/dial.js.map +0 -1
  94. package/dist/define/key.js.map +0 -1
  95. package/dist/define/meter.js.map +0 -1
  96. package/dist/define/segmented.js.map +0 -1
  97. package/dist/define/slider.js.map +0 -1
  98. package/dist/elements/define-once.js.map +0 -1
  99. package/dist/elements/dial.js.map +0 -1
  100. package/dist/elements/key.d.ts +0 -17
  101. package/dist/elements/key.js.map +0 -1
  102. package/dist/elements/meter.js.map +0 -1
  103. package/dist/elements/range-element.d.ts +0 -32
  104. package/dist/elements/range-element.js.map +0 -1
  105. package/dist/elements/range-entry.js.map +0 -1
  106. package/dist/elements/segmented.js +0 -104
  107. package/dist/elements/segmented.js.map +0 -1
  108. package/dist/elements/slider.js.map +0 -1
  109. package/dist/elements/sonic-element.d.ts +0 -20
  110. package/dist/elements/sonic-element.js +0 -94
  111. package/dist/elements/sonic-element.js.map +0 -1
  112. package/dist/lib/read-px-property.js.map +0 -1
  113. package/dist/lib/render.js.map +0 -1
  114. package/dist/lib/taper.js.map +0 -1
  115. package/dist/lib/write-attribute.js.map +0 -1
  116. /package/dist/{define → dev/define}/dial.d.ts +0 -0
  117. /package/dist/{define → dev/define}/dial.js +0 -0
  118. /package/dist/{define → dev/define}/key.d.ts +0 -0
  119. /package/dist/{define → dev/define}/key.js +0 -0
  120. /package/dist/{define → dev/define}/meter.d.ts +0 -0
  121. /package/dist/{define → dev/define}/meter.js +0 -0
  122. /package/dist/{define → dev/define}/segmented.d.ts +0 -0
  123. /package/dist/{define → dev/define}/segmented.js +0 -0
  124. /package/dist/{define → dev/define}/slider.d.ts +0 -0
  125. /package/dist/{define → dev/define}/slider.js +0 -0
  126. /package/dist/{elements → dev/elements}/define-once.js +0 -0
  127. /package/dist/{lib → dev/lib}/read-px-property.js +0 -0
  128. /package/dist/{lib → dev/lib}/write-attribute.js +0 -0
@@ -1,16 +1,24 @@
1
+ @property --_sonic-readout-size {
2
+ syntax: '<length>';
3
+ inherits: true;
4
+ initial-value: 24px;
5
+ }
6
+
1
7
  @layer sonic {
2
8
  /* Resolved per control rather than on `:root`, so each follows its own cap and unit */
3
9
  :is(
4
10
  .sonic-dial,
5
11
  .sonic-dial-readout,
6
12
  .sonic-key,
13
+ .sonic-led,
7
14
  .sonic-meter,
15
+ .sonic-number,
8
16
  .sonic-screen,
9
17
  .sonic-segmented,
10
18
  .sonic-slider,
11
19
  .sonic-slider-readout
12
20
  ) {
13
- --_sonic-unlit: var(--sonic-unlit, #27272a);
21
+ --_sonic-unlit: var(--sonic-unlit, oklch(27.4% 0.005 286deg));
14
22
 
15
23
  /* Degrees left of overhead */
16
24
  --_sonic-light-tilt: var(--sonic-light-tilt, 17deg);
@@ -19,23 +27,36 @@
19
27
  --_sonic-cast-y: calc(cos(var(--_sonic-light-tilt)) * var(--_sonic-unit));
20
28
  }
21
29
 
22
- :is(.sonic-dial, .sonic-key, .sonic-meter, .sonic-segmented-segment, .sonic-slider) {
23
- --_sonic-lit: var(--sonic-lit, #f59e0b);
30
+ :is(
31
+ .sonic-dial,
32
+ .sonic-key,
33
+ .sonic-led,
34
+ .sonic-meter,
35
+ .sonic-number,
36
+ .sonic-segmented-segment,
37
+ .sonic-slider
38
+ ) {
39
+ --_sonic-lit: var(--sonic-lit, oklch(76.9% 0.165 70deg));
40
+ }
41
+
42
+ :is(.sonic-led, .sonic-meter) {
43
+ --_sonic-lens:
44
+ linear-gradient(var(--_sonic-light-fall), rgb(255 255 255 / 10%), transparent 60%),
45
+ color-mix(in oklab, var(--_sonic-unlit) 60%, #000);
24
46
  }
25
47
 
26
48
  .sonic-meter {
27
- --_sonic-hot: var(--sonic-hot, #f97316);
28
- --_sonic-clip: var(--sonic-clip, #ef4444);
49
+ --_sonic-hot: var(--sonic-hot, oklch(70.5% 0.187 48deg));
50
+ --_sonic-clip: var(--sonic-clip, oklch(63.7% 0.208 25deg));
29
51
  }
30
52
 
31
- :is(.sonic-dial, .sonic-key, .sonic-segmented-segment, .sonic-slider) {
32
- --_sonic-cap: var(--sonic-cap, #3f3f46);
33
- --_sonic-cap-hover: var(--sonic-cap-hover, #52525b);
53
+ :is(.sonic-dial, .sonic-key, .sonic-number, .sonic-segmented-segment, .sonic-slider) {
54
+ --_sonic-cap: var(--sonic-cap, oklch(37% 0.012 286deg));
55
+ --_sonic-cap-hover: var(--sonic-cap-hover, oklch(44.2% 0.015 286deg));
34
56
  --_sonic-focus: var(--sonic-focus, oklch(90% 0.23 128deg));
35
-
36
- /* Derived from the cap, so a reskinned cap brings its marks along */
37
57
  --_sonic-ink: var(--sonic-mark, color-mix(in oklab, var(--_sonic-cap) 30%, #fff));
38
58
  --_sonic-etch: color-mix(in oklab, var(--_sonic-ink) 30%, transparent);
59
+ --_sonic-ink-lift: color-mix(in oklab, var(--_sonic-ink) 60%, #fff);
39
60
  --_sonic-lit-disabled: color-mix(in oklab, var(--_sonic-ink) 25%, var(--_sonic-unlit));
40
61
  --_sonic-skirt: linear-gradient(
41
62
  var(--_sonic-light-fall),
@@ -66,23 +87,66 @@
66
87
  rgb(255 255 255 / 12%);
67
88
  --_sonic-rim: 0 0 0 max(1px, 0.75 * var(--_sonic-unit))
68
89
  color-mix(in oklab, var(--_sonic-cap) 40%, #000);
90
+ --_sonic-drop-shade: rgb(0 0 0 / 65%);
69
91
  --_sonic-focus-shadow: 0 0 transparent;
70
92
  --_sonic-focus-glow: 0 0 max(4px, 3 * var(--_sonic-unit)) max(1px, 0.5 * var(--_sonic-unit))
71
93
  color-mix(in oklab, var(--_sonic-focus) 60%, transparent);
72
94
  }
73
95
 
74
96
  :is(.sonic-dial, .sonic-slider) {
97
+ /* On the control, since the readout's font size reads it */
98
+ --_sonic-readout-size: var(--sonic-readout-size, 1.5rem);
75
99
  --_sonic-lit-off: var(
76
100
  --sonic-dimmed,
77
101
  color-mix(in oklab, var(--_sonic-lit) 50%, var(--_sonic-unlit))
78
102
  );
79
103
  }
80
104
 
81
- :is(.sonic-dial-readout, .sonic-screen, .sonic-slider-readout) {
105
+ :is(.sonic-dial-readout, .sonic-number, .sonic-screen, .sonic-slider-readout) {
82
106
  --_sonic-glass: var(--sonic-glass, color-mix(in oklab, var(--_sonic-unlit) 45%, #000));
107
+ --_sonic-glass-fill: radial-gradient(
108
+ closest-side,
109
+ color-mix(in oklab, var(--_sonic-glass) 88%, #fff),
110
+ var(--_sonic-glass)
111
+ )
112
+ var(--_sonic-glass);
113
+
114
+ /* Not the cap's ink, which a skin may darken */
115
+ --_sonic-glass-text: var(
116
+ --sonic-glass-text,
117
+ color-mix(in oklab, var(--_sonic-glass) 20%, #fff)
118
+ );
119
+ }
120
+
121
+ /* A definite cell, so percentage-sized content fills the glass; a canvas sized to its own box would feed back */
122
+ :is(.sonic-number, .sonic-screen) {
123
+ position: relative;
124
+ box-sizing: border-box;
125
+ display: grid;
126
+ flex-shrink: 0;
127
+ grid-template: minmax(0, 1fr) / minmax(0, 1fr);
128
+ place-items: center;
129
+ font-family: var(--sonic-glass-font);
130
+ color: var(--_sonic-glass-text);
131
+
132
+ /* A double click aimed at a neighbouring control would highlight it */
133
+ user-select: none;
134
+ background: var(--_sonic-glass-fill);
135
+
136
+ &::after {
137
+ position: absolute;
138
+ inset: 0;
139
+ pointer-events: none;
140
+ content: '';
141
+ background: linear-gradient(var(--_sonic-light-fall), rgb(255 255 255 / 7%), transparent 45%);
142
+ border-radius: inherit;
143
+ box-shadow:
144
+ var(--_sonic-well),
145
+ inset 0 0 calc(3 * var(--_sonic-unit)) rgb(0 0 0 / 45%);
146
+ }
83
147
  }
84
148
 
85
- :is(.sonic-key, .sonic-screen, .sonic-segmented) {
149
+ :is(.sonic-key, .sonic-number, .sonic-screen, .sonic-segmented) {
86
150
  --_sonic-well:
87
151
  inset var(--_sonic-cast-x) var(--_sonic-cast-y) calc(2 * var(--_sonic-unit)) rgb(0 0 0 / 60%),
88
152
  calc(0.5 * var(--_sonic-cast-x)) calc(0.5 * var(--_sonic-cast-y)) 0 rgb(255 255 255 / 6%);
@@ -116,27 +180,30 @@
116
180
  }
117
181
  }
118
182
 
119
- :is(.sonic-dial, .sonic-key, .sonic-segmented-segment, .sonic-slider):focus-visible {
183
+ :is(
184
+ .sonic-dial,
185
+ .sonic-key,
186
+ .sonic-number,
187
+ .sonic-segmented-segment,
188
+ .sonic-slider
189
+ ):focus-visible {
120
190
  --_sonic-cap: var(--_sonic-cap-hover);
121
191
  --_sonic-focus-shadow: var(--_sonic-focus-glow);
122
192
 
123
- /* Painted only in forced colours; inset so it adds no size */
124
193
  outline: 2px solid transparent;
125
194
  outline-offset: -2px;
126
195
  }
127
196
 
128
197
  /* Keeps the glow while focus is in the entry; its own rule, since an engine without `:state()` drops a whole selector list */
129
- :state(editing) > :is(.sonic-dial, .sonic-slider) {
198
+ :state(editing) > :is(.sonic-dial, .sonic-number, .sonic-slider) {
130
199
  --_sonic-cap: var(--_sonic-cap-hover);
131
200
  --_sonic-focus-shadow: var(--_sonic-focus-glow);
132
201
  }
133
202
 
134
203
  :is(.sonic-dial-readout, .sonic-slider-readout) {
135
- --_sonic-readout-size: var(--sonic-readout-size, 1.5rem);
136
204
  --_sonic-unit: calc(var(--_sonic-readout-size) / 32);
137
205
 
138
206
  box-sizing: border-box;
139
- display: grid;
140
207
  place-items: center;
141
208
  min-inline-size: calc(1.75 * var(--_sonic-readout-size));
142
209
  block-size: var(--_sonic-readout-size);
@@ -146,19 +213,15 @@
146
213
  position-try-fallbacks: flip-block;
147
214
  overflow: visible;
148
215
  font: inherit;
216
+ font-family: var(--sonic-glass-font);
149
217
  font-size: calc(0.5 * var(--_sonic-readout-size));
150
218
  font-variant-numeric: tabular-nums;
151
219
  line-height: 1;
152
- color: color-mix(in oklab, var(--_sonic-glass) 20%, #fff);
220
+ color: var(--_sonic-glass-text);
153
221
  pointer-events: none;
154
222
  cursor: default;
155
223
  user-select: none;
156
- background: radial-gradient(
157
- closest-side,
158
- color-mix(in oklab, var(--_sonic-glass) 88%, #fff),
159
- var(--_sonic-glass)
160
- )
161
- var(--_sonic-glass);
224
+ background: var(--_sonic-glass-fill);
162
225
  border: 0;
163
226
  border-radius: calc(0.25 * var(--_sonic-readout-size));
164
227
  box-shadow:
@@ -173,7 +236,9 @@
173
236
  display 120ms allow-discrete,
174
237
  overlay 120ms allow-discrete;
175
238
 
239
+ /* Grid only while open; a closed readout left rendered is placed against a filtered ancestor, and engines keep the flip it took there */
176
240
  &:popover-open {
241
+ display: grid;
177
242
  opacity: 1;
178
243
  translate: 0;
179
244
 
@@ -201,7 +266,7 @@
201
266
  cursor: text;
202
267
  }
203
268
 
204
- :is(.sonic-dial-entry, .sonic-slider-entry) {
269
+ :is(.sonic-dial-entry, .sonic-number-entry, .sonic-slider-entry) {
205
270
  inline-size: 6ch;
206
271
  padding: 0;
207
272
  font: inherit;
@@ -226,4 +291,68 @@
226
291
  field-sizing: content;
227
292
  }
228
293
  }
294
+
295
+ @media (forced-colors: active) {
296
+ :is(
297
+ .sonic-dial,
298
+ .sonic-key,
299
+ .sonic-led,
300
+ .sonic-meter,
301
+ .sonic-number,
302
+ .sonic-segmented-segment,
303
+ .sonic-slider
304
+ ) {
305
+ --_sonic-lit: Highlight;
306
+ --_sonic-unlit: GrayText;
307
+ }
308
+
309
+ /* Tokens rather than properties, so a state rule that restates one still paints in system colours */
310
+ :is(.sonic-dial, .sonic-key, .sonic-number, .sonic-segmented-segment, .sonic-slider) {
311
+ --_sonic-ink: ButtonText;
312
+ --_sonic-etch: ButtonText;
313
+ --_sonic-lit-disabled: GrayText;
314
+ --_sonic-skirt: ButtonFace;
315
+ --_sonic-face: ButtonFace;
316
+ --_sonic-sheen: none;
317
+ --_sonic-face-shadow: none;
318
+ --_sonic-rim: 0 0 0 max(1px, 0.75 * var(--_sonic-unit)) var(--_sonic-ink);
319
+ --_sonic-drop-shade: transparent;
320
+ --_sonic-focus-glow: 0 0 transparent;
321
+ }
322
+
323
+ /* Dimmed is a hint, not a state; the value stays readable */
324
+ :is(.sonic-dial, .sonic-slider) {
325
+ --_sonic-lit-off: Highlight;
326
+ }
327
+
328
+ :is(
329
+ :disabled > :is(.sonic-dial, .sonic-slider),
330
+ .sonic-key:disabled,
331
+ .sonic-segmented-segment:disabled
332
+ ) {
333
+ --_sonic-ink: GrayText;
334
+ --_sonic-etch: GrayText;
335
+ }
336
+
337
+ /* Stands in for the glow, which forced colours drop; inset, it merged with the cap's rim */
338
+ :is(
339
+ .sonic-dial,
340
+ .sonic-key,
341
+ .sonic-number,
342
+ .sonic-segmented-segment,
343
+ .sonic-slider
344
+ ):focus-visible {
345
+ outline-offset: 2px;
346
+ }
347
+
348
+ :is(.sonic-dial-cap, .sonic-key-cap, .sonic-segmented-cap, .sonic-slider-cap) {
349
+ color: var(--_sonic-ink);
350
+ forced-color-adjust: none;
351
+ }
352
+
353
+ /* Glass is forced to Canvas like the page, so only a border shows its edge */
354
+ :is(.sonic-dial-readout, .sonic-number, .sonic-screen, .sonic-slider-readout) {
355
+ border: 1px solid CanvasText;
356
+ }
357
+ }
229
358
  }
@@ -1,6 +1,23 @@
1
+ @property --_sonic-meter-size {
2
+ syntax: '<length>';
3
+ inherits: true;
4
+ initial-value: 8px;
5
+ }
6
+
7
+ @property --_sonic-meter-length {
8
+ syntax: '<length>';
9
+ inherits: true;
10
+ initial-value: 128px;
11
+ }
12
+
13
+ @property --_sonic-meter-pitch {
14
+ syntax: '<length>';
15
+ inherits: true;
16
+ initial-value: 4px;
17
+ }
18
+
1
19
  /* The size is the thickness */
2
20
  @layer sonic {
3
- /* On the host too, for the placeholder */
4
21
  :is(sonic-meter, .sonic-meter) {
5
22
  --_sonic-meter-size: var(--sonic-meter-size, 0.5rem);
6
23
  --_sonic-meter-length: var(--sonic-meter-length, 8rem);
@@ -22,7 +39,6 @@
22
39
  block-size: var(--_sonic-meter-size);
23
40
  }
24
41
 
25
- /* Laid on its side rather than rotated, as the slider is */
26
42
  .sonic-meter {
27
43
  /* Absolute, so a longer meter gains segments rather than stretching them */
28
44
  --_sonic-meter-pitch: var(--sonic-meter-segment-pitch, 4px);
@@ -46,8 +62,6 @@
46
62
  --_sonic-meter-segment-radius: calc(
47
63
  var(--_sonic-meter-segment) * var(--_sonic-meter-segment-radius-ratio)
48
64
  );
49
-
50
- /* Whole segments only, so the last one ends flush */
51
65
  --_sonic-meter-segments: round(
52
66
  down,
53
67
  var(--_sonic-meter-length) - 3 * var(--_sonic-meter-inset) - var(--_sonic-meter-lens) +
@@ -62,7 +76,6 @@
62
76
  background: color-mix(in oklab, var(--_sonic-unlit) 55%, #000);
63
77
  border-radius: calc(var(--_sonic-meter-size) * var(--_sonic-meter-radius-ratio));
64
78
 
65
- /* Over the segments, so the lip shades them too */
66
79
  &::after {
67
80
  position: absolute;
68
81
  inset: 0;
@@ -244,9 +257,7 @@
244
257
  position: absolute;
245
258
  inset: var(--_sonic-meter-inset) var(--_sonic-meter-inset) auto;
246
259
  block-size: var(--_sonic-meter-lens);
247
- background:
248
- linear-gradient(var(--_sonic-light-fall), rgb(255 255 255 / 10%), transparent 60%),
249
- color-mix(in oklab, var(--_sonic-unlit) 60%, #000);
260
+ background: var(--_sonic-lens);
250
261
  border-radius: 50%;
251
262
 
252
263
  &::after {
@@ -268,4 +279,29 @@
268
279
  inline-size: var(--_sonic-meter-lens);
269
280
  block-size: auto;
270
281
  }
282
+
283
+ /* Takes no focus, so the whole meter opts out */
284
+ @media (forced-colors: active) {
285
+ .sonic-meter {
286
+ forced-color-adjust: none;
287
+ background: Canvas;
288
+
289
+ &::after {
290
+ border: 1px solid CanvasText;
291
+ box-shadow: none;
292
+ }
293
+ }
294
+
295
+ :is(.sonic-meter-segments, .sonic-meter-clip) {
296
+ background: var(--_sonic-unlit);
297
+ }
298
+
299
+ .sonic-meter-level {
300
+ background: var(--_sonic-lit);
301
+ }
302
+
303
+ .sonic-meter-clip::after {
304
+ background: Mark;
305
+ }
306
+ }
271
307
  }
@@ -0,0 +1,81 @@
1
+ @property --_sonic-number-size {
2
+ syntax: '<length>';
3
+ inherits: true;
4
+ initial-value: 28px;
5
+ }
6
+
7
+ @property --_sonic-number-travel {
8
+ syntax: '<length>';
9
+ inherits: false;
10
+ initial-value: 160px;
11
+ }
12
+
13
+ @layer sonic {
14
+ :is(sonic-number, .sonic-number) {
15
+ --_sonic-number-size: var(--sonic-number-size, 1.75rem);
16
+ --_sonic-number-aspect-ratio: var(--sonic-number-aspect-ratio, 3);
17
+ }
18
+
19
+ :has(> .sonic-number):not([hidden]) {
20
+ display: contents;
21
+ }
22
+
23
+ sonic-number:not(:defined, [hidden]) {
24
+ display: block;
25
+ flex-shrink: 0;
26
+ inline-size: calc(var(--_sonic-number-size) * var(--_sonic-number-aspect-ratio));
27
+ block-size: var(--_sonic-number-size);
28
+ }
29
+
30
+ .sonic-number {
31
+ --_sonic-number-radius-ratio: var(--sonic-number-radius-ratio, 0.15);
32
+ --_sonic-number-inset-ratio: var(--sonic-number-inset-ratio, 0.2);
33
+ --_sonic-number-text-ratio: var(--sonic-number-text-ratio, 0.45);
34
+ --_sonic-number-travel: var(--sonic-number-travel, 160px);
35
+ --_sonic-unit: calc(var(--_sonic-number-size) / 32);
36
+
37
+ inline-size: calc(var(--_sonic-number-size) * var(--_sonic-number-aspect-ratio));
38
+ block-size: var(--_sonic-number-size);
39
+ padding: 0 calc(var(--_sonic-number-size) * var(--_sonic-number-inset-ratio));
40
+ font-size: calc(var(--_sonic-number-size) * var(--_sonic-number-text-ratio));
41
+ font-variant-numeric: tabular-nums;
42
+ line-height: 1;
43
+ touch-action: none;
44
+ cursor: ns-resize;
45
+ border-radius: calc(var(--_sonic-number-size) * var(--_sonic-number-radius-ratio));
46
+ box-shadow: var(--_sonic-focus-shadow);
47
+ }
48
+
49
+ :disabled > .sonic-number {
50
+ color: var(--_sonic-etch);
51
+ cursor: default;
52
+ }
53
+
54
+ :is(.sonic-number-value, .sonic-number-entry) {
55
+ grid-area: 1 / 1;
56
+ max-inline-size: 100%;
57
+ overflow: hidden;
58
+ white-space: nowrap;
59
+ }
60
+
61
+ :state(editing) > .sonic-number > .sonic-number-value {
62
+ visibility: hidden;
63
+ }
64
+
65
+ .sonic-number-entry {
66
+ inline-size: 100%;
67
+ cursor: text;
68
+ field-sizing: fixed;
69
+ }
70
+
71
+ @media (forced-colors: active) {
72
+ .sonic-number-value {
73
+ color: CanvasText;
74
+ forced-color-adjust: none;
75
+ }
76
+
77
+ :disabled > .sonic-number > .sonic-number-value {
78
+ color: GrayText;
79
+ }
80
+ }
81
+ }
@@ -1,3 +1,9 @@
1
+ @property --_sonic-screen-size {
2
+ syntax: '<length>';
3
+ inherits: true;
4
+ initial-value: 40px;
5
+ }
6
+
1
7
  @layer sonic {
2
8
  .sonic-screen {
3
9
  --_sonic-screen-size: var(--sonic-screen-size, 2.5rem);
@@ -6,42 +12,9 @@
6
12
  --_sonic-screen-inset-ratio: var(--sonic-screen-inset-ratio, 0.1);
7
13
  --_sonic-unit: calc(var(--_sonic-screen-size) / 32);
8
14
 
9
- position: relative;
10
- box-sizing: border-box;
11
- display: grid;
12
- flex-shrink: 0;
13
-
14
- /* A definite cell, so percentage-sized content fills the glass; a canvas sized to its own box would feed back */
15
- grid-template: minmax(0, 1fr) / minmax(0, 1fr);
16
- place-items: center;
17
15
  inline-size: calc(var(--_sonic-screen-size) * var(--_sonic-screen-aspect-ratio));
18
16
  block-size: var(--_sonic-screen-size);
19
17
  padding: calc(var(--_sonic-screen-size) * var(--_sonic-screen-inset-ratio));
20
-
21
- /* Not the cap's ink, which a skin may darken */
22
- color: color-mix(in oklab, var(--_sonic-glass) 20%, #fff);
23
-
24
- /* A double click aimed at a neighbouring control would highlight it */
25
- user-select: none;
26
- background: radial-gradient(
27
- closest-side,
28
- color-mix(in oklab, var(--_sonic-glass) 88%, #fff),
29
- var(--_sonic-glass)
30
- )
31
- var(--_sonic-glass);
32
18
  border-radius: calc(var(--_sonic-screen-size) * var(--_sonic-screen-radius-ratio));
33
-
34
- /* Over the content, so the lip shades the picture too */
35
- &::after {
36
- position: absolute;
37
- inset: 0;
38
- pointer-events: none;
39
- content: '';
40
- background: linear-gradient(var(--_sonic-light-fall), rgb(255 255 255 / 7%), transparent 45%);
41
- border-radius: inherit;
42
- box-shadow:
43
- var(--_sonic-well),
44
- inset 0 0 calc(3 * var(--_sonic-unit)) rgb(0 0 0 / 45%);
45
- }
46
19
  }
47
20
  }
@@ -1,5 +1,10 @@
1
+ @property --_sonic-segmented-size {
2
+ syntax: '<length>';
3
+ inherits: true;
4
+ initial-value: 32px;
5
+ }
6
+
1
7
  @layer sonic {
2
- /* On the host too, for the placeholder */
3
8
  :is(sonic-segmented, .sonic-segmented) {
4
9
  --_sonic-segmented-size: var(--sonic-segmented-size, 2rem);
5
10
  }
@@ -8,7 +13,6 @@
8
13
  display: contents;
9
14
  }
10
15
 
11
- /* Hides the options, which have no size before upgrade */
12
16
  sonic-segmented:not(:defined, [hidden]) {
13
17
  display: block;
14
18
  visibility: hidden;
@@ -34,8 +38,6 @@
34
38
  var(--_sonic-segmented-size) * var(--_sonic-segmented-depth-ratio)
35
39
  );
36
40
  --_sonic-segmented-gap: calc(var(--_sonic-segmented-size) * var(--_sonic-segmented-gap-ratio));
37
-
38
- /* Concentric with the well's corner */
39
41
  --_sonic-segmented-inner-corner: max(
40
42
  0px,
41
43
  var(--_sonic-segmented-corner) - var(--_sonic-segmented-gap)
@@ -47,6 +49,7 @@
47
49
  gap: var(--_sonic-segmented-gap);
48
50
  block-size: var(--_sonic-segmented-size);
49
51
  padding: var(--_sonic-segmented-gap);
52
+ touch-action: pan-y;
50
53
  user-select: none;
51
54
  background: linear-gradient(
52
55
  var(--_sonic-light-fall),
@@ -61,7 +64,7 @@
61
64
  --_sonic-segmented-shift: calc(var(--_sonic-segmented-depth) / -2);
62
65
  --_sonic-segmented-scale: 1;
63
66
  --_sonic-segmented-drop: calc(1.5 * var(--_sonic-cast-x)) calc(1.5 * var(--_sonic-cast-y))
64
- calc(2 * var(--_sonic-unit)) rgb(0 0 0 / 65%);
67
+ calc(2 * var(--_sonic-unit)) var(--_sonic-drop-shade);
65
68
  --_sonic-segmented-glow: transparent;
66
69
 
67
70
  display: grid;
@@ -75,14 +78,15 @@
75
78
  background: transparent;
76
79
  border: 0;
77
80
  border-radius: var(--_sonic-segmented-inner-corner);
81
+ transition: color 120ms ease-out;
78
82
  }
79
83
 
80
- .sonic-segmented-segment:active:where(:not(:disabled)),
84
+ .sonic-segmented-segment:where([data-sonic-pressed], :focus-visible:active):not(:disabled),
81
85
  .sonic-segmented-segment[aria-checked='true'] {
82
86
  --_sonic-segmented-shift: calc(var(--_sonic-segmented-depth) / 2);
83
87
  --_sonic-segmented-scale: var(--_sonic-segmented-press-scale);
84
88
  --_sonic-segmented-drop: calc(0.5 * var(--_sonic-cast-x)) calc(0.5 * var(--_sonic-cast-y))
85
- var(--_sonic-unit) rgb(0 0 0 / 65%);
89
+ var(--_sonic-unit) var(--_sonic-drop-shade);
86
90
  }
87
91
 
88
92
  .sonic-segmented-segment[aria-checked='true'] {
@@ -100,6 +104,20 @@
100
104
  cursor: default;
101
105
  }
102
106
 
107
+ .sonic-segmented-segment:not([aria-checked='true'], :disabled):is(
108
+ :focus-visible,
109
+ :active,
110
+ [data-sonic-pressed]
111
+ ) {
112
+ color: var(--_sonic-ink-lift);
113
+ }
114
+
115
+ @media (hover: hover) {
116
+ .sonic-segmented-segment:not([aria-checked='true'], :disabled):hover {
117
+ color: var(--_sonic-ink-lift);
118
+ }
119
+ }
120
+
103
121
  /* In flow, so a long label widens its segment rather than spilling over the next */
104
122
  .sonic-segmented-cap {
105
123
  position: relative;
@@ -144,4 +162,24 @@
144
162
  filter: var(--_sonic-engraving)
145
163
  drop-shadow(0 0 var(--_sonic-unit) color-mix(in oklab, var(--_sonic-lit) 35%, transparent));
146
164
  }
165
+
166
+ @media (forced-colors: active) {
167
+ .sonic-segmented-cap > * {
168
+ filter: none;
169
+ }
170
+
171
+ .sonic-segmented-segment[aria-checked='true'] {
172
+ --_sonic-skirt: var(--_sonic-lit);
173
+ --_sonic-face: var(--_sonic-lit);
174
+ --_sonic-ink: HighlightText;
175
+
176
+ &:disabled {
177
+ --_sonic-ink: ButtonFace;
178
+ }
179
+
180
+ & .sonic-segmented-cap > * {
181
+ filter: none;
182
+ }
183
+ }
184
+ }
147
185
  }