@xsynaptic/sonic-ui 0.2.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 (42) hide show
  1. package/README.md +2 -2
  2. package/dist/default/define/number.js +7 -0
  3. package/dist/default/define.js +1 -0
  4. package/dist/default/elements/dial.js +19 -7
  5. package/dist/default/elements/number.js +46 -0
  6. package/dist/default/elements/range-element.js +46 -23
  7. package/dist/default/elements/slider.js +16 -2
  8. package/dist/default/index.js +2 -1
  9. package/dist/default/lib/taper.js +4 -1
  10. package/dist/dev/define/number.d.ts +2 -0
  11. package/dist/dev/define/number.js +8 -0
  12. package/dist/dev/define/number.js.map +1 -0
  13. package/dist/dev/define.d.ts +3 -1
  14. package/dist/dev/define.js +1 -0
  15. package/dist/dev/elements/dial.d.ts +3 -0
  16. package/dist/dev/elements/dial.js +19 -7
  17. package/dist/dev/elements/dial.js.map +1 -1
  18. package/dist/dev/elements/number.d.ts +16 -0
  19. package/dist/dev/elements/number.js +47 -0
  20. package/dist/dev/elements/number.js.map +1 -0
  21. package/dist/dev/elements/range-element.d.ts +4 -0
  22. package/dist/dev/elements/range-element.js +46 -23
  23. package/dist/dev/elements/range-element.js.map +1 -1
  24. package/dist/dev/elements/slider.d.ts +2 -0
  25. package/dist/dev/elements/slider.js +16 -2
  26. package/dist/dev/elements/slider.js.map +1 -1
  27. package/dist/dev/index.d.ts +2 -1
  28. package/dist/dev/index.js +2 -1
  29. package/dist/dev/lib/read-px-property.js.map +1 -1
  30. package/dist/dev/lib/taper.js +4 -1
  31. package/dist/dev/lib/taper.js.map +1 -1
  32. package/dist/styles/controls.css +2 -0
  33. package/dist/styles/dial.css +37 -3
  34. package/dist/styles/key.css +41 -1
  35. package/dist/styles/led.css +75 -0
  36. package/dist/styles/material.css +100 -19
  37. package/dist/styles/meter.css +19 -3
  38. package/dist/styles/number.css +81 -0
  39. package/dist/styles/screen.css +6 -39
  40. package/dist/styles/segmented.css +21 -0
  41. package/dist/styles/slider.css +52 -1
  42. package/package.json +4 -2
