@xsynaptic/sonic-ui 0.4.0 → 0.6.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 (247) hide show
  1. package/README.md +3 -20
  2. package/dist/default/dat.js +51 -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 +383 -0
  14. package/dist/default/elements/meter.js +155 -63
  15. package/dist/default/elements/number.js +22 -9
  16. package/dist/default/elements/radio-group.js +183 -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 +69 -31
  22. package/dist/default/elements/split.js +249 -0
  23. package/dist/default/elements/switch.js +273 -0
  24. package/dist/default/elements/value-element.js +694 -0
  25. package/dist/default/elements/{range-entry.js → value-entry.js} +3 -3
  26. package/dist/default/elements/wave-element.js +80 -0
  27. package/dist/default/elements/waveform.js +328 -0
  28. package/dist/default/elements/wavestrip.js +185 -0
  29. package/dist/default/elements/xy.js +487 -0
  30. package/dist/default/index.js +10 -2
  31. package/dist/default/lib/adsr-shape.js +113 -0
  32. package/dist/default/lib/ballistics.js +55 -0
  33. package/dist/default/lib/canvas-surface.js +203 -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 +63 -0
  42. package/dist/default/lib/hold.js +38 -0
  43. package/dist/default/lib/marker-band.js +80 -0
  44. package/dist/default/lib/marker-rider.js +120 -0
  45. package/dist/default/lib/math.js +17 -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 +46 -0
  49. package/dist/default/lib/render.js +20 -5
  50. package/dist/default/lib/resample-peaks.js +46 -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/default/lib/write-attribute.js +1 -0
  58. package/dist/dev/dat.d.ts +19 -0
  59. package/dist/dev/dat.js +52 -0
  60. package/dist/dev/dat.js.map +1 -0
  61. package/dist/dev/define/button.d.ts +2 -0
  62. package/dist/dev/define/button.js +8 -0
  63. package/dist/dev/define/button.js.map +1 -0
  64. package/dist/dev/define/dial.js.map +1 -1
  65. package/dist/dev/define/envelope.d.ts +2 -0
  66. package/dist/dev/define/envelope.js +8 -0
  67. package/dist/dev/define/envelope.js.map +1 -0
  68. package/dist/dev/define/meter.js.map +1 -1
  69. package/dist/dev/define/number.js.map +1 -1
  70. package/dist/dev/define/segmented.js.map +1 -1
  71. package/dist/dev/define/slider.js.map +1 -1
  72. package/dist/dev/define/split.d.ts +2 -0
  73. package/dist/dev/define/split.js +8 -0
  74. package/dist/dev/define/split.js.map +1 -0
  75. package/dist/dev/define/switch.d.ts +2 -0
  76. package/dist/dev/define/switch.js +8 -0
  77. package/dist/dev/define/switch.js.map +1 -0
  78. package/dist/dev/define/waveform.d.ts +2 -0
  79. package/dist/dev/define/waveform.js +8 -0
  80. package/dist/dev/define/waveform.js.map +1 -0
  81. package/dist/dev/define/wavestrip.d.ts +2 -0
  82. package/dist/dev/define/wavestrip.js +8 -0
  83. package/dist/dev/define/wavestrip.js.map +1 -0
  84. package/dist/dev/define/xy.d.ts +2 -0
  85. package/dist/dev/define/xy.js +8 -0
  86. package/dist/dev/define/xy.js.map +1 -0
  87. package/dist/dev/define.d.ts +15 -3
  88. package/dist/dev/define.js +7 -1
  89. package/dist/dev/elements/{key.d.ts → button.d.ts} +8 -6
  90. package/dist/dev/elements/button.js +166 -0
  91. package/dist/dev/elements/button.js.map +1 -0
  92. package/dist/dev/elements/dial.d.ts +6 -4
  93. package/dist/dev/elements/dial.js +16 -22
  94. package/dist/dev/elements/dial.js.map +1 -1
  95. package/dist/dev/elements/envelope.d.ts +36 -0
  96. package/dist/dev/elements/envelope.js +388 -0
  97. package/dist/dev/elements/envelope.js.map +1 -0
  98. package/dist/dev/elements/form-element.d.ts +1 -1
  99. package/dist/dev/elements/form-element.js.map +1 -1
  100. package/dist/dev/elements/meter.d.ts +11 -6
  101. package/dist/dev/elements/meter.js +155 -63
  102. package/dist/dev/elements/meter.js.map +1 -1
  103. package/dist/dev/elements/number.d.ts +7 -3
  104. package/dist/dev/elements/number.js +22 -9
  105. package/dist/dev/elements/number.js.map +1 -1
  106. package/dist/dev/elements/radio-group.d.ts +25 -0
  107. package/dist/dev/elements/radio-group.js +184 -0
  108. package/dist/dev/elements/radio-group.js.map +1 -0
  109. package/dist/dev/elements/readout-claim.js +82 -0
  110. package/dist/dev/elements/readout-claim.js.map +1 -0
  111. package/dist/dev/elements/readout.js +36 -0
  112. package/dist/dev/elements/readout.js.map +1 -0
  113. package/dist/dev/elements/segmented.d.ts +4 -10
  114. package/dist/dev/elements/segmented.js +9 -159
  115. package/dist/dev/elements/segmented.js.map +1 -1
  116. package/dist/dev/elements/slider.d.ts +6 -6
  117. package/dist/dev/elements/slider.js +42 -51
  118. package/dist/dev/elements/slider.js.map +1 -1
  119. package/dist/dev/elements/sonic-element.d.ts +6 -3
  120. package/dist/dev/elements/sonic-element.js +119 -40
  121. package/dist/dev/elements/sonic-element.js.map +1 -1
  122. package/dist/dev/elements/split.d.ts +21 -0
  123. package/dist/dev/elements/split.js +258 -0
  124. package/dist/dev/elements/split.js.map +1 -0
  125. package/dist/dev/elements/switch.d.ts +35 -0
  126. package/dist/dev/elements/switch.js +274 -0
  127. package/dist/dev/elements/switch.js.map +1 -0
  128. package/dist/dev/elements/value-element.d.ts +84 -0
  129. package/dist/dev/elements/value-element.js +695 -0
  130. package/dist/dev/elements/value-element.js.map +1 -0
  131. package/dist/dev/elements/{range-entry.js → value-entry.js} +4 -4
  132. package/dist/dev/elements/value-entry.js.map +1 -0
  133. package/dist/dev/elements/wave-element.d.ts +37 -0
  134. package/dist/dev/elements/wave-element.js +81 -0
  135. package/dist/dev/elements/wave-element.js.map +1 -0
  136. package/dist/dev/elements/waveform.d.ts +55 -0
  137. package/dist/dev/elements/waveform.js +329 -0
  138. package/dist/dev/elements/waveform.js.map +1 -0
  139. package/dist/dev/elements/wavestrip.d.ts +51 -0
  140. package/dist/dev/elements/wavestrip.js +186 -0
  141. package/dist/dev/elements/wavestrip.js.map +1 -0
  142. package/dist/dev/elements/xy.d.ts +62 -0
  143. package/dist/dev/elements/xy.js +488 -0
  144. package/dist/dev/elements/xy.js.map +1 -0
  145. package/dist/dev/index.d.ts +11 -2
  146. package/dist/dev/index.js +10 -2
  147. package/dist/dev/lib/adsr-shape.js +114 -0
  148. package/dist/dev/lib/adsr-shape.js.map +1 -0
  149. package/dist/dev/lib/ballistics.js +56 -0
  150. package/dist/dev/lib/ballistics.js.map +1 -0
  151. package/dist/dev/lib/canvas-surface.d.ts +26 -0
  152. package/dist/dev/lib/canvas-surface.js +204 -0
  153. package/dist/dev/lib/canvas-surface.js.map +1 -0
  154. package/dist/dev/lib/copy-node.js +32 -2
  155. package/dist/dev/lib/copy-node.js.map +1 -1
  156. package/dist/dev/lib/crossfade.d.ts +12 -0
  157. package/dist/dev/lib/crossfade.js +23 -0
  158. package/dist/dev/lib/crossfade.js.map +1 -0
  159. package/dist/dev/lib/distribute.d.ts +4 -0
  160. package/dist/dev/lib/distribute.js +216 -0
  161. package/dist/dev/lib/distribute.js.map +1 -0
  162. package/dist/dev/lib/drag-step.js +100 -0
  163. package/dist/dev/lib/drag-step.js.map +1 -0
  164. package/dist/dev/lib/envelope-curve.d.ts +4 -0
  165. package/dist/dev/lib/envelope-curve.js +10 -0
  166. package/dist/dev/lib/envelope-curve.js.map +1 -0
  167. package/dist/dev/lib/field.d.ts +4 -0
  168. package/dist/dev/lib/field.js +95 -0
  169. package/dist/dev/lib/field.js.map +1 -0
  170. package/dist/dev/lib/focus-by-pointer.js +29 -0
  171. package/dist/dev/lib/focus-by-pointer.js.map +1 -0
  172. package/dist/dev/lib/frame-timeline.js +64 -0
  173. package/dist/dev/lib/frame-timeline.js.map +1 -0
  174. package/dist/dev/lib/hold.js +39 -0
  175. package/dist/dev/lib/hold.js.map +1 -0
  176. package/dist/dev/lib/marker-band.js +81 -0
  177. package/dist/dev/lib/marker-band.js.map +1 -0
  178. package/dist/dev/lib/marker-rider.js +121 -0
  179. package/dist/dev/lib/marker-rider.js.map +1 -0
  180. package/dist/dev/lib/math.js +17 -3
  181. package/dist/dev/lib/math.js.map +1 -1
  182. package/dist/dev/lib/modifier-press.js +12 -0
  183. package/dist/dev/lib/modifier-press.js.map +1 -0
  184. package/dist/dev/lib/number-list.js +6 -6
  185. package/dist/dev/lib/number-list.js.map +1 -1
  186. package/dist/dev/lib/pointer-drag.js +47 -0
  187. package/dist/dev/lib/pointer-drag.js.map +1 -0
  188. package/dist/dev/lib/read-px-property.js.map +1 -1
  189. package/dist/dev/lib/render.js +20 -5
  190. package/dist/dev/lib/render.js.map +1 -1
  191. package/dist/dev/lib/resample-peaks.js +47 -0
  192. package/dist/dev/lib/resample-peaks.js.map +1 -0
  193. package/dist/dev/lib/strip-scene.js +49 -0
  194. package/dist/dev/lib/strip-scene.js.map +1 -0
  195. package/dist/dev/lib/taper.js +23 -17
  196. package/dist/dev/lib/taper.js.map +1 -1
  197. package/dist/dev/lib/time-regions.d.ts +4 -0
  198. package/dist/dev/lib/time-regions.js +9 -0
  199. package/dist/dev/lib/time-regions.js.map +1 -0
  200. package/dist/dev/lib/tracking-clock.js +36 -0
  201. package/dist/dev/lib/tracking-clock.js.map +1 -0
  202. package/dist/dev/lib/value-mapping.d.ts +23 -0
  203. package/dist/dev/lib/value-mapping.js +116 -0
  204. package/dist/dev/lib/value-mapping.js.map +1 -0
  205. package/dist/dev/lib/waveform-buckets.d.ts +9 -0
  206. package/dist/dev/lib/waveform-buckets.js +42 -0
  207. package/dist/dev/lib/waveform-buckets.js.map +1 -0
  208. package/dist/dev/lib/write-attribute.js +1 -0
  209. package/dist/dev/lib/write-attribute.js.map +1 -1
  210. package/dist/skins/amber.css +8 -0
  211. package/dist/skins/flat.css +25 -0
  212. package/dist/skins/ivory.css +2 -2
  213. package/dist/skins/lime.css +2 -0
  214. package/dist/skins/slate.css +2 -0
  215. package/dist/styles/button.css +240 -0
  216. package/dist/styles/controls.css +8 -1
  217. package/dist/styles/dial.css +110 -56
  218. package/dist/styles/envelope.css +204 -0
  219. package/dist/styles/led.css +39 -8
  220. package/dist/styles/material.css +343 -100
  221. package/dist/styles/meter.css +41 -52
  222. package/dist/styles/number.css +5 -1
  223. package/dist/styles/panel.css +61 -0
  224. package/dist/styles/ring.css +74 -0
  225. package/dist/styles/segmented.css +46 -51
  226. package/dist/styles/slider.css +177 -40
  227. package/dist/styles/switch.css +386 -0
  228. package/dist/styles/waveform.css +196 -0
  229. package/dist/styles/wavestrip.css +232 -0
  230. package/dist/styles/xy.css +241 -0
  231. package/package.json +15 -6
  232. package/dist/default/define/key.js +0 -7
  233. package/dist/default/elements/key.js +0 -169
  234. package/dist/default/elements/range-element.js +0 -546
  235. package/dist/default/lib/detent.js +0 -17
  236. package/dist/dev/define/key.d.ts +0 -2
  237. package/dist/dev/define/key.js +0 -8
  238. package/dist/dev/define/key.js.map +0 -1
  239. package/dist/dev/elements/key.js +0 -170
  240. package/dist/dev/elements/key.js.map +0 -1
  241. package/dist/dev/elements/range-element.d.ts +0 -64
  242. package/dist/dev/elements/range-element.js +0 -547
  243. package/dist/dev/elements/range-element.js.map +0 -1
  244. package/dist/dev/elements/range-entry.js.map +0 -1
  245. package/dist/dev/lib/detent.js +0 -18
  246. package/dist/dev/lib/detent.js.map +0 -1
  247. package/dist/styles/key.css +0 -242
