@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
@@ -16,7 +16,6 @@
16
16
  initial-value: 4px;
17
17
  }
18
18
 
19
- /* The size is the thickness */
20
19
  @layer sonic {
21
20
  :is(sonic-meter, .sonic-meter) {
22
21
  --_sonic-meter-size: var(--sonic-meter-size, 0.5rem);
@@ -40,23 +39,17 @@
40
39
  }
41
40
 
42
41
  .sonic-meter {
43
- /* Absolute, so a longer meter gains segments rather than stretching them */
44
42
  --_sonic-meter-pitch: var(--sonic-meter-segment-pitch, 4px);
45
-
46
- /* A fraction of the pitch */
47
43
  --_sonic-meter-gap-ratio: var(--sonic-meter-gap-ratio, 0.25);
48
44
  --_sonic-meter-radius-ratio: var(--sonic-meter-radius-ratio, 0.25);
49
-
50
- /* A fraction of the light's length along the meter */
51
45
  --_sonic-meter-segment-radius-ratio: var(--sonic-meter-segment-radius-ratio, 0.35);
52
-
53
- /* dBFS */
54
46
  --_sonic-meter-hot-from: var(--sonic-meter-hot-from, -12);
55
47
  --_sonic-meter-clip-from: var(--sonic-meter-clip-from, -3);
56
48
  --_sonic-unit: calc(var(--_sonic-meter-size) / 8);
57
49
  --_sonic-meter-toward: to top;
58
50
  --_sonic-meter-inset: calc(var(--_sonic-meter-size) * 0.125);
59
51
  --_sonic-meter-lens: calc(var(--_sonic-meter-size) - 2 * var(--_sonic-meter-inset));
52
+ --_sonic-meter-clip-space: calc(var(--_sonic-meter-inset) + var(--_sonic-meter-lens));
60
53
  --_sonic-meter-gap: calc(var(--_sonic-meter-pitch) * var(--_sonic-meter-gap-ratio));
61
54
  --_sonic-meter-segment: calc(var(--_sonic-meter-pitch) - var(--_sonic-meter-gap));
62
55
  --_sonic-meter-segment-radius: calc(
@@ -64,7 +57,7 @@
64
57
  );
65
58
  --_sonic-meter-segments: round(
66
59
  down,
67
- var(--_sonic-meter-length) - 3 * var(--_sonic-meter-inset) - var(--_sonic-meter-lens) +
60
+ var(--_sonic-meter-length) - 2 * var(--_sonic-meter-inset) - var(--_sonic-meter-clip-space) +
68
61
  var(--_sonic-meter-gap),
69
62
  var(--_sonic-meter-pitch)
70
63
  );
@@ -93,8 +86,26 @@
93
86
  block-size: var(--_sonic-meter-size);
94
87
  }
95
88
 
96
- /* Snapped to whole lights, so none is split between two colours */
97
- :is(.sonic-meter-segments, .sonic-meter-level) {
89
+ :is([value], :state(ladder)) > .sonic-meter {
90
+ --_sonic-meter-clip-space: 0px;
91
+ }
92
+
93
+ :state(ladder) > .sonic-meter {
94
+ --_sonic-meter-pitch: calc(
95
+ (var(--_sonic-meter-length) - 2 * var(--_sonic-meter-inset)) / var(--_sonic-meter-count, 1)
96
+ );
97
+ --_sonic-meter-gap: 0px;
98
+ --_sonic-meter-segments: calc(var(--_sonic-meter-length) - 2 * var(--_sonic-meter-inset));
99
+ --_sonic-meter-ladder-radius: calc(
100
+ min(
101
+ var(--_sonic-meter-lens),
102
+ var(--_sonic-meter-pitch) * (1 - var(--_sonic-meter-gap-ratio))
103
+ ) /
104
+ 2
105
+ );
106
+ }
107
+
108
+ :is(.sonic-meter-segments, .sonic-meter-bar) {
98
109
  --_sonic-meter-span: calc(var(--_sonic-meter-max, 0) - var(--_sonic-meter-min, -60));
99
110
  --_sonic-meter-hot-at: round(
100
111
  clamp(
@@ -108,15 +119,15 @@
108
119
  --_sonic-meter-clip-at: round(
109
120
  clamp(
110
121
  0,
111
- (var(--_sonic-meter-clip-from) - var(--_sonic-meter-min, -60)) / var(--_sonic-meter-span),
122
+ /* fallow-ignore-next-line code-duplication -- each zone snaps its own threshold */
123
+ (var(--_sonic-meter-clip-from) - var(--_sonic-meter-min, -60)) /
124
+ var(--_sonic-meter-span),
112
125
  1
113
126
  ) *
114
127
  var(--_sonic-meter-segments),
115
128
  var(--_sonic-meter-pitch)
116
129
  );
117
-
118
- /* Each rounded light is two crossed bands and four corner dots added together */
119
- --_sonic-meter-lights:
130
+ --_sonic-meter-segment-mask:
120
131
  linear-gradient(to top, #000 var(--_sonic-meter-segment), transparent 0)
121
132
  var(--_sonic-meter-segment-radius) 100% /
122
133
  calc(100% - 2 * var(--_sonic-meter-segment-radius)) var(--_sonic-meter-pitch) no-repeat
@@ -144,6 +155,7 @@
144
155
  0 100% / 100% var(--_sonic-meter-pitch) no-repeat repeat,
145
156
  radial-gradient(
146
157
  circle var(--_sonic-meter-segment-radius) at left var(--_sonic-meter-segment-radius)
158
+ /* fallow-ignore-next-line code-duplication -- one gradient per segment corner is geometry, not copied logic */
147
159
  bottom calc(var(--_sonic-meter-segment) - var(--_sonic-meter-segment-radius)),
148
160
  #000 calc(100% - 0.5px),
149
161
  transparent
@@ -160,12 +172,28 @@
160
172
  position: absolute;
161
173
  inset: auto var(--_sonic-meter-inset) var(--_sonic-meter-inset);
162
174
  block-size: calc(var(--_sonic-meter-segments) - var(--_sonic-meter-gap));
163
- mask: var(--_sonic-meter-lights);
175
+ mask: var(--_sonic-meter-segment-mask);
164
176
  mask-composite: add;
165
177
  }
166
178
 
167
- [orientation='horizontal'] > .sonic-meter > :is(.sonic-meter-segments, .sonic-meter-level) {
168
- --_sonic-meter-lights:
179
+ :state(ladder) > .sonic-meter > :is(.sonic-meter-segments, .sonic-meter-bar) {
180
+ --_sonic-meter-hot-at: calc(var(--_sonic-meter-hot-segments, 0) * var(--_sonic-meter-pitch));
181
+ --_sonic-meter-clip-at: calc(var(--_sonic-meter-clip-segments, 0) * var(--_sonic-meter-pitch));
182
+ --_sonic-meter-segment-mask: radial-gradient(
183
+ circle var(--_sonic-meter-ladder-radius),
184
+ #000 calc(100% - 0.5px),
185
+ transparent
186
+ )
187
+ 0 100% / 100% var(--_sonic-meter-pitch) no-repeat repeat;
188
+ }
189
+
190
+ [value] > .sonic-meter > :is(.sonic-meter-segments, .sonic-meter-bar) {
191
+ --_sonic-meter-hot-at: var(--_sonic-meter-segments);
192
+ --_sonic-meter-clip-at: var(--_sonic-meter-segments);
193
+ }
194
+
195
+ [orientation='horizontal'] > .sonic-meter > :is(.sonic-meter-segments, .sonic-meter-bar) {
196
+ --_sonic-meter-segment-mask:
169
197
  linear-gradient(to right, #000 var(--_sonic-meter-segment), transparent 0) 0
170
198
  var(--_sonic-meter-segment-radius) / var(--_sonic-meter-pitch)
171
199
  calc(100% - 2 * var(--_sonic-meter-segment-radius)) repeat no-repeat,
@@ -194,6 +222,7 @@
194
222
  radial-gradient(
195
223
  circle var(--_sonic-meter-segment-radius) at left
196
224
  calc(var(--_sonic-meter-segment) - var(--_sonic-meter-segment-radius)) top
225
+ /* fallow-ignore-next-line code-duplication -- one gradient per segment corner is geometry, not copied logic */
197
226
  var(--_sonic-meter-segment-radius),
198
227
  #000 calc(100% - 0.5px),
199
228
  transparent
@@ -213,6 +242,42 @@
213
242
  block-size: auto;
214
243
  }
215
244
 
245
+ [orientation='horizontal']:state(ladder)
246
+ > .sonic-meter
247
+ > :is(.sonic-meter-segments, .sonic-meter-bar) {
248
+ --_sonic-meter-segment-mask: radial-gradient(
249
+ circle var(--_sonic-meter-ladder-radius),
250
+ #000 calc(100% - 0.5px),
251
+ transparent
252
+ )
253
+ 0 0 / var(--_sonic-meter-pitch) 100% repeat no-repeat;
254
+ }
255
+
256
+ :state(ladder) > .sonic-meter > :is(.sonic-meter-segments, .sonic-meter-bar)::after {
257
+ position: absolute;
258
+ inset: 0;
259
+ content: '';
260
+ background: linear-gradient(var(--_sonic-light-fall), rgb(255 255 255 / 10%), transparent 60%) 0
261
+ 100% / 100% var(--_sonic-meter-pitch) repeat-y;
262
+ }
263
+
264
+ :state(ladder) > .sonic-meter > .sonic-meter-bar::after {
265
+ background: radial-gradient(
266
+ circle var(--_sonic-meter-ladder-radius),
267
+ rgb(255 255 255 / 45%),
268
+ transparent
269
+ )
270
+ 0 100% / 100% var(--_sonic-meter-pitch) repeat-y;
271
+ }
272
+
273
+ [orientation='horizontal']:state(ladder)
274
+ > .sonic-meter
275
+ > :is(.sonic-meter-segments, .sonic-meter-bar)::after {
276
+ background-repeat: repeat-x;
277
+ background-position: 0 0;
278
+ background-size: var(--_sonic-meter-pitch) 100%;
279
+ }
280
+
216
281
  .sonic-meter-segments {
217
282
  background: linear-gradient(
218
283
  var(--_sonic-meter-toward),
@@ -222,16 +287,23 @@
222
287
  );
223
288
  }
224
289
 
225
- /* One mask for the bar and peak, so a frame repaints without layout */
226
- .sonic-meter-level {
290
+ /* The hair of slack keeps an exact fraction from losing a segment to float error */
291
+ .sonic-meter-bar {
292
+ --_sonic-meter-lit-from: round(
293
+ up,
294
+ min(var(--_sonic-meter-origin, 0), var(--_sonic-meter-bar, 0)) *
295
+ var(--_sonic-meter-segments) - 0.01px,
296
+ var(--_sonic-meter-pitch)
297
+ );
227
298
  --_sonic-meter-lit: round(
228
299
  down,
229
- var(--_sonic-meter-level, 0) * var(--_sonic-meter-segments),
300
+ max(var(--_sonic-meter-origin, 0), var(--_sonic-meter-bar, 0)) *
301
+ var(--_sonic-meter-segments) + 0.01px,
230
302
  var(--_sonic-meter-pitch)
231
303
  );
232
- --_sonic-meter-held: round(
304
+ --_sonic-meter-peak-hold-edge: round(
233
305
  down,
234
- var(--_sonic-meter-peak, 0) * var(--_sonic-meter-segments),
306
+ var(--_sonic-meter-peak-hold, 0) * var(--_sonic-meter-segments) + 0.01px,
235
307
  var(--_sonic-meter-pitch)
236
308
  );
237
309
 
@@ -244,12 +316,13 @@
244
316
  mask:
245
317
  linear-gradient(
246
318
  var(--_sonic-meter-toward),
247
- #000 var(--_sonic-meter-lit),
248
- transparent 0 calc(var(--_sonic-meter-held) - var(--_sonic-meter-pitch)),
249
- #000 0 var(--_sonic-meter-held),
319
+ transparent var(--_sonic-meter-lit-from),
320
+ #000 0 var(--_sonic-meter-lit),
321
+ transparent 0 calc(var(--_sonic-meter-peak-hold-edge) - var(--_sonic-meter-pitch)),
322
+ #000 0 var(--_sonic-meter-peak-hold-edge),
250
323
  transparent 0
251
324
  ),
252
- var(--_sonic-meter-lights);
325
+ var(--_sonic-meter-segment-mask);
253
326
  mask-composite: intersect, add, add, add, add, add, add;
254
327
  }
255
328
 
@@ -274,6 +347,10 @@
274
347
  }
275
348
  }
276
349
 
350
+ :is([value], :state(ladder)) > .sonic-meter > .sonic-meter-clip {
351
+ display: none;
352
+ }
353
+
277
354
  [orientation='horizontal'] > .sonic-meter > .sonic-meter-clip {
278
355
  inset: var(--_sonic-meter-inset) var(--_sonic-meter-inset) var(--_sonic-meter-inset) auto;
279
356
  inline-size: var(--_sonic-meter-lens);
@@ -296,12 +373,16 @@
296
373
  background: var(--_sonic-unlit);
297
374
  }
298
375
 
299
- .sonic-meter-level {
376
+ .sonic-meter-bar {
300
377
  background: var(--_sonic-lit);
301
378
  }
302
379
 
303
380
  .sonic-meter-clip::after {
304
381
  background: Mark;
305
382
  }
383
+
384
+ :state(ladder) > .sonic-meter > :is(.sonic-meter-segments, .sonic-meter-bar)::after {
385
+ display: none;
386
+ }
306
387
  }
307
388
  }
@@ -40,12 +40,16 @@
40
40
  font-size: calc(var(--_sonic-number-size) * var(--_sonic-number-text-ratio));
41
41
  font-variant-numeric: tabular-nums;
42
42
  line-height: 1;
43
- touch-action: none;
43
+ touch-action: pan-x;
44
44
  cursor: ns-resize;
45
45
  border-radius: calc(var(--_sonic-number-size) * var(--_sonic-number-radius-ratio));
46
46
  box-shadow: var(--_sonic-focus-shadow);
47
47
  }
48
48
 
49
+ [press='step'] > .sonic-number {
50
+ cursor: pointer;
51
+ }
52
+
49
53
  :disabled > .sonic-number {
50
54
  color: var(--_sonic-etch);
51
55
  cursor: default;
@@ -0,0 +1,59 @@
1
+ @property --_sonic-panel-depth {
2
+ syntax: '<length>';
3
+ inherits: true;
4
+ initial-value: 2px;
5
+ }
6
+
7
+ @property --_sonic-panel-radius {
8
+ syntax: '<length>';
9
+ inherits: true;
10
+ initial-value: 12px;
11
+ }
12
+
13
+ @layer sonic {
14
+ :is(.sonic-panel, .sonic-panel-title, .sonic-panel-rule) {
15
+ --_sonic-panel-line: color-mix(in oklab, currentcolor 20%, transparent);
16
+ }
17
+
18
+ .sonic-panel {
19
+ --_sonic-panel-depth: var(--sonic-panel-depth, 0.125rem);
20
+ --_sonic-panel-radius: var(--sonic-panel-radius, 0.75rem);
21
+ --_sonic-unit: var(--_sonic-panel-depth);
22
+
23
+ background: var(--sonic-panel, rgb(255 255 255 / 3%));
24
+ border: 1px solid var(--_sonic-panel-line);
25
+ border-radius: var(--_sonic-panel-radius);
26
+ box-shadow:
27
+ inset var(--_sonic-cast-x) var(--_sonic-cast-y)
28
+ max(var(--_sonic-panel-depth), -1 * var(--_sonic-panel-depth)) rgb(255 255 255 / 7%),
29
+ inset calc(-1 * var(--_sonic-cast-x)) calc(-1 * var(--_sonic-cast-y))
30
+ max(var(--_sonic-panel-depth), -1 * var(--_sonic-panel-depth)) rgb(0 0 0 / 35%),
31
+ calc(2 * sin(var(--_sonic-light-tilt)) * max(0px, var(--_sonic-panel-depth)))
32
+ calc(2 * cos(var(--_sonic-light-tilt)) * max(0px, var(--_sonic-panel-depth)))
33
+ calc(3 * max(0px, var(--_sonic-panel-depth))) rgb(0 0 0 / 45%);
34
+ }
35
+
36
+ .sonic-panel-title {
37
+ display: flex;
38
+ gap: 0.75em;
39
+ align-items: center;
40
+ margin: 0;
41
+ white-space: nowrap;
42
+
43
+ &::before,
44
+ &::after {
45
+ flex: 1;
46
+ min-inline-size: 1em;
47
+ content: '';
48
+ border-block-start: 1px solid var(--_sonic-panel-line);
49
+ }
50
+ }
51
+
52
+ .sonic-panel-rule {
53
+ align-self: stretch;
54
+ block-size: 0;
55
+ margin: 0;
56
+ border: 0;
57
+ border-block-start: 1px solid var(--_sonic-panel-line);
58
+ }
59
+ }
@@ -0,0 +1,74 @@
1
+ @property --_sonic-ring-size {
2
+ syntax: '<length>';
3
+ inherits: true;
4
+ initial-value: 40px;
5
+ }
6
+
7
+ @layer sonic {
8
+ .sonic-ring {
9
+ --_sonic-ring-size: var(--sonic-ring-size, 2.5rem);
10
+ --_sonic-ring-ratio: var(--sonic-ring-ratio, 0.075);
11
+ --_sonic-ring-gap-ratio: var(--sonic-ring-gap-ratio, 0.05);
12
+ --_sonic-ring-start: var(--sonic-ring-start, 0deg);
13
+ --_sonic-ring-sweep: var(--sonic-ring-sweep, 360deg);
14
+ --_sonic-ring-from: clamp(0, var(--sonic-ring-from, 0), 1);
15
+ --_sonic-ring-to: clamp(0, var(--sonic-ring-to, 0), 1);
16
+
17
+ position: relative;
18
+ box-sizing: border-box;
19
+ display: inline-grid;
20
+ flex-shrink: 0;
21
+ grid-template: minmax(0, 1fr) / minmax(0, 1fr);
22
+ place-items: center;
23
+ inline-size: var(--_sonic-ring-size);
24
+ block-size: var(--_sonic-ring-size);
25
+ padding: calc(
26
+ var(--_sonic-ring-size) * (var(--_sonic-ring-ratio) + var(--_sonic-ring-gap-ratio))
27
+ );
28
+ border-radius: 50%;
29
+
30
+ &::before {
31
+ --_sonic-arc-width: calc(var(--_sonic-ring-size) * var(--_sonic-ring-ratio));
32
+ --_sonic-arc-inset: 0px;
33
+
34
+ position: absolute;
35
+ inset: 0;
36
+ pointer-events: none;
37
+ content: '';
38
+ background:
39
+ var(--_sonic-arc-shade),
40
+ conic-gradient(
41
+ from var(--_sonic-ring-start),
42
+ var(--_sonic-unlit)
43
+ calc(min(var(--_sonic-ring-from), var(--_sonic-ring-to)) * var(--_sonic-ring-sweep)),
44
+ var(--_sonic-lit) 0
45
+ calc(max(var(--_sonic-ring-from), var(--_sonic-ring-to)) * var(--_sonic-ring-sweep)),
46
+ var(--_sonic-unlit) 0 var(--_sonic-ring-sweep),
47
+ transparent 0
48
+ );
49
+ border-radius: 50%;
50
+ mask: var(--_sonic-arc-mask);
51
+ }
52
+
53
+ @media (forced-colors: active) {
54
+ &::before {
55
+ --_sonic-arc-shade: none;
56
+
57
+ forced-color-adjust: none;
58
+ }
59
+ }
60
+ }
61
+
62
+ .sonic-ring > :not(:defined),
63
+ .sonic-ring > * > .sonic-button {
64
+ --_sonic-button-size: calc(
65
+ var(--_sonic-ring-size) * (1 - 2 * (var(--_sonic-ring-ratio) + var(--_sonic-ring-gap-ratio)))
66
+ );
67
+ --_sonic-button-aspect-ratio: 1;
68
+ }
69
+
70
+ .sonic-ring > * > .sonic-button {
71
+ --_sonic-button-radius-ratio: 0.5;
72
+ --_sonic-button-face-radius-ratio: 0.5;
73
+ }
74
+ }
@@ -34,9 +34,7 @@
34
34
  --_sonic-segmented-corner: calc(
35
35
  var(--_sonic-segmented-size) * var(--_sonic-segmented-radius-ratio)
36
36
  );
37
- --_sonic-segmented-depth: calc(
38
- var(--_sonic-segmented-size) * var(--_sonic-segmented-depth-ratio)
39
- );
37
+ --_sonic-keycap-depth: calc(var(--_sonic-segmented-size) * var(--_sonic-segmented-depth-ratio));
40
38
  --_sonic-segmented-gap: calc(var(--_sonic-segmented-size) * var(--_sonic-segmented-gap-ratio));
41
39
  --_sonic-segmented-inner-corner: max(
42
40
  0px,
@@ -51,22 +49,12 @@
51
49
  padding: var(--_sonic-segmented-gap);
52
50
  touch-action: pan-y;
53
51
  user-select: none;
54
- background: linear-gradient(
55
- var(--_sonic-light-fall),
56
- color-mix(in oklab, var(--_sonic-unlit) 55%, #000),
57
- color-mix(in oklab, var(--_sonic-unlit) 85%, #000)
58
- );
52
+ background: var(--_sonic-well-floor);
59
53
  border-radius: var(--_sonic-segmented-corner);
60
54
  box-shadow: var(--_sonic-well);
61
55
  }
62
56
 
63
- .sonic-segmented-segment {
64
- --_sonic-segmented-shift: calc(var(--_sonic-segmented-depth) / -2);
65
- --_sonic-segmented-scale: 1;
66
- --_sonic-segmented-drop: calc(1.5 * var(--_sonic-cast-x)) calc(1.5 * var(--_sonic-cast-y))
67
- calc(2 * var(--_sonic-unit)) var(--_sonic-drop-shade);
68
- --_sonic-segmented-glow: transparent;
69
-
57
+ .sonic-segmented-option {
70
58
  display: grid;
71
59
  min-inline-size: calc(var(--_sonic-segmented-size) - 2 * var(--_sonic-segmented-gap));
72
60
  padding: 0;
@@ -81,30 +69,29 @@
81
69
  transition: color 120ms ease-out;
82
70
  }
83
71
 
84
- .sonic-segmented-segment:where([data-sonic-pressed], :focus-visible:active):not(:disabled),
85
- .sonic-segmented-segment[aria-checked='true'] {
86
- --_sonic-segmented-shift: calc(var(--_sonic-segmented-depth) / 2);
87
- --_sonic-segmented-scale: var(--_sonic-segmented-press-scale);
88
- --_sonic-segmented-drop: calc(0.5 * var(--_sonic-cast-x)) calc(0.5 * var(--_sonic-cast-y))
89
- var(--_sonic-unit) var(--_sonic-drop-shade);
72
+ .sonic-segmented-option:where([data-sonic-pressed], :focus-visible:active):not(:disabled),
73
+ .sonic-segmented-option[aria-checked='true'] {
74
+ --_sonic-keycap-shift: calc(var(--_sonic-keycap-depth) / 2);
75
+ --_sonic-keycap-scale: var(--_sonic-segmented-press-scale);
76
+ --_sonic-keycap-drop: var(--_sonic-press-drop);
90
77
  }
91
78
 
92
- .sonic-segmented-segment[aria-checked='true'] {
93
- --_sonic-segmented-glow: color-mix(in oklab, var(--_sonic-lit) 22%, transparent);
79
+ .sonic-segmented-option[aria-checked='true'] {
80
+ --_sonic-keycap-glow: color-mix(in oklab, var(--_sonic-lit) 22%, transparent);
94
81
 
95
82
  color: var(--_sonic-lit);
96
83
  background: var(--_sonic-lit);
97
84
  box-shadow: var(--_sonic-well);
98
85
  }
99
86
 
100
- .sonic-segmented-segment:disabled {
87
+ .sonic-segmented-option:disabled {
101
88
  --_sonic-lit: var(--_sonic-lit-disabled);
102
89
 
103
90
  color: var(--_sonic-etch);
104
91
  cursor: default;
105
92
  }
106
93
 
107
- .sonic-segmented-segment:not([aria-checked='true'], :disabled):is(
94
+ .sonic-segmented-option:not([aria-checked='true'], :disabled):is(
108
95
  :focus-visible,
109
96
  :active,
110
97
  [data-sonic-pressed]
@@ -113,41 +100,23 @@
113
100
  }
114
101
 
115
102
  @media (hover: hover) {
116
- .sonic-segmented-segment:not([aria-checked='true'], :disabled):hover {
103
+ .sonic-segmented-option:not([aria-checked='true'], :disabled):hover {
117
104
  color: var(--_sonic-ink-lift);
118
105
  }
119
106
  }
120
107
 
121
- /* In flow, so a long label widens its segment rather than spilling over the next */
122
108
  .sonic-segmented-cap {
109
+ --_sonic-keycap-corner: var(--_sonic-segmented-inner-corner);
110
+ --_sonic-keycap-bevel: calc(var(--_sonic-segmented-size) * var(--_sonic-segmented-bevel-ratio));
111
+ --_sonic-keycap-face-corner: max(
112
+ 0px,
113
+ var(--_sonic-segmented-inner-corner) - var(--_sonic-keycap-bevel)
114
+ );
115
+
123
116
  position: relative;
124
- display: grid;
125
- place-items: center;
126
117
  padding-inline: calc(var(--_sonic-segmented-size) * 0.25);
127
- background: var(--_sonic-skirt);
128
- border-radius: var(--_sonic-segmented-inner-corner);
129
- box-shadow: var(--_sonic-segmented-drop), var(--_sonic-rim), var(--_sonic-focus-shadow);
130
- scale: var(--_sonic-segmented-scale);
131
- translate: 0 var(--_sonic-segmented-shift);
132
- transition: var(--_sonic-press-transition);
133
-
134
- &::before {
135
- position: absolute;
136
- inset: calc(var(--_sonic-segmented-size) * var(--_sonic-segmented-bevel-ratio));
137
- content: '';
138
- background:
139
- radial-gradient(closest-side, var(--_sonic-segmented-glow), transparent),
140
- var(--_sonic-sheen), var(--_sonic-face);
141
- border-radius: max(
142
- 0px,
143
- var(--_sonic-segmented-inner-corner) - var(--_sonic-segmented-size) *
144
- var(--_sonic-segmented-bevel-ratio)
145
- );
146
- box-shadow: var(--_sonic-face-shadow);
147
- }
148
118
 
149
119
  & > * {
150
- position: relative;
151
120
  filter: var(--_sonic-engraving);
152
121
  }
153
122
 
@@ -157,8 +126,7 @@
157
126
  }
158
127
  }
159
128
 
160
- /* Engraving under the glow keeps a lit label's edge */
161
- .sonic-segmented-segment[aria-checked='true'] .sonic-segmented-cap > * {
129
+ .sonic-segmented-option[aria-checked='true'] .sonic-segmented-cap > * {
162
130
  filter: var(--_sonic-engraving)
163
131
  drop-shadow(0 0 var(--_sonic-unit) color-mix(in oklab, var(--_sonic-lit) 35%, transparent));
164
132
  }
@@ -168,7 +136,7 @@
168
136
  filter: none;
169
137
  }
170
138
 
171
- .sonic-segmented-segment[aria-checked='true'] {
139
+ .sonic-segmented-option[aria-checked='true'] {
172
140
  --_sonic-skirt: var(--_sonic-lit);
173
141
  --_sonic-face: var(--_sonic-lit);
174
142
  --_sonic-ink: HighlightText;