@@ -0,0 +1,75 @@
1
+ @property --_sonic-led-size {
2
+ syntax: '<length>';
3
+ inherits: true;
4
+ initial-value: 8px;
5
+ }
6
+
7
+ @layer sonic {
8
+ .sonic-led {
9
+ --_sonic-led-size: var(--sonic-led-size, 0.5rem);
10
+ --_sonic-led-lens-ratio: var(--sonic-led-lens-ratio, 0.625);
11
+ --_sonic-unit: calc(var(--_sonic-led-size) / 8);
12
+ --_sonic-led-bezel: color-mix(in oklab, var(--_sonic-unlit) 55%, #000);
13
+
14
+ position: relative;
15
+ display: inline-block;
16
+ flex-shrink: 0;
17
+ inline-size: var(--_sonic-led-size);
18
+ block-size: var(--_sonic-led-size);
19
+ background: var(--_sonic-led-bezel);
20
+ border-radius: 50%;
21
+
22
+ &::after {
23
+ position: absolute;
24
+ inset: calc(var(--_sonic-led-size) * (1 - var(--_sonic-led-lens-ratio)) / 2);
25
+ content: '';
26
+ background: var(--_sonic-lens);
27
+ border-radius: inherit;
28
+ }
29
+
30
+ @media (forced-colors: active) {
31
+ forced-color-adjust: none;
32
+ background: none;
33
+
34
+ &::after {
35
+ background: GrayText;
36
+ box-shadow: 0 0 0 1px CanvasText;
37
+ }
38
+ }
39
+ }
40
+
41
+ .sonic-led:is(
42
+ [data-sonic-lit],
43
+ :where(
44
+ .sonic-key[aria-pressed='true'],
45
+ [momentary]:state(pressed) > .sonic-key,
46
+ .sonic-segmented-segment[aria-checked='true']
47
+ )
48
+ *
49
+ ) {
50
+ background:
51
+ radial-gradient(
52
+ closest-side,
53
+ color-mix(in oklab, var(--_sonic-lit) 60%, transparent)
54
+ calc(var(--_sonic-led-lens-ratio) * 100%),
55
+ transparent
56
+ ),
57
+ var(--_sonic-led-bezel);
58
+
59
+ &::after {
60
+ background: radial-gradient(
61
+ closest-side,
62
+ color-mix(in oklab, var(--_sonic-lit) 55%, #fff),
63
+ var(--_sonic-lit)
64
+ );
65
+ }
66
+
67
+ @media (forced-colors: active) {
68
+ background: none;
69
+
70
+ &::after {
71
+ background: Highlight;
72
+ }
73
+ }
74
+ }
75
+ }
@@ -1,10 +1,18 @@
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,
@@ -19,21 +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) {
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
+ ) {
23
39
  --_sonic-lit: var(--sonic-lit, oklch(76.9% 0.165 70deg));
24
40
  }
25
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);
46
+ }
47
+
26
48
  .sonic-meter {
27
49
  --_sonic-hot: var(--sonic-hot, oklch(70.5% 0.187 48deg));
28
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) {
53
+ :is(.sonic-dial, .sonic-key, .sonic-number, .sonic-segmented-segment, .sonic-slider) {
32
54
  --_sonic-cap: var(--sonic-cap, oklch(37% 0.012 286deg));
33
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
57
  --_sonic-ink: var(--sonic-mark, color-mix(in oklab, var(--_sonic-cap) 30%, #fff));
36
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);
37
60
  --_sonic-lit-disabled: color-mix(in oklab, var(--_sonic-ink) 25%, var(--_sonic-unlit));
38
61
  --_sonic-skirt: linear-gradient(
39
62
  var(--_sonic-light-fall),
@@ -71,17 +94,59 @@
71
94
  }
72
95
 
73
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);
74
99
  --_sonic-lit-off: var(
75
100
  --sonic-dimmed,
76
101
  color-mix(in oklab, var(--_sonic-lit) 50%, var(--_sonic-unlit))
77
102
  );
78
103
  }
79
104
 
80
- :is(.sonic-dial-readout, .sonic-screen, .sonic-slider-readout) {
105
+ :is(.sonic-dial-readout, .sonic-number, .sonic-screen, .sonic-slider-readout) {
81
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
+ }
82
147
  }
83
148
 
84
- :is(.sonic-key, .sonic-screen, .sonic-segmented) {
149
+ :is(.sonic-key, .sonic-number, .sonic-screen, .sonic-segmented) {
85
150
  --_sonic-well:
86
151
  inset var(--_sonic-cast-x) var(--_sonic-cast-y) calc(2 * var(--_sonic-unit)) rgb(0 0 0 / 60%),
87
152
  calc(0.5 * var(--_sonic-cast-x)) calc(0.5 * var(--_sonic-cast-y)) 0 rgb(255 255 255 / 6%);
@@ -115,7 +180,13 @@
115
180
  }
116
181
  }
117
182
 
118
- :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 {
119
190
  --_sonic-cap: var(--_sonic-cap-hover);
120
191
  --_sonic-focus-shadow: var(--_sonic-focus-glow);
121
192
 
@@ -124,13 +195,12 @@
124
195
  }
125
196
 
126
197
  /* Keeps the glow while focus is in the entry; its own rule, since an engine without `:state()` drops a whole selector list */
127
- :state(editing) > :is(.sonic-dial, .sonic-slider) {
198
+ :state(editing) > :is(.sonic-dial, .sonic-number, .sonic-slider) {
128
199
  --_sonic-cap: var(--_sonic-cap-hover);
129
200
  --_sonic-focus-shadow: var(--_sonic-focus-glow);
130
201
  }
131
202
 
132
203
  :is(.sonic-dial-readout, .sonic-slider-readout) {
133
- --_sonic-readout-size: var(--sonic-readout-size, 1.5rem);
134
204
  --_sonic-unit: calc(var(--_sonic-readout-size) / 32);
135
205
 
136
206
  box-sizing: border-box;
@@ -143,19 +213,15 @@
143
213
  position-try-fallbacks: flip-block;
144
214
  overflow: visible;
145
215
  font: inherit;
216
+ font-family: var(--sonic-glass-font);
146
217
  font-size: calc(0.5 * var(--_sonic-readout-size));
147
218
  font-variant-numeric: tabular-nums;
148
219
  line-height: 1;
149
- color: color-mix(in oklab, var(--_sonic-glass) 20%, #fff);
220
+ color: var(--_sonic-glass-text);
150
221
  pointer-events: none;
151
222
  cursor: default;
152
223
  user-select: none;
153
- background: radial-gradient(
154
- closest-side,
155
- color-mix(in oklab, var(--_sonic-glass) 88%, #fff),
156
- var(--_sonic-glass)
157
- )
158
- var(--_sonic-glass);
224
+ background: var(--_sonic-glass-fill);
159
225
  border: 0;
160
226
  border-radius: calc(0.25 * var(--_sonic-readout-size));
161
227
  box-shadow:
@@ -200,7 +266,7 @@
200
266
  cursor: text;
201
267
  }
202
268
 
203
- :is(.sonic-dial-entry, .sonic-slider-entry) {
269
+ :is(.sonic-dial-entry, .sonic-number-entry, .sonic-slider-entry) {
204
270
  inline-size: 6ch;
205
271
  padding: 0;
206
272
  font: inherit;
@@ -227,13 +293,21 @@
227
293
  }
228
294
 
229
295
  @media (forced-colors: active) {
230
- :is(.sonic-dial, .sonic-key, .sonic-meter, .sonic-segmented-segment, .sonic-slider) {
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
+ ) {
231
305
  --_sonic-lit: Highlight;
232
306
  --_sonic-unlit: GrayText;
233
307
  }
234
308
 
235
309
  /* Tokens rather than properties, so a state rule that restates one still paints in system colours */
236
- :is(.sonic-dial, .sonic-key, .sonic-segmented-segment, .sonic-slider) {
310
+ :is(.sonic-dial, .sonic-key, .sonic-number, .sonic-segmented-segment, .sonic-slider) {
237
311
  --_sonic-ink: ButtonText;
238
312
  --_sonic-etch: ButtonText;
239
313
  --_sonic-lit-disabled: GrayText;
@@ -261,7 +335,13 @@
261
335
  }
262
336
 
263
337
  /* Stands in for the glow, which forced colours drop; inset, it merged with the cap's rim */
264
- :is(.sonic-dial, .sonic-key, .sonic-segmented-segment, .sonic-slider):focus-visible {
338
+ :is(
339
+ .sonic-dial,
340
+ .sonic-key,
341
+ .sonic-number,
342
+ .sonic-segmented-segment,
343
+ .sonic-slider
344
+ ):focus-visible {
265
345
  outline-offset: 2px;
266
346
  }
267
347
 
@@ -270,7 +350,8 @@
270
350
  forced-color-adjust: none;
271
351
  }
272
352
 
273
- :is(.sonic-dial-readout, .sonic-slider-readout) {
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) {
274
355
  border: 1px solid CanvasText;
275
356
  }
276
357
  }
@@ -1,3 +1,21 @@
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
21
  :is(sonic-meter, .sonic-meter) {
@@ -239,9 +257,7 @@
239
257
  position: absolute;
240
258
  inset: var(--_sonic-meter-inset) var(--_sonic-meter-inset) auto;
241
259
  block-size: var(--_sonic-meter-lens);
242
- background:
243
- linear-gradient(var(--_sonic-light-fall), rgb(255 255 255 / 10%), transparent 60%),
244
- color-mix(in oklab, var(--_sonic-unlit) 60%, #000);
260
+ background: var(--_sonic-lens);
245
261
  border-radius: 50%;
246
262
 
247
263
  &::after {
@@ -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,48 +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
- &::after {
35
- position: absolute;
36
- inset: 0;
37
- pointer-events: none;
38
- content: '';
39
- background: linear-gradient(var(--_sonic-light-fall), rgb(255 255 255 / 7%), transparent 45%);
40
- border-radius: inherit;
41
- box-shadow:
42
- var(--_sonic-well),
43
- inset 0 0 calc(3 * var(--_sonic-unit)) rgb(0 0 0 / 45%);
44
- }
45
- }
46
-
47
- /* The glass is forced to Canvas like the page, so only a border shows its edge */
48
- @media (forced-colors: active) {
49
- .sonic-screen {
50
- border: 1px solid CanvasText;
51
- }
52
19
  }
53
20
  }
@@ -1,3 +1,9 @@
1
+ @property --_sonic-segmented-size {
2
+ syntax: '<length>';
3
+ inherits: true;
4
+ initial-value: 32px;
5
+ }
6
+
1
7
  @layer sonic {
2
8
  :is(sonic-segmented, .sonic-segmented) {
3
9
  --_sonic-segmented-size: var(--sonic-segmented-size, 2rem);
@@ -72,6 +78,7 @@
72
78
  background: transparent;
73
79
  border: 0;
74
80
  border-radius: var(--_sonic-segmented-inner-corner);
81
+ transition: color 120ms ease-out;
75
82
  }
76
83
 
77
84
  .sonic-segmented-segment:where([data-sonic-pressed], :focus-visible:active):not(:disabled),
@@ -97,6 +104,20 @@
97
104
  cursor: default;
98
105
  }
99
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
+
100
121
  /* In flow, so a long label widens its segment rather than spilling over the next */
101
122
  .sonic-segmented-cap {
102
123
  position: relative;
@@ -1,3 +1,15 @@
1
+ @property --_sonic-slider-size {
2
+ syntax: '<length>';
3
+ inherits: true;
4
+ initial-value: 32px;
5
+ }
6
+
7
+ @property --_sonic-slider-length {
8
+ syntax: '<length>';
9
+ inherits: true;
10
+ initial-value: 128px;
11
+ }
12
+
1
13
  /* The size is the thickness across the travel */
2
14
  @layer sonic {
3
15
  :is(sonic-slider, .sonic-slider) {
@@ -140,6 +152,41 @@
140
152
  calc(50% - var(--_sonic-slider-groove) / 2);
141
153
  }
142
154
 
155
+ .sonic-slider-modulation {
156
+ --_sonic-slider-modulation: var(
157
+ --sonic-modulation,
158
+ color-mix(in oklab, var(--_sonic-slider-lit) 60%, #000)
159
+ );
160
+ --_sonic-slider-modulation-band: calc(var(--_sonic-slider-groove) * 0.45);
161
+ --_sonic-slider-modulation-start: calc(
162
+ var(--_sonic-slider-cap) / 2 + var(--_sonic-slider-modulation-from, 0) *
163
+ var(--_sonic-slider-travel)
164
+ );
165
+ --_sonic-slider-modulation-length: calc(
166
+ (var(--_sonic-slider-modulation-to, 0) - var(--_sonic-slider-modulation-from, 0)) *
167
+ var(--_sonic-slider-travel)
168
+ );
169
+
170
+ position: absolute;
171
+ inset: calc(50% - var(--_sonic-slider-modulation-band) / 2) auto auto
172
+ var(--_sonic-slider-modulation-start);
173
+ inline-size: var(--_sonic-slider-modulation-length);
174
+ block-size: var(--_sonic-slider-modulation-band);
175
+ background: var(--_sonic-slider-modulation);
176
+ border-radius: calc(var(--_sonic-slider-modulation-band) / 2);
177
+ }
178
+
179
+ [orientation='vertical'] > .sonic-slider > .sonic-slider-modulation {
180
+ inset: auto auto var(--_sonic-slider-modulation-start)
181
+ calc(50% - var(--_sonic-slider-modulation-band) / 2);
182
+ inline-size: var(--_sonic-slider-modulation-band);
183
+ block-size: var(--_sonic-slider-modulation-length);
184
+ }
185
+
186
+ :not([modulation]) > .sonic-slider > .sonic-slider-modulation {
187
+ display: none;
188
+ }
189
+
143
190
  .sonic-slider-cap {
144
191
  --_sonic-slider-pointer-width: calc(
145
192
  var(--_sonic-slider-size) * var(--_sonic-slider-pointer-ratio)
@@ -202,10 +249,14 @@
202
249
  }
203
250
 
204
251
  @media (forced-colors: active) {
205
- :is(.sonic-slider-marks, .sonic-slider-groove) {
252
+ :is(.sonic-slider-marks, .sonic-slider-groove, .sonic-slider-modulation) {
206
253
  forced-color-adjust: none;
207
254
  }
208
255
 
256
+ .sonic-slider-modulation {
257
+ --_sonic-slider-modulation: CanvasText;
258
+ }
259
+
209
260
  .sonic-slider-groove {
210
261
  box-shadow: none;
211
262
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xsynaptic/sonic-ui",
3
- "version": "0.2.0",
4
- "description": "Native custom elements for audio interfaces: dials, sliders, keys, a segmented switch, a peak meter and a screen panel, skinned with CSS custom properties",
3
+ "version": "0.3.0",
4
+ "description": "Native custom elements for audio interfaces, skinned with CSS custom properties",
5
5
  "keywords": [
6
6
  "custom-elements",
7
7
  "web-components",
@@ -54,7 +54,9 @@
54
54
  "./material.css": "./dist/styles/material.css",
55
55
  "./dial.css": "./dist/styles/dial.css",
56
56
  "./key.css": "./dist/styles/key.css",
57
+ "./led.css": "./dist/styles/led.css",
57
58
  "./meter.css": "./dist/styles/meter.css",
59
+ "./number.css": "./dist/styles/number.css",
58
60
  "./screen.css": "./dist/styles/screen.css",
59
61
  "./segmented.css": "./dist/styles/segmented.css",
60
62
  "./slider.css": "./dist/styles/slider.css",