package/README.md CHANGED
@@ -1,11 +1,9 @@
1
1
  # @xsynaptic/sonic-ui
2
2
 
3
- Native custom elements for audio interfaces. Each control renders in the light DOM, drawn in CSS, skinned with `--sonic-*` custom properties. No framework, no runtime dependencies.
3
+ Native custom elements for audio interfaces. Each control renders in the light DOM, skinned with `--sonic-*` tokens (CSS custom properties). No framework, no runtime dependencies.
4
4
 
5
5
  Early and unstable: any 0.x release may break the API.
6
6
 
7
- ## Setup
8
-
9
7
  ```sh
10
8
  pnpm add @xsynaptic/sonic-ui
11
9
  ```
@@ -23,23 +21,8 @@ import '@xsynaptic/sonic-ui/define';
23
21
 
24
22
  ```html
25
23
  <sonic-dial aria-label="Cutoff" value="40"></sonic-dial>
26
- <sonic-slider aria-label="Send" value="30"></sonic-slider>
27
- <sonic-key aria-label="Mute" toggle>…</sonic-key>
28
24
  ```
29
25
 
30
- The styles sit in `@layer sonic`, so list it after your resets. A skin (`slate`, `lime` or `ivory`) applies under `.sonic-skin-<name>` on any ancestor. The package root exports the classes without registering them, for your own tag names.
31
-
32
- ## Usage
33
-
34
- - **Attributes and properties** reflect each other: `dial.max = 200` writes `max="200"`. `value` and the key's `pressed` are the live state and never write their attribute, as on native inputs.
35
- - **Events:** `change` when a control settles, and `input` while a dial or slider moves; both bubble.
36
- - **Formatting:** `formatValue` sets the text the readout and assistive technology read, and `parseValue` reads typed entry back. `formatPercent` and `parsePercent` from the package root show 0 to 1 as a percentage.
37
- - **Forms:** controls that hold a value submit under their `name`, reset, take a `<label>`, and follow a disabled `<fieldset>`, as native inputs do.
38
-
39
- ## Browsers
40
-
41
- Current Chrome and Edge, Safari 26 and Firefox 147.
42
-
43
- ## License
26
+ Under a hydrating framework, register the definitions once hydration is done (in React, from an effect); a control owns one child of its host and uses only the children it documents.
44
27
 
