@xsynaptic/sonic-ui 0.3.0 → 0.5.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 (237) hide show
  1. package/README.md +2 -21
  2. package/dist/default/dat.js +50 -0
  3. package/dist/default/define/button.js +7 -0
  4. package/dist/default/define/envelope.js +7 -0
  5. package/dist/default/define/split.js +7 -0
  6. package/dist/default/define/switch.js +7 -0
  7. package/dist/default/define/waveform.js +7 -0
  8. package/dist/default/define/wavestrip.js +7 -0
  9. package/dist/default/define/xy.js +7 -0
  10. package/dist/default/define.js +7 -1
  11. package/dist/default/elements/button.js +165 -0
  12. package/dist/default/elements/dial.js +19 -23
  13. package/dist/default/elements/envelope.js +367 -0
  14. package/dist/default/elements/meter.js +168 -26
  15. package/dist/default/elements/number.js +21 -8
  16. package/dist/default/elements/radio-group.js +185 -0
  17. package/dist/default/elements/readout-claim.js +81 -0
  18. package/dist/default/elements/readout.js +35 -0
  19. package/dist/default/elements/segmented.js +9 -159
  20. package/dist/default/elements/slider.js +64 -27
  21. package/dist/default/elements/sonic-element.js +24 -13
  22. package/dist/default/elements/split.js +249 -0
  23. package/dist/default/elements/switch.js +279 -0
  24. package/dist/default/elements/value-element.js +691 -0
  25. package/dist/default/elements/{range-entry.js → value-entry.js} +3 -3
  26. package/dist/default/elements/wave-element.js +77 -0
  27. package/dist/default/elements/waveform.js +305 -0
  28. package/dist/default/elements/wavestrip.js +182 -0
  29. package/dist/default/elements/xy.js +473 -0
  30. package/dist/default/index.js +10 -2
  31. package/dist/default/lib/adsr-shape.js +108 -0
  32. package/dist/default/lib/ballistics.js +55 -0
  33. package/dist/default/lib/canvas-surface.js +192 -0
  34. package/dist/default/lib/copy-node.js +32 -2
  35. package/dist/default/lib/crossfade.js +22 -0
  36. package/dist/default/lib/distribute.js +215 -0
  37. package/dist/default/lib/drag-step.js +99 -0
  38. package/dist/default/lib/envelope-curve.js +9 -0
  39. package/dist/default/lib/field.js +94 -0
  40. package/dist/default/lib/focus-by-pointer.js +28 -0
  41. package/dist/default/lib/frame-timeline.js +62 -0
  42. package/dist/default/lib/hold.js +38 -0
  43. package/dist/default/lib/marker-band.js +36 -0
  44. package/dist/default/lib/marker-rider.js +114 -0
  45. package/dist/default/lib/math.js +25 -0
  46. package/dist/default/lib/modifier-press.js +11 -0
  47. package/dist/default/lib/number-list.js +14 -0
  48. package/dist/default/lib/pointer-drag.js +43 -0
  49. package/dist/default/lib/render.js +20 -5
  50. package/dist/default/lib/resample-peaks.js +36 -0
  51. package/dist/default/lib/strip-scene.js +48 -0
  52. package/dist/default/lib/taper.js +32 -16
  53. package/dist/default/lib/time-regions.js +8 -0
  54. package/dist/default/lib/tracking-clock.js +35 -0
  55. package/dist/default/lib/value-mapping.js +115 -0
  56. package/dist/default/lib/waveform-buckets.js +41 -0
  57. package/dist/dev/dat.d.ts +19 -0
  58. package/dist/dev/dat.js +51 -0
  59. package/dist/dev/dat.js.map +1 -0
  60. package/dist/dev/define/button.d.ts +2 -0
  61. package/dist/dev/define/button.js +8 -0
  62. package/dist/dev/define/button.js.map +1 -0
  63. package/dist/dev/define/dial.js.map +1 -1
  64. package/dist/dev/define/envelope.d.ts +2 -0
  65. package/dist/dev/define/envelope.js +8 -0
  66. package/dist/dev/define/envelope.js.map +1 -0
  67. package/dist/dev/define/meter.js.map +1 -1
  68. package/dist/dev/define/number.js.map +1 -1
  69. package/dist/dev/define/segmented.js.map +1 -1
  70. package/dist/dev/define/slider.js.map +1 -1
  71. package/dist/dev/define/split.d.ts +2 -0
  72. package/dist/dev/define/split.js +8 -0
  73. package/dist/dev/define/split.js.map +1 -0
  74. package/dist/dev/define/switch.d.ts +2 -0
  75. package/dist/dev/define/switch.js +8 -0
  76. package/dist/dev/define/switch.js.map +1 -0
  77. package/dist/dev/define/waveform.d.ts +2 -0
  78. package/dist/dev/define/waveform.js +8 -0
  79. package/dist/dev/define/waveform.js.map +1 -0
  80. package/dist/dev/define/wavestrip.d.ts +2 -0
  81. package/dist/dev/define/wavestrip.js +8 -0
  82. package/dist/dev/define/wavestrip.js.map +1 -0
  83. package/dist/dev/define/xy.d.ts +2 -0
  84. package/dist/dev/define/xy.js +8 -0
  85. package/dist/dev/define/xy.js.map +1 -0
  86. package/dist/dev/define.d.ts +15 -3
  87. package/dist/dev/define.js +7 -1
  88. package/dist/dev/elements/{key.d.ts → button.d.ts} +12 -6
  89. package/dist/dev/elements/button.js +166 -0
  90. package/dist/dev/elements/button.js.map +1 -0
  91. package/dist/dev/elements/dial.d.ts +6 -4
  92. package/dist/dev/elements/dial.js +19 -23
  93. package/dist/dev/elements/dial.js.map +1 -1
  94. package/dist/dev/elements/envelope.d.ts +36 -0
  95. package/dist/dev/elements/envelope.js +372 -0
  96. package/dist/dev/elements/envelope.js.map +1 -0
  97. package/dist/dev/elements/form-element.d.ts +1 -1
  98. package/dist/dev/elements/form-element.js.map +1 -1
  99. package/dist/dev/elements/meter.d.ts +12 -1
  100. package/dist/dev/elements/meter.js +168 -26
  101. package/dist/dev/elements/meter.js.map +1 -1
  102. package/dist/dev/elements/number.d.ts +7 -3
  103. package/dist/dev/elements/number.js +21 -8
  104. package/dist/dev/elements/number.js.map +1 -1
  105. package/dist/dev/elements/radio-group.d.ts +25 -0
  106. package/dist/dev/elements/radio-group.js +186 -0
  107. package/dist/dev/elements/radio-group.js.map +1 -0
  108. package/dist/dev/elements/readout-claim.js +82 -0
  109. package/dist/dev/elements/readout-claim.js.map +1 -0
  110. package/dist/dev/elements/readout.js +36 -0
  111. package/dist/dev/elements/readout.js.map +1 -0
  112. package/dist/dev/elements/segmented.d.ts +4 -10
  113. package/dist/dev/elements/segmented.js +9 -159
  114. package/dist/dev/elements/segmented.js.map +1 -1
  115. package/dist/dev/elements/slider.d.ts +9 -3
  116. package/dist/dev/elements/slider.js +64 -27
  117. package/dist/dev/elements/slider.js.map +1 -1
  118. package/dist/dev/elements/sonic-element.d.ts +4 -3
  119. package/dist/dev/elements/sonic-element.js +51 -22
  120. package/dist/dev/elements/sonic-element.js.map +1 -1
  121. package/dist/dev/elements/split.d.ts +21 -0
  122. package/dist/dev/elements/split.js +258 -0
  123. package/dist/dev/elements/split.js.map +1 -0
  124. package/dist/dev/elements/switch.d.ts +35 -0
  125. package/dist/dev/elements/switch.js +280 -0
  126. package/dist/dev/elements/switch.js.map +1 -0
  127. package/dist/dev/elements/value-element.d.ts +84 -0
  128. package/dist/dev/elements/value-element.js +692 -0
  129. package/dist/dev/elements/value-element.js.map +1 -0
  130. package/dist/dev/elements/{range-entry.js → value-entry.js} +4 -4
  131. package/dist/dev/elements/value-entry.js.map +1 -0
  132. package/dist/dev/elements/wave-element.d.ts +36 -0
  133. package/dist/dev/elements/wave-element.js +78 -0
  134. package/dist/dev/elements/wave-element.js.map +1 -0
  135. package/dist/dev/elements/waveform.d.ts +55 -0
  136. package/dist/dev/elements/waveform.js +306 -0
  137. package/dist/dev/elements/waveform.js.map +1 -0
  138. package/dist/dev/elements/wavestrip.d.ts +51 -0
  139. package/dist/dev/elements/wavestrip.js +183 -0
  140. package/dist/dev/elements/wavestrip.js.map +1 -0
  141. package/dist/dev/elements/xy.d.ts +62 -0
  142. package/dist/dev/elements/xy.js +474 -0
  143. package/dist/dev/elements/xy.js.map +1 -0
  144. package/dist/dev/index.d.ts +11 -2
  145. package/dist/dev/index.js +10 -2
  146. package/dist/dev/lib/adsr-shape.js +109 -0
  147. package/dist/dev/lib/adsr-shape.js.map +1 -0
  148. package/dist/dev/lib/ballistics.js +56 -0
  149. package/dist/dev/lib/ballistics.js.map +1 -0
  150. package/dist/dev/lib/canvas-surface.d.ts +25 -0
  151. package/dist/dev/lib/canvas-surface.js +193 -0
  152. package/dist/dev/lib/canvas-surface.js.map +1 -0
  153. package/dist/dev/lib/copy-node.js +32 -2
  154. package/dist/dev/lib/copy-node.js.map +1 -1
  155. package/dist/dev/lib/crossfade.d.ts +12 -0
  156. package/dist/dev/lib/crossfade.js +23 -0
  157. package/dist/dev/lib/crossfade.js.map +1 -0
  158. package/dist/dev/lib/distribute.d.ts +4 -0
  159. package/dist/dev/lib/distribute.js +216 -0
  160. package/dist/dev/lib/distribute.js.map +1 -0
  161. package/dist/dev/lib/drag-step.js +100 -0
  162. package/dist/dev/lib/drag-step.js.map +1 -0
  163. package/dist/dev/lib/envelope-curve.d.ts +4 -0
  164. package/dist/dev/lib/envelope-curve.js +10 -0
  165. package/dist/dev/lib/envelope-curve.js.map +1 -0
  166. package/dist/dev/lib/field.d.ts +4 -0
  167. package/dist/dev/lib/field.js +95 -0
  168. package/dist/dev/lib/field.js.map +1 -0
  169. package/dist/dev/lib/focus-by-pointer.js +29 -0
  170. package/dist/dev/lib/focus-by-pointer.js.map +1 -0
  171. package/dist/dev/lib/frame-timeline.js +63 -0
  172. package/dist/dev/lib/frame-timeline.js.map +1 -0
  173. package/dist/dev/lib/hold.js +39 -0
  174. package/dist/dev/lib/hold.js.map +1 -0
  175. package/dist/dev/lib/marker-band.js +37 -0
  176. package/dist/dev/lib/marker-band.js.map +1 -0
  177. package/dist/dev/lib/marker-rider.js +115 -0
  178. package/dist/dev/lib/marker-rider.js.map +1 -0
  179. package/dist/dev/lib/math.js +26 -0
  180. package/dist/dev/lib/math.js.map +1 -0
  181. package/dist/dev/lib/modifier-press.js +12 -0
  182. package/dist/dev/lib/modifier-press.js.map +1 -0
  183. package/dist/dev/lib/number-list.js +15 -0
  184. package/dist/dev/lib/number-list.js.map +1 -0
  185. package/dist/dev/lib/pointer-drag.js +44 -0
  186. package/dist/dev/lib/pointer-drag.js.map +1 -0
  187. package/dist/dev/lib/read-px-property.js.map +1 -1
  188. package/dist/dev/lib/render.js +20 -5
  189. package/dist/dev/lib/render.js.map +1 -1
  190. package/dist/dev/lib/resample-peaks.js +37 -0
  191. package/dist/dev/lib/resample-peaks.js.map +1 -0
  192. package/dist/dev/lib/strip-scene.js +49 -0
  193. package/dist/dev/lib/strip-scene.js.map +1 -0
  194. package/dist/dev/lib/taper.js +32 -16
  195. package/dist/dev/lib/taper.js.map +1 -1
  196. package/dist/dev/lib/time-regions.d.ts +4 -0
  197. package/dist/dev/lib/time-regions.js +9 -0
  198. package/dist/dev/lib/time-regions.js.map +1 -0
  199. package/dist/dev/lib/tracking-clock.js +36 -0
  200. package/dist/dev/lib/tracking-clock.js.map +1 -0
  201. package/dist/dev/lib/value-mapping.d.ts +23 -0
  202. package/dist/dev/lib/value-mapping.js +116 -0
  203. package/dist/dev/lib/value-mapping.js.map +1 -0
  204. package/dist/dev/lib/waveform-buckets.d.ts +9 -0
  205. package/dist/dev/lib/waveform-buckets.js +42 -0
  206. package/dist/dev/lib/waveform-buckets.js.map +1 -0
  207. package/dist/skins/ivory.css +1 -2
  208. package/dist/styles/button.css +212 -0
  209. package/dist/styles/controls.css +8 -1
  210. package/dist/styles/dial.css +130 -44
  211. package/dist/styles/envelope.css +159 -0
  212. package/dist/styles/led.css +44 -6
  213. package/dist/styles/material.css +321 -71
  214. package/dist/styles/meter.css +109 -28
  215. package/dist/styles/number.css +5 -1
  216. package/dist/styles/panel.css +59 -0
  217. package/dist/styles/ring.css +74 -0
  218. package/dist/styles/segmented.css +22 -54
  219. package/dist/styles/slider.css +256 -58
  220. package/dist/styles/switch.css +347 -0
  221. package/dist/styles/waveform.css +173 -0
  222. package/dist/styles/wavestrip.css +215 -0
  223. package/dist/styles/xy.css +204 -0
  224. package/package.json +14 -2
  225. package/dist/default/define/key.js +0 -7
  226. package/dist/default/elements/key.js +0 -144
  227. package/dist/default/elements/range-element.js +0 -433
  228. package/dist/dev/define/key.d.ts +0 -2
  229. package/dist/dev/define/key.js +0 -8
  230. package/dist/dev/define/key.js.map +0 -1
  231. package/dist/dev/elements/key.js +0 -145
  232. package/dist/dev/elements/key.js.map +0 -1
  233. package/dist/dev/elements/range-element.d.ts +0 -56
  234. package/dist/dev/elements/range-element.js +0 -434
  235. package/dist/dev/elements/range-element.js.map +0 -1
  236. package/dist/dev/elements/range-entry.js.map +0 -1
  237. package/dist/styles/key.css +0 -197
