@xsynaptic/sonic-ui 0.4.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 (240) 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 +16 -22
  13. package/dist/default/elements/envelope.js +367 -0
  14. package/dist/default/elements/meter.js +149 -61
  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 +42 -51
  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 +12 -3
  46. package/dist/default/lib/modifier-press.js +11 -0
  47. package/dist/default/lib/number-list.js +6 -6
  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 +23 -17
  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} +8 -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 +16 -22
  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 +10 -5
  100. package/dist/dev/elements/meter.js +149 -61
  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 +6 -6
  116. package/dist/dev/elements/slider.js +42 -51
  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 +12 -3
  180. package/dist/dev/lib/math.js.map +1 -1
  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 +6 -6
  184. package/dist/dev/lib/number-list.js.map +1 -1
  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 +23 -17
  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 +88 -42
  211. package/dist/styles/envelope.css +159 -0
  212. package/dist/styles/led.css +36 -5
  213. package/dist/styles/material.css +277 -76
  214. package/dist/styles/meter.css +33 -48
  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 +21 -48
  219. package/dist/styles/slider.css +175 -39
  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 -169
  227. package/dist/default/elements/range-element.js +0 -546
  228. package/dist/default/lib/detent.js +0 -17
  229. package/dist/dev/define/key.d.ts +0 -2
  230. package/dist/dev/define/key.js +0 -8
  231. package/dist/dev/define/key.js.map +0 -1
  232. package/dist/dev/elements/key.js +0 -170
  233. package/dist/dev/elements/key.js.map +0 -1
  234. package/dist/dev/elements/range-element.d.ts +0 -64
  235. package/dist/dev/elements/range-element.js +0 -547
  236. package/dist/dev/elements/range-element.js.map +0 -1
  237. package/dist/dev/elements/range-entry.js.map +0 -1
  238. package/dist/dev/lib/detent.js +0 -18
  239. package/dist/dev/lib/detent.js.map +0 -1
  240. package/dist/styles/key.css +0 -242