45
- MIT
28
+ Targets current Chrome and Edge, Safari 26 and Firefox 147. MIT licensed.
@@ -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
+ if (samplesPerPixel < 1) throw new Error("A .dat header names no samples per pixel");
20
+ return {
21
+ bits: (view.getUint32(4, true) & 1) === 1 ? 8 : 16,
22
+ channels,
23
+ dataOffset,
24
+ pairs: view.getUint32(16, true),
25
+ pairsPerSecond: sampleRate / samplesPerPixel,
26
+ sampleRate,
27
+ samplesPerPixel,
28
+ version
29
+ };
30
+ }
31
+ function datByteRange(header, fromPair, toPair) {
32
+ const from = clamp(Math.floor(fromPair), 0, header.pairs);
33
+ const to = clamp(Math.ceil(toPair), from, header.pairs);
34
+ if (!(to > from)) return void 0;
35
+ const pairBytes = header.channels * 2 * header.bits / 8;
36
+ return [header.dataOffset + from * pairBytes, header.dataOffset + to * pairBytes - 1];
37
+ }
38
+ function readDatSamples(header, body, byteOffset = 0) {
39
+ return header.bits === 8 ? new Int8Array(body, byteOffset) : new Int16Array(body, byteOffset, Math.floor((body.byteLength - byteOffset) / 2));
40
+ }
41
+ function readDatPeaks(header, body, byteOffset = 0) {
42
+ return {
43
+ channels: header.channels,
44
+ fullScale: header.bits === 8 ? 128 : 32768,
45
+ pairsPerSecond: header.pairsPerSecond,
46
+ samples: readDatSamples(header, body, byteOffset)
47
+ };
48
+ }
49
+
50
+ //#endregion
51
+ export { datByteRange, readDatHeader, readDatPeaks, readDatSamples };
@@ -0,0 +1,7 @@
1
+ import { SonicButton } from "../elements/button.js";
2
+ import { defineOnce } from "../elements/define-once.js";
3
+
4
+ //#region src/define/button.ts
5
+ defineOnce("sonic-button", SonicButton);
6
+
7
+ //#endregion
@@ -0,0 +1,7 @@
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
@@ -0,0 +1,7 @@
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
@@ -0,0 +1,7 @@
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
@@ -0,0 +1,7 @@
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
@@ -0,0 +1,7 @@
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
@@ -0,0 +1,7 @@
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
@@ -1,6 +1,12 @@
1
+ import "./define/button.js";
1
2
  import "./define/dial.js";