@@ -4,23 +4,43 @@
4
4
  initial-value: 24px;
5
5
  }
6
6
 
7
+ @property --_sonic-detent-zone {
8
+ syntax: '<length>';
9
+ inherits: true;
10
+ initial-value: 8px;
11
+ }
12
+
13
+ @keyframes sonic-glass-breathe {
14
+ to {
15
+ opacity: calc(0.4 * min(1, var(--_sonic-glass-texture)));
16
+ }
17
+ }
18
+
7
19
  @layer sonic {
8
- /* Resolved per control rather than on `:root`, so each follows its own cap and unit */
9
20
  :is(
10
21
  .sonic-dial,
11
22
  .sonic-dial-readout,
12
- .sonic-key,
23
+ .sonic-envelope,
24
+ .sonic-envelope-readout,
25
+ .sonic-button,
13
26
  .sonic-led,
27
+ .sonic-switch,
14
28
  .sonic-meter,
15
29
  .sonic-number,
30
+ .sonic-panel,
31
+ .sonic-ring,
16
32
  .sonic-screen,
17
33
  .sonic-segmented,
18
34
  .sonic-slider,
19
- .sonic-slider-readout
35
+ .sonic-slider-readout,
36
+ .sonic-waveform,
37
+ .sonic-waveform-readout,
38
+ .sonic-wavestrip,
39
+ .sonic-wavestrip-readout,
40
+ .sonic-xy,
41
+ .sonic-xy-readout
20
42
  ) {
21
43
  --_sonic-unlit: var(--sonic-unlit, oklch(27.4% 0.005 286deg));
22
-
23
- /* Degrees left of overhead */
24
44
  --_sonic-light-tilt: var(--sonic-light-tilt, 17deg);
25
45
  --_sonic-light-fall: calc(180deg - var(--_sonic-light-tilt));
26
46
  --_sonic-cast-x: calc(sin(var(--_sonic-light-tilt)) * var(--_sonic-unit));
@@ -29,32 +49,67 @@
29
49
 
30
50
  :is(
31
51
  .sonic-dial,
32
- .sonic-key,
52
+ .sonic-envelope,
53
+ .sonic-button,
33
54
  .sonic-led,
34
55
  .sonic-meter,
35
56
  .sonic-number,
36
- .sonic-segmented-segment,
37
- .sonic-slider
57
+ .sonic-ring,
58
+ .sonic-segmented-option,
59
+ .sonic-slider,
60
+ .sonic-waveform,
61
+ .sonic-wavestrip,
62
+ .sonic-xy
38
63
  ) {
39
64
  --_sonic-lit: var(--sonic-lit, oklch(76.9% 0.165 70deg));
40
65
  }
41
66
 
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);
67
+ /* On the parts, since a recipe's `var()`s resolve where it is declared */
68
+ .sonic-dial-ring,
69
+ .sonic-dial-modulation,
70
+ .sonic-ring::before {
71
+ --_sonic-arc-mask: radial-gradient(
72
+ closest-side,
73
+ transparent calc(100% - var(--_sonic-arc-width) - 0.5px),
74
+ #000 calc(100% - var(--_sonic-arc-width)),
75
+ #000 calc(100% - var(--_sonic-arc-inset) - 0.5px),
76
+ transparent calc(100% - var(--_sonic-arc-inset))
77
+ );
78
+ --_sonic-arc-shade: radial-gradient(
79
+ closest-side,
80
+ rgb(0 0 0 / 55%) calc(100% - var(--_sonic-arc-width)),
81
+ transparent calc(100% - var(--_sonic-arc-width) * 0.4),
82
+ rgb(0 0 0 / 25%) 100%
83
+ );
46
84
  }
47
85
 
48
- .sonic-meter {
86
+ :is(.sonic-led, .sonic-meter) {
87
+ --_sonic-lens-glint: linear-gradient(
88
+ var(--_sonic-light-fall),
89
+ rgb(255 255 255 / 10%),
90
+ transparent 60%
91
+ );
92
+ --_sonic-lens-glass: color-mix(in oklab, var(--_sonic-unlit) 60%, #000);
93
+ --_sonic-lens: var(--_sonic-lens-glint), var(--_sonic-lens-glass);
49
94
  --_sonic-hot: var(--sonic-hot, oklch(70.5% 0.187 48deg));
50
95
  --_sonic-clip: var(--sonic-clip, oklch(63.7% 0.208 25deg));
51
96
  }
52
97
 
53
- :is(.sonic-dial, .sonic-key, .sonic-number, .sonic-segmented-segment, .sonic-slider) {
98
+ :is(
99
+ .sonic-dial,
100
+ .sonic-button,
101
+ .sonic-switch,
102
+ .sonic-number,
103
+ .sonic-segmented-option,
104
+ .sonic-slider,
105
+ .sonic-waveform,
106
+ .sonic-wavestrip,
107
+ .sonic-xy
108
+ ) {
54
109
  --_sonic-cap: var(--sonic-cap, oklch(37% 0.012 286deg));
55
110
  --_sonic-cap-hover: var(--sonic-cap-hover, oklch(44.2% 0.015 286deg));
56
111
  --_sonic-focus: var(--sonic-focus, oklch(90% 0.23 128deg));
57
- --_sonic-ink: var(--sonic-mark, color-mix(in oklab, var(--_sonic-cap) 30%, #fff));
112
+ --_sonic-ink: var(--sonic-ink, color-mix(in oklab, var(--_sonic-cap) 30%, #fff));
58
113
  --_sonic-etch: color-mix(in oklab, var(--_sonic-ink) 30%, transparent);
59
114
  --_sonic-ink-lift: color-mix(in oklab, var(--_sonic-ink) 60%, #fff);
60
115
  --_sonic-lit-disabled: color-mix(in oklab, var(--_sonic-ink) 25%, var(--_sonic-unlit));
@@ -63,8 +118,6 @@
63
118
  color-mix(in oklab, var(--_sonic-cap) 70%, #fff),
64
119
  color-mix(in oklab, var(--_sonic-cap) 55%, #000)
65
120
  );
66
-
67
- /* Inverted from the skirt, as a dished face takes light */
68
121
  --_sonic-face: linear-gradient(
69
122
  var(--_sonic-light-fall),
70
123
  color-mix(in oklab, var(--_sonic-cap) 85%, #000),
@@ -93,16 +146,35 @@
93
146
  color-mix(in oklab, var(--_sonic-focus) 60%, transparent);
94
147
  }
95
148
 
96
- :is(.sonic-dial, .sonic-slider) {
97
- /* On the control, since the readout's font size reads it */
149
+ :is(.sonic-dial, .sonic-number, .sonic-slider, .sonic-waveform, .sonic-wavestrip) {
150
+ --_sonic-detent-zone: var(--sonic-detent-zone, 8px);
151
+ }
152
+
153
+ :is(.sonic-dial, .sonic-envelope, .sonic-slider, .sonic-waveform, .sonic-wavestrip, .sonic-xy) {
98
154
  --_sonic-readout-size: var(--sonic-readout-size, 1.5rem);
155
+ }
156
+
157
+ :is(.sonic-dial, .sonic-slider, .sonic-waveform, .sonic-wavestrip) {
99
158
  --_sonic-lit-off: var(
100
159
  --sonic-dimmed,
101
160
  color-mix(in oklab, var(--_sonic-lit) 50%, var(--_sonic-unlit))
102
161
  );
103
162
  }
104
163
 
105
- :is(.sonic-dial-readout, .sonic-number, .sonic-screen, .sonic-slider-readout) {
164
+ :is(
165
+ .sonic-dial-readout,
166
+ .sonic-envelope,
167
+ .sonic-envelope-readout,
168
+ .sonic-number,
169
+ .sonic-screen,
170
+ .sonic-slider-readout,
171
+ .sonic-waveform,
172
+ .sonic-waveform-readout,
173
+ .sonic-wavestrip,
174
+ .sonic-wavestrip-readout,
175
+ .sonic-xy,
176
+ .sonic-xy-readout
177
+ ) {
106
178
  --_sonic-glass: var(--sonic-glass, color-mix(in oklab, var(--_sonic-unlit) 45%, #000));
107
179
  --_sonic-glass-fill: radial-gradient(
108
180
  closest-side,
@@ -110,49 +182,139 @@
110
182
  var(--_sonic-glass)
111
183
  )
112
184
  var(--_sonic-glass);
113
-
114
- /* Not the cap's ink, which a skin may darken */
115
185
  --_sonic-glass-text: var(
116
186
  --sonic-glass-text,
117
187
  color-mix(in oklab, var(--_sonic-glass) 20%, #fff)
118
188
  );
189
+ --_sonic-glass-edge: 0 none;
190
+
191
+ /* Glass is forced to Canvas like the page, so only a border shows its edge */
192
+ @media (forced-colors: active) {
193
+ --_sonic-glass-edge: 1px solid CanvasText;
194
+ }
119
195
  }
120
196
 
121
197
  /* 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) {
198
+ :is(.sonic-envelope, .sonic-number, .sonic-screen, .sonic-waveform, .sonic-wavestrip, .sonic-xy) {
199
+ --_sonic-glass-depth: var(--sonic-glass-depth, 1);
200
+ --_sonic-glass-texture: var(--sonic-glass-texture, 1);
201
+ --_sonic-glass-pitch: max(2px, round(2 * var(--_sonic-unit), 1px));
202
+
123
203
  position: relative;
124
204
  box-sizing: border-box;
125
205
  display: grid;
126
206
  flex-shrink: 0;
127
207
  grid-template: minmax(0, 1fr) / minmax(0, 1fr);
128
208
  place-items: center;
129
- font-family: var(--sonic-glass-font);
209
+ font-family: var(--sonic-glass-font, inherit);
130
210
  color: var(--_sonic-glass-text);
131
-
132
- /* A double click aimed at a neighbouring control would highlight it */
133
211
  user-select: none;
134
212
  background: var(--_sonic-glass-fill);
213
+ border: var(--_sonic-glass-edge);
214
+
215
+ @media (forced-colors: active) {
216
+ --_sonic-glass-texture: 0;
217
+ }
135
218
 
136
219
  &::after {
137
220
  position: absolute;
138
221
  inset: 0;
139
222
  pointer-events: none;
140
223
  content: '';
141
- background: linear-gradient(var(--_sonic-light-fall), rgb(255 255 255 / 7%), transparent 45%);
224
+ background:
225
+ linear-gradient(
226
+ var(--_sonic-light-fall),
227
+ rgb(255 255 255 / calc(0.07 * var(--_sonic-glass-depth))),
228
+ transparent 45%
229
+ ),
230
+ radial-gradient(
231
+ farthest-corner,
232
+ transparent 55%,
233
+ rgb(0 0 0 / calc(0.4 * var(--_sonic-glass-texture)))
234
+ ),
235
+ repeating-linear-gradient(
236
+ to bottom,
237
+ rgb(0 0 0 / calc(0.04 * var(--_sonic-glass-texture))) 0
238
+ calc(var(--_sonic-glass-pitch) / 2),
239
+ transparent 0 var(--_sonic-glass-pitch)
240
+ );
142
241
  border-radius: inherit;
143
242
  box-shadow:
144
243
  var(--_sonic-well),
145
- inset 0 0 calc(3 * var(--_sonic-unit)) rgb(0 0 0 / 45%);
244
+ inset 0 0 calc(3 * var(--_sonic-glass-depth) * var(--_sonic-unit)) rgb(0 0 0 / 45%);
245
+ }
246
+
247
+ @media (forced-colors: none) {
248
+ /* No var() beside the tile, which would parse the url() again on every style recalculation */
249
+ &::before {
250
+ position: absolute;
251
+ inset: 0;
252
+ color: color-mix(in oklab, var(--_sonic-glass-text) 7.5%, transparent);
253
+ pointer-events: none;
254
+ content: '';
255
+ background:
256
+ radial-gradient(closest-side, currentcolor, transparent) no-repeat,
257
+ url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='128' height='128'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.056 -0.01925'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")
258
+ 0 0 / 128px 128px repeat;
259
+ border-radius: inherit;
260
+ opacity: min(1, var(--_sonic-glass-texture));
261
+ }
262
+
263
+ @media (prefers-reduced-motion: no-preference) {
264
+ &:is(:focus-visible, :focus-within)::before,
265
+ :state(dragging) > &::before {
266
+ animation: sonic-glass-breathe 3s ease-in-out infinite alternate;
267
+ }
268
+
269
+ @media (hover: hover) {
270
+ &:hover::before {
271
+ animation: sonic-glass-breathe 3s ease-in-out infinite alternate;
272
+ }
273
+ }
274
+ }
275
+ }
276
+ }
277
+
278
+ @media (forced-colors: none) {
279
+ :is(.sonic-number, .sonic-screen),
280
+ :is(.sonic-envelope, .sonic-waveform, .sonic-wavestrip, .sonic-xy)::after {
281
+ filter: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='w' x='-0.3' y='-0.3' width='1.6' height='1.6' primitiveUnits='objectBoundingBox' color-interpolation-filters='sRGB'%3E%3CfeFlood x='0' y='0' width='1' height='1' flood-color='%23000'/%3E%3CfeFlood x='.5' y='0' width='.5' height='1' flood-color='%23f00' result='r'/%3E%3CfeFlood x='0' y='.5' width='1' height='.5' flood-color='%230f0' result='g'/%3E%3CfeFlood x='0' y='0' width='1' height='1' flood-color='%23000' result='k'/%3E%3CfeComposite in='r' in2='g' operator='arithmetic' k2='1' k3='1' result='h'/%3E%3CfeMerge x='0' y='0' width='1' height='1'%3E%3CfeMergeNode in='k'/%3E%3CfeMergeNode in='h'/%3E%3C/feMerge%3E%3CfeGaussianBlur x='0' y='0' width='1' height='1' stdDeviation='0.25'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1'/%3E%3CfeComponentTransfer result='a'%3E%3CfeFuncR type='table' tableValues='0 0.052 0.172 0.25 0.312 0.364 0.412 0.457 0.5 0.543 0.588 0.636 0.688 0.75 0.828 0.948 1'/%3E%3CfeFuncG type='table' tableValues='0 0.052 0.172 0.25 0.312 0.364 0.412 0.457 0.5 0.543 0.588 0.636 0.688 0.75 0.828 0.948 1'/%3E%3C/feComponentTransfer%3E%3CfeComponentTransfer%3E%3CfeFuncR type='table' tableValues='1 0.563 0.25 0.063 0 0.063 0.25 0.563 1'/%3E%3CfeFuncG type='table' tableValues='1 0.563 0.25 0.063 0 0.063 0.25 0.563 1'/%3E%3C/feComponentTransfer%3E%3CfeColorMatrix values='.5 .5 0 0 0 .5 .5 0 0 0 0 0 0 0 0 0 0 0 0 1'/%3E%3CfeComponentTransfer result='f'%3E%3CfeFuncR type='gamma' amplitude='0.333' exponent='2'/%3E%3CfeFuncG type='gamma' exponent='2'/%3E%3C/feComponentTransfer%3E%3CfeComposite in='a' in2='f' operator='arithmetic' k1='1' k3='-.5' k4='.5' result='m'/%3E%3CfeFlood flood-color='%23808080'/%3E%3CfeMerge result='n'%3E%3CfeMergeNode/%3E%3CfeMergeNode in='m'/%3E%3C/feMerge%3E%3CfeDisplacementMap in='SourceGraphic' in2='n' scale='0.04' xChannelSelector='R' yChannelSelector='G'/%3E%3C/filter%3E%3C/svg%3E#w");
282
+ }
283
+
284
+ /* A query reads the parent, or a pseudo-element's own element: on a readout itself, 0 leaves the warp on */
285
+ @container style(--sonic-glass-texture: 0) {
286
+ :is(.sonic-number, .sonic-screen),
287
+ :is(.sonic-envelope, .sonic-waveform, .sonic-wavestrip, .sonic-xy)::after {
288
+ filter: none;
289
+ }
146
290
  }
147
291
  }
148
292
 
149
- :is(.sonic-key, .sonic-number, .sonic-screen, .sonic-segmented) {
293
+ :is(
294
+ .sonic-envelope,
295
+ .sonic-button,
296
+ .sonic-number,
297
+ .sonic-screen,
298
+ .sonic-segmented,
299
+ .sonic-waveform,
300
+ .sonic-wavestrip,
301
+ .sonic-xy
302
+ ) {
303
+ --_sonic-well-depth: var(--_sonic-glass-depth, 1);
150
304
  --_sonic-well:
151
- inset var(--_sonic-cast-x) var(--_sonic-cast-y) calc(2 * var(--_sonic-unit)) rgb(0 0 0 / 60%),
152
- calc(0.5 * var(--_sonic-cast-x)) calc(0.5 * var(--_sonic-cast-y)) 0 rgb(255 255 255 / 6%);
305
+ inset calc(var(--_sonic-well-depth) * var(--_sonic-cast-x))
306
+ calc(var(--_sonic-well-depth) * var(--_sonic-cast-y))
307
+ calc(2 * var(--_sonic-well-depth) * var(--_sonic-unit)) rgb(0 0 0 / 60%),
308
+ calc(0.5 * var(--_sonic-well-depth) * var(--_sonic-cast-x))
309
+ calc(0.5 * var(--_sonic-well-depth) * var(--_sonic-cast-y)) 0 rgb(255 255 255 / 6%);
153
310
  }
154
311
 
155
- :is(.sonic-key, .sonic-segmented) {
312
+ :is(.sonic-button, .sonic-segmented) {
313
+ --_sonic-well-floor: linear-gradient(
314
+ var(--_sonic-light-fall),
315
+ color-mix(in oklab, var(--_sonic-unlit) 55%, #000),
316
+ color-mix(in oklab, var(--_sonic-unlit) 85%, #000)
317
+ );
156
318
  --_sonic-engraving: drop-shadow(
157
319
  calc(-0.4 * var(--_sonic-cast-x)) calc(-0.4 * var(--_sonic-cast-y))
158
320
  calc(0.4 * var(--_sonic-unit)) rgb(0 0 0 / 30%)
@@ -162,7 +324,44 @@
162
324
  );
163
325
  }
164
326
 
165
- /* The well's full blur would fill a slot this narrow */
327
+ /* On the option rather than the strip, where forced colours clear the drop shade */
328
+ :is(.sonic-button, .sonic-segmented-option) {
329
+ --_sonic-press-drop: calc(0.5 * var(--_sonic-cast-x)) calc(0.5 * var(--_sonic-cast-y))
330
+ var(--_sonic-unit) var(--_sonic-drop-shade);
331
+ --_sonic-keycap-shift: calc(var(--_sonic-keycap-depth) / -2);
332
+ --_sonic-keycap-scale: 1;
333
+ --_sonic-keycap-drop: calc(1.5 * var(--_sonic-cast-x)) calc(1.5 * var(--_sonic-cast-y))
334
+ calc(2 * var(--_sonic-unit)) var(--_sonic-drop-shade);
335
+ --_sonic-keycap-glow: transparent;
336
+ }
337
+
338
+ /* Each sheet maps its own depth, corner, bevel and face corner onto the `keycap` tokens */
339
+ :is(.sonic-button-cap, .sonic-segmented-cap) {
340
+ display: grid;
341
+ place-items: center;
342
+ background: var(--_sonic-skirt);
343
+ border-radius: var(--_sonic-keycap-corner);
344
+ box-shadow: var(--_sonic-keycap-drop), var(--_sonic-rim), var(--_sonic-focus-shadow);
345
+ scale: var(--_sonic-keycap-scale);
346
+ translate: 0 var(--_sonic-keycap-shift);
347
+ transition: var(--_sonic-press-transition);
348
+
349
+ &::before {
350
+ position: absolute;
351
+ inset: var(--_sonic-keycap-bevel);
352
+ content: '';
353
+ background:
354
+ radial-gradient(closest-side, var(--_sonic-keycap-glow), transparent), var(--_sonic-sheen),
355
+ var(--_sonic-face);
356
+ border-radius: var(--_sonic-keycap-face-corner);
357
+ box-shadow: var(--_sonic-face-shadow);
358
+ }
359
+
360
+ & > * {
361
+ position: relative;
362
+ }
363
+ }
364
+
166
365
  :is(.sonic-meter, .sonic-slider) {
167
366
  --_sonic-groove:
168
367
  inset var(--_sonic-cast-x) var(--_sonic-cast-y) calc(0.75 * var(--_sonic-unit))
@@ -172,7 +371,7 @@
172
371
  }
173
372
 
174
373
  @media (hover: hover) {
175
- :is(.sonic-dial, .sonic-key, .sonic-segmented-segment, .sonic-slider):not(
374
+ :is(.sonic-dial, .sonic-button, .sonic-segmented-option, .sonic-slider):not(
176
375
  :disabled,
177
376
  [aria-disabled='true']
178
377
  ):hover {
@@ -182,25 +381,37 @@
182
381
 
183
382
  :is(
184
383
  .sonic-dial,
185
- .sonic-key,
384
+ .sonic-button,
186
385
  .sonic-number,
187
- .sonic-segmented-segment,
188
- .sonic-slider
386
+ .sonic-segmented-option,
387
+ .sonic-slider,
388
+ .sonic-waveform,
389
+ .sonic-wavestrip,
390
+ .sonic-xy-axis
189
391
  ):focus-visible {
190
- --_sonic-cap: var(--_sonic-cap-hover);
191
- --_sonic-focus-shadow: var(--_sonic-focus-glow);
192
-
193
392
  outline: 2px solid transparent;
194
393
  outline-offset: -2px;
394
+
395
+ &:not([data-sonic-pointer-focus]) {
396
+ --_sonic-cap: var(--_sonic-cap-hover);
397
+ --_sonic-focus-shadow: var(--_sonic-focus-glow);
398
+ }
195
399
  }
196
400
 
197
- /* Keeps the glow while focus is in the entry; its own rule, since an engine without `:state()` drops a whole selector list */
198
- :state(editing) > :is(.sonic-dial, .sonic-number, .sonic-slider) {
401
+ :state(editing)
402
+ > :is(.sonic-dial, .sonic-number, .sonic-slider, .sonic-waveform, .sonic-wavestrip) {
199
403
  --_sonic-cap: var(--_sonic-cap-hover);
200
404
  --_sonic-focus-shadow: var(--_sonic-focus-glow);
201
405
  }
202
406
 
203
- :is(.sonic-dial-readout, .sonic-slider-readout) {
407
+ :is(
408
+ .sonic-dial-readout,
409
+ .sonic-envelope-readout,
410
+ .sonic-slider-readout,
411
+ .sonic-waveform-readout,
412
+ .sonic-wavestrip-readout,
413
+ .sonic-xy-readout
414
+ ) {
204
415
  --_sonic-unit: calc(var(--_sonic-readout-size) / 32);
205
416
 
206
417
  box-sizing: border-box;
@@ -213,7 +424,7 @@
213
424
  position-try-fallbacks: flip-block;
214
425
  overflow: visible;
215
426
  font: inherit;
216
- font-family: var(--sonic-glass-font);
427
+ font-family: var(--sonic-glass-font, inherit);
217
428
  font-size: calc(0.5 * var(--_sonic-readout-size));
218
429
  font-variant-numeric: tabular-nums;
219
430
  line-height: 1;
@@ -222,7 +433,7 @@
222
433
  cursor: default;
223
434
  user-select: none;
224
435
  background: var(--_sonic-glass-fill);
225
- border: 0;
436
+ border: var(--_sonic-glass-edge);
226
437
  border-radius: calc(0.25 * var(--_sonic-readout-size));
227
438
  box-shadow:
228
439
  calc(2 * var(--_sonic-cast-x)) calc(2 * var(--_sonic-cast-y)) calc(6 * var(--_sonic-unit))
@@ -236,7 +447,7 @@
236
447
  display 120ms allow-discrete,
237
448
  overlay 120ms allow-discrete;
238
449
 
239
- /* Grid only while open; a closed readout left rendered is placed against a filtered ancestor, and engines keep the flip it took there */
450
+ /* Grid only while open; engines keep the flip a closed readout took against a filtered ancestor */
240
451
  &:popover-open {
241
452
  display: grid;
242
453
  opacity: 1;
@@ -257,16 +468,20 @@
257
468
  }
258
469
  }
259
470
  }
260
- }
261
471
 
262
- :state(editing)
263
- > :is(.sonic-dial, .sonic-slider)
264
- > :is(.sonic-dial-readout, .sonic-slider-readout) {
265
- pointer-events: auto;
266
- cursor: text;
472
+ :state(editing) > :is(.sonic-dial, .sonic-slider, .sonic-waveform, .sonic-wavestrip) > & {
473
+ pointer-events: auto;
474
+ cursor: text;
475
+ }
267
476
  }
268
477
 
269
- :is(.sonic-dial-entry, .sonic-number-entry, .sonic-slider-entry) {
478
+ :is(
479
+ .sonic-dial-entry,
480
+ .sonic-number-entry,
481
+ .sonic-slider-entry,
482
+ .sonic-waveform-entry,
483
+ .sonic-wavestrip-entry
484
+ ) {
270
485
  inline-size: 6ch;
271
486
  padding: 0;
272
487
  font: inherit;
@@ -292,14 +507,41 @@
292
507
  }
293
508
  }
294
509
 
510
+ :is(.sonic-dial-scale, .sonic-slider-scale) {
511
+ position: absolute;
512
+ inset: 0;
513
+ line-height: 1;
514
+ white-space: nowrap;
515
+ pointer-events: none;
516
+
517
+ & > * {
518
+ position: absolute;
519
+ }
520
+
521
+ & svg {
522
+ display: block;
523
+ inline-size: 1em;
524
+ block-size: 1em;
525
+ }
526
+
527
+ & > .sonic-scale-tick {
528
+ background: var(--_sonic-etch);
529
+ }
530
+ }
531
+
295
532
  @media (forced-colors: active) {
533
+ .sonic-scale-tick {
534
+ forced-color-adjust: none;
535
+ }
536
+
296
537
  :is(
297
538
  .sonic-dial,
298
- .sonic-key,
539
+ .sonic-button,
299
540
  .sonic-led,
300
541
  .sonic-meter,
301
542
  .sonic-number,
302
- .sonic-segmented-segment,
543
+ .sonic-ring,
544
+ .sonic-segmented-option,
303
545
  .sonic-slider
304
546
  ) {
305
547
  --_sonic-lit: Highlight;
@@ -307,7 +549,16 @@
307
549
  }
308
550
 
309
551
  /* 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) {
552
+ :is(
553
+ .sonic-dial,
554
+ .sonic-button,
555
+ .sonic-number,
556
+ .sonic-segmented-option,
557
+ .sonic-slider,
558
+ .sonic-waveform,
559
+ .sonic-wavestrip,
560
+ .sonic-xy
561
+ ) {
311
562
  --_sonic-ink: ButtonText;
312
563
  --_sonic-etch: ButtonText;
313
564
  --_sonic-lit-disabled: GrayText;
@@ -320,39 +571,38 @@
320
571
  --_sonic-focus-glow: 0 0 transparent;
321
572
  }
322
573
 
323
- /* Dimmed is a hint, not a state; the value stays readable */
324
- :is(.sonic-dial, .sonic-slider) {
574
+ :is(.sonic-dial, .sonic-slider, .sonic-waveform, .sonic-wavestrip) {
325
575
  --_sonic-lit-off: Highlight;
326
576
  }
327
577
 
328
578
  :is(
329
- :disabled > :is(.sonic-dial, .sonic-slider),
330
- .sonic-key:disabled,
331
- .sonic-segmented-segment:disabled
579
+ :disabled > :is(.sonic-dial, .sonic-slider, .sonic-waveform, .sonic-wavestrip, .sonic-xy),
580
+ .sonic-button:is(:disabled, [aria-disabled='true']),
581
+ .sonic-segmented-option:disabled
332
582
  ) {
333
583
  --_sonic-ink: GrayText;
334
584
  --_sonic-etch: GrayText;
335
585
  }
336
586
 
337
- /* Stands in for the glow, which forced colours drop; inset, it merged with the cap's rim */
338
587
  :is(
339
588
  .sonic-dial,
340
- .sonic-key,
589
+ .sonic-button,
341
590
  .sonic-number,
342
- .sonic-segmented-segment,
343
- .sonic-slider
591
+ .sonic-segmented-option,
592
+ .sonic-slider,
593
+ .sonic-waveform,
594
+ .sonic-wavestrip
344
595
  ):focus-visible {
345
596
  outline-offset: 2px;
597
+
598
+ &[data-sonic-pointer-focus] {
599
+ outline-style: none;
600
+ }
346
601
  }
347
602
 
348
- :is(.sonic-dial-cap, .sonic-key-cap, .sonic-segmented-cap, .sonic-slider-cap) {
603
+ :is(.sonic-dial-cap, .sonic-button-cap, .sonic-segmented-cap, .sonic-slider-cap) {
349
604
  color: var(--_sonic-ink);
350
605
  forced-color-adjust: none;
351
606
  }
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
607
  }
358
608
  }