@@ -0,0 +1,115 @@
1
+ import { clamp, decimalPlaces, roundTo, trimFloat } from "./math.js";
2
+ import { nearestPosition } from "./number-list.js";
3
+ import { linearTaper, listTaper, logTaper, skewTaper } from "./taper.js";
4
+
5
+ //#region src/lib/value-mapping.ts
6
+ const resetKeys = /* @__PURE__ */ new Set(["Backspace", "Delete"]);
7
+ const keySteps = /* @__PURE__ */ new Map([
8
+ ["ArrowDown", -1],
9
+ ["ArrowLeft", -1],
10
+ ["ArrowRight", 1],
11
+ ["ArrowUp", 1],
12
+ ["PageDown", -10],
13
+ ["PageUp", 10]
14
+ ]);
15
+ function curveOf(spec, max) {
16
+ const { min, positions } = spec;
17
+ if (positions) return listTaper(positions);
18
+ if (spec.isNotched || spec.isWrapping) return void 0;
19
+ return (spec.taper === "log" ? logTaper(min, max) : void 0) ?? skewTaper(min, max, spec.midpoint ?? NaN);
20
+ }
21
+ function countPositions(spec, count) {
22
+ if (!spec.isNotched || !Number.isFinite(count) || count < 2) return;
23
+ return count;
24
+ }
25
+ function countSteps(spec, range) {
26
+ if (spec.step <= 0) return NaN;
27
+ const fit = trimFloat(range / spec.step);
28
+ return spec.isWrapping ? Math.max(1, Math.ceil(fit)) : Math.floor(fit) + 1;
29
+ }
30
+ function valueMapping(spec) {
31
+ const { min, positions, step } = spec;
32
+ const max = Math.max(min, spec.max);
33
+ const range = max - min;
34
+ const count = countSteps(spec, range);
35
+ const isStepped = step > 0 && !positions;
36
+ const curve = curveOf(spec, max);
37
+ const taper = curve ?? linearTaper(min, max);
38
+ function round(value) {
39
+ if (step <= 0) return trimFloat(value);
40
+ return roundTo(value, Math.max(decimalPlaces(step), decimalPlaces(min)));
41
+ }
42
+ const top = round((count - 1) * step);
43
+ function limits() {
44
+ if (positions) return [positions[0] ?? min, positions.at(-1) ?? max];
45
+ return [min, isStepped && !spec.isWrapping ? round(min + top) : max];
46
+ }
47
+ const bounds = limits();
48
+ function wrap(value, span) {
49
+ const offset = round(((value - min) % span + span) % span);
50
+ return offset >= span ? 0 : offset;
51
+ }
52
+ function bound(value) {
53
+ if (!spec.isWrapping) return clamp(value, ...bounds);
54
+ if (range <= 0) return min;
55
+ return round(min + wrap(value, range));
56
+ }
57
+ function ring(value, span) {
58
+ if (range <= 0) return min;
59
+ const offset = wrap(value, span);
60
+ if (offset > top) return span - offset <= offset - top ? min : round(min + top);
61
+ return round(min + Math.round(offset / step) * step);
62
+ }
63
+ function snap(value) {
64
+ if (positions) return nearestPosition(positions, value);
65
+ if (step <= 0) return bound(round(value));
66
+ if (spec.isWrapping) return ring(value, range);
67
+ return bound(round(min + Math.round((value - min) / step) * step));
68
+ }
69
+ function stepBy(from, steps, size) {
70
+ if (positions) {
71
+ const index = clamp(positions.indexOf(from) + steps, 0, positions.length - 1);
72
+ return positions[index] ?? from;
73
+ }
74
+ if (!curve) return from + steps * size;
75
+ const next = snap(curve.valueAt(curve.proportionOf(from) + steps / 100));
76
+ return next === from ? from + Math.sign(steps) * size : next;
77
+ }
78
+ function stopAtDetent(from, next) {
79
+ if (spec.detent === void 0) return next;
80
+ const detent = snap(spec.detent);
81
+ const toward = Math.sign(next - from) * (detent - from);
82
+ const ahead = spec.isWrapping ? wrap(min + toward, isStepped ? count * step : range) : toward;
83
+ return ahead > 0 && ahead < Math.abs(next - from) ? detent : next;
84
+ }
85
+ function keyStride(keyStep) {
86
+ if (positions || !(keyStep > 0)) return void 0;
87
+ return step > 0 ? Math.max(1, Math.round(trimFloat(keyStep / step))) * step : keyStep;
88
+ }
89
+ function end(size) {
90
+ if (!spec.isWrapping) return bounds[1];
91
+ return min + (isStepped ? top : (Math.ceil(range / size) - 1) * size);
92
+ }
93
+ function target(key, from, keyStep) {
94
+ if (key === "Home") return bounds[0];
95
+ const size = step > 0 ? step : range / 100;
96
+ if (key === "End") return snap(end(size));
97
+ const steps = keySteps.get(key);
98
+ if (steps === void 0) return void 0;
99
+ const stride = keyStride(keyStep);
100
+ const next = stopAtDetent(from, stride === void 0 ? stepBy(from, steps, size) : from + steps * stride);
101
+ return isStepped && spec.isWrapping ? ring(next, count * step) : snap(next);
102
+ }
103
+ return {
104
+ bounds,
105
+ isWrapping: spec.isWrapping,
106
+ keyTarget: (key, from, keyStep = 0) => target(key, from, keyStep),
107
+ positionCount: countPositions(spec, positions?.length ?? count),
108
+ proportionOf: (value) => taper.proportionOf(bound(value)),
109
+ snap,
110
+ valueAt: (proportion) => taper.valueAt(proportion)
111
+ };
112
+ }
113
+
114
+ //#endregion
115
+ export { resetKeys, valueMapping };
@@ -0,0 +1,41 @@
1
+ //#region src/lib/waveform-buckets.ts
2
+ function foldPairs(peaks, fromPair, toPair) {
3
+ const { samples } = peaks;
4
+ const channels = Math.max(1, peaks.channels ?? 1);
5
+ const stride = channels * 2;
6
+ const pairsTotal = Math.floor(samples.length / stride);
7
+ let low = 0;
8
+ let high = 0;
9
+ for (let pair = Math.max(0, fromPair); pair < Math.min(pairsTotal, toPair); pair += 1) for (let channel = 0; channel < channels; channel += 1) {
10
+ const at = pair * stride + channel * 2;
11
+ low = Math.min(low, samples[at] ?? 0);
12
+ high = Math.max(high, samples[at + 1] ?? 0);
13
+ }
14
+ return [low / peaks.fullScale, high / peaks.fullScale];
15
+ }
16
+ function waveformBuckets(peaks, view) {
17
+ const { pairsPerSecond } = peaks;
18
+ if (pairsPerSecond <= 0 || view.pixelsPerSecond <= 0) return [];
19
+ const pxPerPair = view.pixelsPerSecond / pairsPerSecond;
20
+ const pairs = Math.max(1, Math.round(1 / pxPerPair));
21
+ const openingPair = view.startSeconds * pairsPerSecond;
22
+ const first = Math.floor(openingPair / pairs) - 1;
23
+ const count = Math.ceil(view.width / (pairs * pxPerPair)) + 3;
24
+ const buckets = [];
25
+ for (let index = 0; index < count; index += 1) {
26
+ const fromPair = (first + index) * pairs;
27
+ const toPair = fromPair + pairs;
28
+ const [low, high] = foldPairs(peaks, fromPair, toPair);
29
+ buckets.push({
30
+ fromPair,
31
+ high,
32
+ low,
33
+ toPair,
34
+ x: (fromPair - openingPair) * pxPerPair
35
+ });
36
+ }
37
+ return buckets;
38
+ }
39
+
40
+ //#endregion
41
+ export { waveformBuckets };
@@ -0,0 +1,19 @@
1
+ import { WaveformPeaks } from "./lib/waveform-buckets.js";
2
+ //#region src/dat.d.ts
3
+ export interface DatHeader {
4
+ bits: 8 | 16;
5
+ channels: number;
6
+ dataOffset: number;
7
+ pairs: number;
8
+ pairsPerSecond: number;
9
+ sampleRate: number;
10
+ samplesPerPixel: number;
11
+ version: 1 | 2;
12
+ }
13
+ export declare function readDatHeader(buffer: ArrayBuffer): DatHeader;
14
+ export declare function datByteRange(header: DatHeader, fromPair: number, toPair: number): [number, number] | undefined;
15
+ export declare function readDatSamples(header: DatHeader, body: ArrayBuffer): Int8Array | Int16Array;
16
+ export declare function readDatPeaks(header: DatHeader, body: ArrayBuffer): WaveformPeaks;
17
+ //#endregion
18
+ export type { WaveformPeaks };
19
+ //# sourceMappingURL=dat.d.ts.map
@@ -0,0 +1,51 @@
1
+ import { clamp } from "./lib/math.js";
2
+
3
+ //#region src/dat.ts
4
+ function readVersion(view) {
5
+ const version = view.getInt32(0, true);
6
+ if (version === 1 || version === 2) return version;
7
+ throw new Error(`A .dat file of version ${String(version)} is not one this reads`);
8
+ }
9
+ function readDatHeader(buffer) {
10
+ if (buffer.byteLength < 20) throw new Error("A .dat header takes at least 20 bytes");
11
+ const view = new DataView(buffer);
12
+ const version = readVersion(view);
13
+ const dataOffset = version === 1 ? 20 : 24;
14
+ if (buffer.byteLength < dataOffset) throw new Error(`A version ${String(version)} .dat header takes ${String(dataOffset)} bytes`);
15
+ const channels = version === 1 ? 1 : view.getInt32(20, true);
16
+ if (channels < 1) throw new Error("A .dat header names no channels");
17
+ const sampleRate = view.getInt32(8, true);
18
+ const samplesPerPixel = view.getInt32(12, true);
19
+ return {
20
+ bits: (view.getUint32(4, true) & 1) === 1 ? 8 : 16,
21
+ channels,
22
+ dataOffset,
23
+ pairs: view.getUint32(16, true),
24
+ pairsPerSecond: sampleRate / samplesPerPixel,
25
+ sampleRate,
26
+ samplesPerPixel,
27
+ version
28
+ };
29
+ }
30
+ function datByteRange(header, fromPair, toPair) {
31
+ const from = clamp(Math.floor(fromPair), 0, header.pairs);
32
+ const to = clamp(Math.ceil(toPair), from, header.pairs);
33
+ if (!(to > from)) return void 0;
34
+ const pairBytes = header.channels * 2 * header.bits / 8;
35
+ return [header.dataOffset + from * pairBytes, header.dataOffset + to * pairBytes - 1];
36
+ }
37
+ function readDatSamples(header, body) {
38
+ return header.bits === 8 ? new Int8Array(body) : new Int16Array(body, 0, Math.floor(body.byteLength / 2));
39
+ }
40
+ function readDatPeaks(header, body) {
41
+ return {
42
+ channels: header.channels,
43
+ fullScale: header.bits === 8 ? 128 : 32768,
44
+ pairsPerSecond: header.pairsPerSecond,
45
+ samples: readDatSamples(header, body)
46
+ };
47
+ }
48
+
49
+ //#endregion
50
+ export { datByteRange, readDatHeader, readDatPeaks, readDatSamples };
51
+ //# sourceMappingURL=dat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dat.js","names":[],"sources":["../../src/dat.ts"],"sourcesContent":["import type { WaveformPeaks } from '#lib/waveform-buckets.ts';\n\nimport { clamp } from '#lib/math.ts';\n\nexport type { WaveformPeaks } from '#lib/waveform-buckets.ts';\n\nexport interface DatHeader {\n\tbits: 8 | 16;\n\tchannels: number;\n\tdataOffset: number;\n\tpairs: number;\n\tpairsPerSecond: number;\n\tsampleRate: number;\n\tsamplesPerPixel: number;\n\tversion: 1 | 2;\n}\n\nfunction readVersion(view: DataView): 1 | 2 {\n\tconst version = view.getInt32(0, true);\n\tif (version === 1 || version === 2) return version;\n\n\tthrow new Error(`A .dat file of version ${String(version)} is not one this reads`);\n}\n\nexport function readDatHeader(buffer: ArrayBuffer): DatHeader {\n\tif (buffer.byteLength < 20) throw new Error('A .dat header takes at least 20 bytes');\n\n\tconst view = new DataView(buffer);\n\tconst version = readVersion(view);\n\tconst dataOffset = version === 1 ? 20 : 24;\n\tif (buffer.byteLength < dataOffset) {\n\t\tthrow new Error(`A version ${String(version)} .dat header takes ${String(dataOffset)} bytes`);\n\t}\n\n\tconst channels = version === 1 ? 1 : view.getInt32(20, true);\n\tif (channels < 1) throw new Error('A .dat header names no channels');\n\n\tconst sampleRate = view.getInt32(8, true);\n\tconst samplesPerPixel = view.getInt32(12, true);\n\n\treturn {\n\t\tbits: (view.getUint32(4, true) & 1) === 1 ? 8 : 16,\n\t\tchannels,\n\t\tdataOffset,\n\t\tpairs: view.getUint32(16, true),\n\t\tpairsPerSecond: sampleRate / samplesPerPixel,\n\t\tsampleRate,\n\t\tsamplesPerPixel,\n\t\tversion,\n\t};\n}\n\nexport function datByteRange(\n\theader: DatHeader,\n\tfromPair: number,\n\ttoPair: number,\n): [number, number] | undefined {\n\tconst from = clamp(Math.floor(fromPair), 0, header.pairs);\n\tconst to = clamp(Math.ceil(toPair), from, header.pairs);\n\t// A server ignores an inverted `Range` and sends the whole file\n\tif (!(to > from)) return undefined;\n\n\tconst pairBytes = (header.channels * 2 * header.bits) / 8;\n\n\treturn [header.dataOffset + from * pairBytes, header.dataOffset + to * pairBytes - 1];\n}\n\n// Typed arrays read the platform's byte order; every browser platform is little-endian, as the format is\n// A range response can end mid-sample; the odd byte is dropped\nexport function readDatSamples(header: DatHeader, body: ArrayBuffer): Int8Array | Int16Array {\n\treturn header.bits === 8\n\t\t? new Int8Array(body)\n\t\t: new Int16Array(body, 0, Math.floor(body.byteLength / 2));\n}\n\nexport function readDatPeaks(header: DatHeader, body: ArrayBuffer): WaveformPeaks {\n\treturn {\n\t\tchannels: header.channels,\n\t\tfullScale: header.bits === 8 ? 128 : 32_768,\n\t\tpairsPerSecond: header.pairsPerSecond,\n\t\tsamples: readDatSamples(header, body),\n\t};\n}\n"],"mappings":";;;AAiBA,SAAS,YAAY,MAAuB;CAC3C,MAAM,UAAU,KAAK,SAAS,GAAG,IAAI;CACrC,IAAI,YAAY,KAAK,YAAY,GAAG,OAAO;CAE3C,MAAM,IAAI,MAAM,0BAA0B,OAAO,OAAO,EAAE,uBAAuB;AAClF;AAEA,SAAgB,cAAc,QAAgC;CAC7D,IAAI,OAAO,aAAa,IAAI,MAAM,IAAI,MAAM,uCAAuC;CAEnF,MAAM,OAAO,IAAI,SAAS,MAAM;CAChC,MAAM,UAAU,YAAY,IAAI;CAChC,MAAM,aAAa,YAAY,IAAI,KAAK;CACxC,IAAI,OAAO,aAAa,YACvB,MAAM,IAAI,MAAM,aAAa,OAAO,OAAO,EAAE,qBAAqB,OAAO,UAAU,EAAE,OAAO;CAG7F,MAAM,WAAW,YAAY,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI;CAC3D,IAAI,WAAW,GAAG,MAAM,IAAI,MAAM,iCAAiC;CAEnE,MAAM,aAAa,KAAK,SAAS,GAAG,IAAI;CACxC,MAAM,kBAAkB,KAAK,SAAS,IAAI,IAAI;CAE9C,OAAO;EACN,OAAO,KAAK,UAAU,GAAG,IAAI,IAAI,OAAO,IAAI,IAAI;EAChD;EACA;EACA,OAAO,KAAK,UAAU,IAAI,IAAI;EAC9B,gBAAgB,aAAa;EAC7B;EACA;EACA;CACD;AACD;AAEA,SAAgB,aACf,QACA,UACA,QAC+B;CAC/B,MAAM,OAAO,MAAM,KAAK,MAAM,QAAQ,GAAG,GAAG,OAAO,KAAK;CACxD,MAAM,KAAK,MAAM,KAAK,KAAK,MAAM,GAAG,MAAM,OAAO,KAAK;CAEtD,IAAI,EAAE,KAAK,OAAO,OAAO;CAEzB,MAAM,YAAa,OAAO,WAAW,IAAI,OAAO,OAAQ;CAExD,OAAO,CAAC,OAAO,aAAa,OAAO,WAAW,OAAO,aAAa,KAAK,YAAY,CAAC;AACrF;AAIA,SAAgB,eAAe,QAAmB,MAA2C;CAC5F,OAAO,OAAO,SAAS,IACpB,IAAI,UAAU,IAAI,IAClB,IAAI,WAAW,MAAM,GAAG,KAAK,MAAM,KAAK,aAAa,CAAC,CAAC;AAC3D;AAEA,SAAgB,aAAa,QAAmB,MAAkC;CACjF,OAAO;EACN,UAAU,OAAO;EACjB,WAAW,OAAO,SAAS,IAAI,MAAM;EACrC,gBAAgB,OAAO;EACvB,SAAS,eAAe,QAAQ,IAAI;CACrC;AACD"}
@@ -0,0 +1,2 @@
1
+ import { SonicButton } from "../elements/button.js";
2
+ export type { SonicButton };
@@ -0,0 +1,8 @@
1
+ import { defineOnce } from "../elements/define-once.js";
2
+ import { SonicButton } from "../elements/button.js";
3
+
4
+ //#region src/define/button.ts
5
+ defineOnce("sonic-button", SonicButton);
6
+
7
+ //#endregion
8
+ //# sourceMappingURL=button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button.js","names":[],"sources":["../../../src/define/button.ts"],"sourcesContent":["import { SonicButton } from '#elements/button.ts';\nimport { defineOnce } from '#elements/define-once.ts';\n\ndefineOnce('sonic-button', SonicButton);\n\nexport type { SonicButton } from '#elements/button.ts';\n"],"mappings":";;;;AAGA,WAAW,gBAAgB,WAAW"}
@@ -1 +1 @@
1
- {"version":3,"file":"dial.js","names":[],"sources":["../../../src/define/dial.ts"],"sourcesContent":["import { defineOnce } from '#elements/define-once.ts';\nimport { SonicDial } from '#elements/dial.ts';\n\ndefineOnce('sonic-dial', SonicDial);\n\n// Type-only, so the tag map augmentation ships without a runtime export\n/** @public */\nexport type { SonicDial } from '#elements/dial.ts';\n"],"mappings":";;;;AAGA,WAAW,cAAc,SAAS"}
1
+ {"version":3,"file":"dial.js","names":[],"sources":["../../../src/define/dial.ts"],"sourcesContent":["import { defineOnce } from '#elements/define-once.ts';\nimport { SonicDial } from '#elements/dial.ts';\n\ndefineOnce('sonic-dial', SonicDial);\n\nexport type { SonicDial } from '#elements/dial.ts';\n"],"mappings":";;;;AAGA,WAAW,cAAc,SAAS"}
@@ -0,0 +1,2 @@
1
+ import { SonicEnvelope } from "../elements/envelope.js";
2
+ export type { SonicEnvelope };
@@ -0,0 +1,8 @@
1
+ import { defineOnce } from "../elements/define-once.js";
2
+ import { SonicEnvelope } from "../elements/envelope.js";
3
+
4
+ //#region src/define/envelope.ts
5
+ defineOnce("sonic-envelope", SonicEnvelope);
6
+
7
+ //#endregion
8
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","names":[],"sources":["../../../src/define/envelope.ts"],"sourcesContent":["import { defineOnce } from '#elements/define-once.ts';\nimport { SonicEnvelope } from '#elements/envelope.ts';\n\ndefineOnce('sonic-envelope', SonicEnvelope);\n\nexport type { SonicEnvelope } from '#elements/envelope.ts';\n"],"mappings":";;;;AAGA,WAAW,kBAAkB,aAAa"}
@@ -1 +1 @@
1
- {"version":3,"file":"meter.js","names":[],"sources":["../../../src/define/meter.ts"],"sourcesContent":["import { defineOnce } from '#elements/define-once.ts';\nimport { SonicMeter } from '#elements/meter.ts';\n\ndefineOnce('sonic-meter', SonicMeter);\n\n// Type-only, so the tag map augmentation ships without a runtime export\n/** @public */\nexport type { SonicMeter } from '#elements/meter.ts';\n"],"mappings":";;;;AAGA,WAAW,eAAe,UAAU"}
1
+ {"version":3,"file":"meter.js","names":[],"sources":["../../../src/define/meter.ts"],"sourcesContent":["import { defineOnce } from '#elements/define-once.ts';\nimport { SonicMeter } from '#elements/meter.ts';\n\ndefineOnce('sonic-meter', SonicMeter);\n\nexport type { SonicMeter } from '#elements/meter.ts';\n"],"mappings":";;;;AAGA,WAAW,eAAe,UAAU"}
@@ -1 +1 @@
1
- {"version":3,"file":"number.js","names":[],"sources":["../../../src/define/number.ts"],"sourcesContent":["import { defineOnce } from '#elements/define-once.ts';\nimport { SonicNumber } from '#elements/number.ts';\n\ndefineOnce('sonic-number', SonicNumber);\n\n// Type-only, so the tag map augmentation ships without a runtime export\n/** @public */\nexport type { SonicNumber } from '#elements/number.ts';\n"],"mappings":";;;;AAGA,WAAW,gBAAgB,WAAW"}
1
+ {"version":3,"file":"number.js","names":[],"sources":["../../../src/define/number.ts"],"sourcesContent":["import { defineOnce } from '#elements/define-once.ts';\nimport { SonicNumber } from '#elements/number.ts';\n\ndefineOnce('sonic-number', SonicNumber);\n\nexport type { SonicNumber } from '#elements/number.ts';\n"],"mappings":";;;;AAGA,WAAW,gBAAgB,WAAW"}
@@ -1 +1 @@
1
- {"version":3,"file":"segmented.js","names":[],"sources":["../../../src/define/segmented.ts"],"sourcesContent":["import { defineOnce } from '#elements/define-once.ts';\nimport { SonicSegmented } from '#elements/segmented.ts';\n\ndefineOnce('sonic-segmented', SonicSegmented);\n\n// Type-only, so the tag map augmentation ships without a runtime export\n/** @public */\nexport type { SonicSegmented } from '#elements/segmented.ts';\n"],"mappings":";;;;AAGA,WAAW,mBAAmB,cAAc"}
1
+ {"version":3,"file":"segmented.js","names":[],"sources":["../../../src/define/segmented.ts"],"sourcesContent":["import { defineOnce } from '#elements/define-once.ts';\nimport { SonicSegmented } from '#elements/segmented.ts';\n\ndefineOnce('sonic-segmented', SonicSegmented);\n\nexport type { SonicSegmented } from '#elements/segmented.ts';\n"],"mappings":";;;;AAGA,WAAW,mBAAmB,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"slider.js","names":[],"sources":["../../../src/define/slider.ts"],"sourcesContent":["import { defineOnce } from '#elements/define-once.ts';\nimport { SonicSlider } from '#elements/slider.ts';\n\ndefineOnce('sonic-slider', SonicSlider);\n\n// Type-only, so the tag map augmentation ships without a runtime export\n/** @public */\nexport type { SonicSlider } from '#elements/slider.ts';\n"],"mappings":";;;;AAGA,WAAW,gBAAgB,WAAW"}
1
+ {"version":3,"file":"slider.js","names":[],"sources":["../../../src/define/slider.ts"],"sourcesContent":["import { defineOnce } from '#elements/define-once.ts';\nimport { SonicSlider } from '#elements/slider.ts';\n\ndefineOnce('sonic-slider', SonicSlider);\n\nexport type { SonicSlider } from '#elements/slider.ts';\n"],"mappings":";;;;AAGA,WAAW,gBAAgB,WAAW"}
@@ -0,0 +1,2 @@
1
+ import { SonicSplit } from "../elements/split.js";
2
+ export type { SonicSplit };
@@ -0,0 +1,8 @@
1
+ import { defineOnce } from "../elements/define-once.js";
2
+ import { SonicSplit } from "../elements/split.js";
3
+
4
+ //#region src/define/split.ts
5
+ defineOnce("sonic-split", SonicSplit);
6
+
7
+ //#endregion
8
+ //# sourceMappingURL=split.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"split.js","names":[],"sources":["../../../src/define/split.ts"],"sourcesContent":["import { defineOnce } from '#elements/define-once.ts';\nimport { SonicSplit } from '#elements/split.ts';\n\ndefineOnce('sonic-split', SonicSplit);\n\nexport type { SonicSplit } from '#elements/split.ts';\n"],"mappings":";;;;AAGA,WAAW,eAAe,UAAU"}
@@ -0,0 +1,2 @@
1
+ import { SonicSwitch } from "../elements/switch.js";
2
+ export type { SonicSwitch };
@@ -0,0 +1,8 @@
1
+ import { defineOnce } from "../elements/define-once.js";
2
+ import { SonicSwitch } from "../elements/switch.js";
3
+
4
+ //#region src/define/switch.ts
5
+ defineOnce("sonic-switch", SonicSwitch);
6
+
7
+ //#endregion
8
+ //# sourceMappingURL=switch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switch.js","names":[],"sources":["../../../src/define/switch.ts"],"sourcesContent":["import { defineOnce } from '#elements/define-once.ts';\nimport { SonicSwitch } from '#elements/switch.ts';\n\ndefineOnce('sonic-switch', SonicSwitch);\n\nexport type { SonicSwitch } from '#elements/switch.ts';\n"],"mappings":";;;;AAGA,WAAW,gBAAgB,WAAW"}
@@ -0,0 +1,2 @@
1
+ import { SonicWaveform } from "../elements/waveform.js";
2
+ export type { SonicWaveform };
@@ -0,0 +1,8 @@
1
+ import { defineOnce } from "../elements/define-once.js";
2
+ import { SonicWaveform } from "../elements/waveform.js";
3
+
4
+ //#region src/define/waveform.ts
5
+ defineOnce("sonic-waveform", SonicWaveform);
6
+
7
+ //#endregion
8
+ //# sourceMappingURL=waveform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waveform.js","names":[],"sources":["../../../src/define/waveform.ts"],"sourcesContent":["import { defineOnce } from '#elements/define-once.ts';\nimport { SonicWaveform } from '#elements/waveform.ts';\n\ndefineOnce('sonic-waveform', SonicWaveform);\n\nexport type { SonicWaveform } from '#elements/waveform.ts';\n"],"mappings":";;;;AAGA,WAAW,kBAAkB,aAAa"}
@@ -0,0 +1,2 @@
1
+ import { SonicWavestrip } from "../elements/wavestrip.js";
2
+ export type { SonicWavestrip };
@@ -0,0 +1,8 @@
1
+ import { defineOnce } from "../elements/define-once.js";
2
+ import { SonicWavestrip } from "../elements/wavestrip.js";
3
+
4
+ //#region src/define/wavestrip.ts
5
+ defineOnce("sonic-wavestrip", SonicWavestrip);
6
+
7
+ //#endregion
8
+ //# sourceMappingURL=wavestrip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wavestrip.js","names":[],"sources":["../../../src/define/wavestrip.ts"],"sourcesContent":["import { defineOnce } from '#elements/define-once.ts';\nimport { SonicWavestrip } from '#elements/wavestrip.ts';\n\ndefineOnce('sonic-wavestrip', SonicWavestrip);\n\nexport type { SonicWavestrip } from '#elements/wavestrip.ts';\n"],"mappings":";;;;AAGA,WAAW,mBAAmB,cAAc"}
@@ -0,0 +1,2 @@
1
+ import { SonicXy } from "../elements/xy.js";
2
+ export type { SonicXy };
@@ -0,0 +1,8 @@
1
+ import { defineOnce } from "../elements/define-once.js";
2
+ import { SonicXy } from "../elements/xy.js";
3
+
4
+ //#region src/define/xy.ts
5
+ defineOnce("sonic-xy", SonicXy);
6
+
7
+ //#endregion
8
+ //# sourceMappingURL=xy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xy.js","names":[],"sources":["../../../src/define/xy.ts"],"sourcesContent":["import { defineOnce } from '#elements/define-once.ts';\nimport { SonicXy } from '#elements/xy.ts';\n\ndefineOnce('sonic-xy', SonicXy);\n\nexport type { SonicXy } from '#elements/xy.ts';\n"],"mappings":";;;;AAGA,WAAW,YAAY,OAAO"}
@@ -1,7 +1,11 @@
1
1
  import { SonicDial } from "./elements/dial.js";
2
2
  import "./define/dial.js";
3
- import { SonicKey } from "./elements/key.js";
4
- import "./define/key.js";
3
+ import { SonicEnvelope } from "./elements/envelope.js";
4
+ import "./define/envelope.js";
5
+ import { SonicButton } from "./elements/button.js";
6
+ import "./define/button.js";
7
+ import { SonicSwitch } from "./elements/switch.js";
8
+ import "./define/switch.js";
5
9
  import { SonicMeter } from "./elements/meter.js";
6
10
  import "./define/meter.js";
7
11
  import { SonicNumber } from "./elements/number.js";
@@ -10,4 +14,12 @@ import { SonicSegmented } from "./elements/segmented.js";
10
14
  import "./define/segmented.js";
11
15
  import { SonicSlider } from "./elements/slider.js";
12
16
  import "./define/slider.js";
13
- export type { SonicDial, SonicKey, SonicMeter, SonicNumber, SonicSegmented, SonicSlider };
17
+ import { SonicSplit } from "./elements/split.js";
18
+ import "./define/split.js";
19
+ import { SonicWaveform } from "./elements/waveform.js";
20
+ import "./define/waveform.js";
21
+ import { SonicWavestrip } from "./elements/wavestrip.js";
22
+ import "./define/wavestrip.js";
23
+ import { SonicXy } from "./elements/xy.js";
24
+ import "./define/xy.js";
25
+ export type { SonicButton, SonicDial, SonicEnvelope, SonicMeter, SonicNumber, SonicSegmented, SonicSlider, SonicSplit, SonicSwitch, SonicWaveform, SonicWavestrip, SonicXy };
@@ -1,6 +1,12 @@
1
1
  import "./define/dial.js";
2
- import "./define/key.js";
2
+ import "./define/envelope.js";
3
+ import "./define/button.js";
4
+ import "./define/switch.js";
3
5
  import "./define/meter.js";
4
6
  import "./define/number.js";
5
7
  import "./define/segmented.js";
6
8
  import "./define/slider.js";
9
+ import "./define/split.js";
10
+ import "./define/waveform.js";
11
+ import "./define/wavestrip.js";
12
+ import "./define/xy.js";
@@ -1,25 +1,27 @@
1
1
  import { SonicFormElement } from "./form-element.js";
2
- //#region src/elements/key.d.ts
2
+ //#region src/elements/button.d.ts
3
3
  declare global {
4
4
  interface HTMLElementTagNameMap {
5
- 'sonic-key': SonicKey;
5
+ 'sonic-button': SonicButton;
6
6
  }
7
7
  }
8
- export declare class SonicKey extends SonicFormElement {
8
+ export declare class SonicButton extends SonicFormElement {
9
9
  #private;
10
10
  static readonly observedAttributes: string[];
11
+ get armed(): boolean;
12
+ set armed(isArmed: boolean);
11
13
  get busy(): boolean;
12
14
  set busy(isBusy: boolean);
13
15
  get defaultPressed(): boolean;
14
16
  set defaultPressed(isPressed: boolean);
17
+ get latching(): boolean;
18
+ set latching(isLatching: boolean);
15
19
  get momentary(): boolean;
16
20
  set momentary(isMomentary: boolean);
17
21
  get pressed(): boolean;
18
22
  set pressed(isPressed: boolean | undefined);
19
23
  get softDisabled(): boolean;
20
24
  set softDisabled(isSoftDisabled: boolean);
21
- get toggle(): boolean;
22
- set toggle(isToggle: boolean);
23
25
  get value(): string;
24
26
  set value(value: string | undefined);
25
27
  attributeChangedCallback(name: string): void;
@@ -31,4 +33,4 @@ export declare class SonicKey extends SonicFormElement {
31
33
  protected restoreState(state: string): void;
32
34
  }
33
35
  //#endregion
34
- //# sourceMappingURL=key.d.ts.map
36
+ //# sourceMappingURL=button.d.ts.map
@@ -0,0 +1,166 @@
1
+ import { placeChildren, requireChild, template } from "../lib/render.js";
2
+ import { writeAttribute } from "../lib/write-attribute.js";
3
+ import { SonicFormElement } from "./form-element.js";
4
+ import { copyNode } from "../lib/copy-node.js";
5
+ import { bindHold } from "../lib/hold.js";
6
+
7
+ //#region src/elements/button.ts
8
+ const renderButton = template(`
9
+ <button class="sonic-button" type="button"><span class="sonic-button-cap"></span></button>
10
+ `, HTMLButtonElement);
11
+ const holdKeys = /* @__PURE__ */ new Set([" ", "Enter"]);
12
+ var SonicButton = class extends SonicFormElement {
13
+ static observedAttributes = [
14
+ ...SonicFormElement.observedAttributes,
15
+ "busy",
16
+ "momentary",
17
+ "pressed",
18
+ "soft-disabled",
19
+ "latching",
20
+ "value"
21
+ ];
22
+ get armed() {
23
+ return this.hasAttribute("armed");
24
+ }
25
+ set armed(isArmed) {
26
+ this.reflect("armed", isArmed);
27
+ }
28
+ get busy() {
29
+ return this.hasAttribute("busy");
30
+ }
31
+ set busy(isBusy) {
32
+ this.reflect("busy", isBusy);
33
+ }
34
+ get defaultPressed() {
35
+ return this.hasAttribute("pressed");
36
+ }
37
+ set defaultPressed(isPressed) {
38
+ this.reflect("pressed", isPressed);
39
+ }
40
+ get latching() {
41
+ return this.hasAttribute("latching");
42
+ }
43
+ set latching(isLatching) {
44
+ this.reflect("latching", isLatching);
45
+ }
46
+ get momentary() {
47
+ return this.hasAttribute("momentary");
48
+ }
49
+ set momentary(isMomentary) {
50
+ this.reflect("momentary", isMomentary);
51
+ }
52
+ get pressed() {
53
+ return this.#isDirty ? this.#pressed : this.defaultPressed;
54
+ }
55
+ set pressed(isPressed) {
56
+ this.#isDirty = true;
57
+ this.#pressed = isPressed === true;
58
+ this.render();
59
+ }
60
+ get softDisabled() {
61
+ return this.hasAttribute("soft-disabled");
62
+ }
63
+ set softDisabled(isSoftDisabled) {
64
+ this.reflect("soft-disabled", isSoftDisabled);
65
+ }
66
+ get value() {
67
+ return this.getAttribute("value") ?? "on";
68
+ }
69
+ set value(value) {
70
+ this.reflect("value", value);
71
+ }
72
+ #button = renderButton();
73
+ #holding;
74
+ #isDirty = false;
75
+ #pressed = false;
76
+ attributeChangedCallback(name) {
77
+ if (name === "pressed") this.#isDirty = false;
78
+ if (this.isDisabled() || this.#isSoftDisabled()) this.#holding?.release();
79
+ this.render();
80
+ }
81
+ formResetCallback() {
82
+ this.attributeChangedCallback("pressed");
83
+ }
84
+ activate() {
85
+ this.#button.click();
86
+ }
87
+ connect(signal) {
88
+ const button = this.#button;
89
+ const cap = requireChild(button, ".sonic-button-cap", HTMLSpanElement);
90
+ this.upgradeProperties("armed", "busy", "defaultPressed", "momentary", "softDisabled", "latching", "pressed", "value");
91
+ this.mirrorChildren({
92
+ control: button,
93
+ copy: copyNode,
94
+ place: (copies) => {
95
+ placeChildren(cap, copies);
96
+ }
97
+ }, signal);
98
+ this.render();
99
+ this.checkStyles(button, "button.css");
100
+ button.addEventListener("click", (event) => {
101
+ if (this.#isSoftDisabled()) {
102
+ event.preventDefault();
103
+ event.stopImmediatePropagation();
104
+ return;
105
+ }
106
+ if (!this.latching) return;
107
+ this.pressed = !this.pressed;
108
+ this.dispatchEvent(new Event("change", { bubbles: true }));
109
+ }, { signal });
110
+ this.#bindMomentary(button, signal);
111
+ }
112
+ focusTarget() {
113
+ return this.#button;
114
+ }
115
+ render() {
116
+ const button = this.#button;
117
+ button.disabled = this.isDisabled();
118
+ writeAttribute(button, "aria-disabled", this.#isSoftDisabled() ? "true" : void 0);
119
+ writeAttribute(button, "aria-busy", this.busy ? "true" : void 0);
120
+ button.removeAttribute("aria-pressed");
121
+ if (this.latching) button.setAttribute("aria-pressed", String(this.pressed));
122
+ this.toggleState("pressed", this.pressed);
123
+ this.forwardNaming(button, true);
124
+ const submitted = this.latching && this.pressed ? this.value : null;
125
+ this.writeFormValue(submitted, String(this.pressed));
126
+ }
127
+ restoreState(state) {
128
+ if (this.latching) this.pressed = state === "true";
129
+ }
130
+ #bindMomentary(button, signal) {
131
+ const holding = bindHold(button, {
132
+ canHold: () => !this.isDisabled() && !this.#isSoftDisabled(),
133
+ leave: "blur",
134
+ onHold: () => {
135
+ this.#press(true);
136
+ },
137
+ onRelease: () => {
138
+ this.#press(false);
139
+ }
140
+ }, signal);
141
+ this.#holding = holding;
142
+ button.addEventListener("pointerdown", (event) => {
143
+ if (event.button !== 0 || !this.#isMomentary()) return;
144
+ button.setPointerCapture(event.pointerId);
145
+ holding.hold(event.pointerId);
146
+ }, { signal });
147
+ button.addEventListener("keydown", (event) => {
148
+ if (event.repeat || !holdKeys.has(event.key) || !this.#isMomentary()) return;
149
+ holding.hold(event.key);
150
+ }, { signal });
151
+ }
152
+ #isMomentary() {
153
+ return this.momentary && !this.latching;
154
+ }
155
+ #isSoftDisabled() {
156
+ return this.softDisabled && !this.isDisabled();
157
+ }
158
+ #press(isPressed) {
159
+ this.pressed = isPressed;
160
+ this.dispatchEvent(new Event("change", { bubbles: true }));
161
+ }
162
+ };
163
+
164
+ //#endregion
165
+ export { SonicButton };
166
+ //# sourceMappingURL=button.js.map