2
- import "./define/key.js";
3
+ import "./define/envelope.js";
3
4
  import "./define/meter.js";
4
5
  import "./define/number.js";
5
6
  import "./define/segmented.js";
6
7
  import "./define/slider.js";
8
+ import "./define/split.js";
9
+ import "./define/switch.js";
10
+ import "./define/waveform.js";
11
+ import "./define/wavestrip.js";
12
+ import "./define/xy.js";
@@ -0,0 +1,165 @@
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
+ if (!this.isBound()) return;
117
+ const button = this.#button;
118
+ writeAttribute(button, "disabled", this.isDisabled() ? "" : void 0);
119
+ writeAttribute(button, "aria-disabled", this.#isSoftDisabled() ? "true" : void 0);
120
+ writeAttribute(button, "aria-busy", this.busy ? "true" : void 0);
121
+ writeAttribute(button, "aria-pressed", this.latching ? String(this.pressed) : void 0);
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 };
@@ -1,6 +1,5 @@
1
1
  import { requireChild, template } from "../lib/render.js";
2
- import { readPxProperty } from "../lib/read-px-property.js";
3
- import { SonicRangeElement } from "./range-element.js";
2
+ import { SonicValueElement } from "./value-element.js";
4
3
 
5
4
  //#region src/elements/dial.ts
6
5
  const renderDial = template(`
@@ -10,7 +9,7 @@ const renderDial = template(`
10
9
  <div class="sonic-dial-ring"></div>
11
10
  <div class="sonic-dial-modulation"></div>
12
11
  <div class="sonic-dial-cap"></div>
13
- <div class="sonic-dial-pointer"></div>
12
+ <div class="sonic-dial-indicator"></div>
14
13
  <div class="sonic-dial-readout" popover="manual">
15
14
  <span></span>
16
15
  <input
@@ -24,10 +23,9 @@ const renderDial = template(`
24
23
  </div>
25
24
  </div>
26
25
  `, HTMLDivElement);
27
- const fallbackTravelPx = 160;
28
- var SonicDial = class extends SonicRangeElement {
26
+ var SonicDial = class extends SonicValueElement {
29
27
  static observedAttributes = [
30
- ...SonicRangeElement.observedAttributes,
28
+ ...SonicValueElement.observedAttributes,
31
29
  "endless",
32
30
  "modulation"
33
31
  ];
@@ -43,9 +41,15 @@ var SonicDial = class extends SonicRangeElement {
43
41
  set modulation(amount) {
44
42
  this.reflect("modulation", amount);
45
43
  }
44
+ get modulationValue() {
45
+ return this.readModulationValue();
46
+ }
47
+ set modulationValue(value) {
48
+ this.writeModulationValue(this.#dial, "dial", value);
49
+ }
46
50
  #dial = renderDial();
47
51
  connectedCallback() {
48
- this.upgradeProperties("endless", "modulation");
52
+ this.upgradeProperties("endless", "modulationValue", "modulation");
49
53
  super.connectedCallback();
50
54
  }
51
55
  connect(signal) {
@@ -55,26 +59,16 @@ var SonicDial = class extends SonicRangeElement {
55
59
  this.checkStyles(dial, "dial.css");
56
60
  this.bindGestures(dial, signal, () => ({
57
61
  position: (event) => -event.clientY,
58
- travelPx: readPxProperty(getComputedStyle(dial), "--_sonic-dial-travel", fallbackTravelPx)
62
+ travelPx: this.travelPx(dial, "--_sonic-dial-travel")
59
63
  }));
60
64
  }
65
+ draw() {
66
+ this.writeProportions(this.#dial, "dial", this.endless ? 0 : this.modulation);
67
+ }
61
68
  focusTarget() {
62
69
  return this.#dial;
63
70
  }
64
- render() {
65
- const dial = this.#dial;
66
- const positions = this.positions();
67
- const [modulationFrom, modulationTo] = this.modulationFractions(this.endless ? 0 : this.modulation);
68
- dial.style.setProperty("--_sonic-dial-value", String(this.fraction(this.value)));
69
- dial.style.setProperty("--_sonic-dial-origin", String(this.originFraction()));
70
- dial.style.setProperty("--_sonic-dial-modulation-from", String(modulationFrom));
71
- dial.style.setProperty("--_sonic-dial-modulation-to", String(modulationTo));
72
- if (positions === void 0) dial.style.removeProperty("--_sonic-dial-positions");
73
- else dial.style.setProperty("--_sonic-dial-positions", String(positions));
74
- this.renderScale();
75
- this.renderAria(dial);
76
- }
77
- wraps() {
71
+ isWrapping() {
78
72
  return this.endless;
79
73
  }
80
74
  };