@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button.js","names":[],"sources":["../../../src/elements/button.ts"],"sourcesContent":["import type { Hold } from '#lib/hold.ts';\n\nimport { SonicFormElement } from '#elements/form-element.ts';\nimport { copyNode } from '#lib/copy-node.ts';\nimport { bindHold } from '#lib/hold.ts';\nimport { placeChildren, requireChild, template } from '#lib/render.ts';\nimport { writeAttribute } from '#lib/write-attribute.ts';\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sonic-button': SonicButton;\n\t}\n}\n\nconst renderButton = template(\n\t/* HTML */ `\n\t\t<button class=\"sonic-button\" type=\"button\"><span class=\"sonic-button-cap\"></span></button>\n\t`,\n\tHTMLButtonElement,\n);\n\nconst holdKeys = new Set([' ', 'Enter']);\n\nexport class SonicButton extends SonicFormElement {\n\tstatic override readonly observedAttributes = [\n\t\t...SonicFormElement.observedAttributes,\n\t\t'busy',\n\t\t'momentary',\n\t\t'pressed',\n\t\t'soft-disabled',\n\t\t'latching',\n\t\t'value',\n\t];\n\n\tget armed(): boolean {\n\t\treturn this.hasAttribute('armed');\n\t}\n\n\tset armed(isArmed: boolean) {\n\t\tthis.reflect('armed', isArmed);\n\t}\n\n\tget busy(): boolean {\n\t\treturn this.hasAttribute('busy');\n\t}\n\n\tset busy(isBusy: boolean) {\n\t\tthis.reflect('busy', isBusy);\n\t}\n\n\tget defaultPressed(): boolean {\n\t\treturn this.hasAttribute('pressed');\n\t}\n\n\tset defaultPressed(isPressed: boolean) {\n\t\tthis.reflect('pressed', isPressed);\n\t}\n\n\tget latching(): boolean {\n\t\treturn this.hasAttribute('latching');\n\t}\n\n\tset latching(isLatching: boolean) {\n\t\tthis.reflect('latching', isLatching);\n\t}\n\n\tget momentary(): boolean {\n\t\treturn this.hasAttribute('momentary');\n\t}\n\n\tset momentary(isMomentary: boolean) {\n\t\tthis.reflect('momentary', isMomentary);\n\t}\n\n\tget pressed(): boolean {\n\t\treturn this.#isDirty ? this.#pressed : this.defaultPressed;\n\t}\n\n\tset pressed(isPressed: boolean | undefined) {\n\t\tthis.#isDirty = true;\n\t\tthis.#pressed = isPressed === true;\n\t\tthis.render();\n\t}\n\n\tget softDisabled(): boolean {\n\t\treturn this.hasAttribute('soft-disabled');\n\t}\n\n\tset softDisabled(isSoftDisabled: boolean) {\n\t\tthis.reflect('soft-disabled', isSoftDisabled);\n\t}\n\n\tget value(): string {\n\t\treturn this.getAttribute('value') ?? 'on';\n\t}\n\n\tset value(value: string | undefined) {\n\t\tthis.reflect('value', value);\n\t}\n\n\treadonly #button = renderButton();\n\n\t#holding: Hold | undefined;\n\n\t#isDirty = false;\n\n\t#pressed = false;\n\n\tattributeChangedCallback(name: string): void {\n\t\tif (name === 'pressed') this.#isDirty = false;\n\t\tif (this.isDisabled() || this.#isSoftDisabled()) this.#holding?.release();\n\t\tthis.render();\n\t}\n\n\toverride formResetCallback(): void {\n\t\tthis.attributeChangedCallback('pressed');\n\t}\n\n\tprotected override activate(): void {\n\t\tthis.#button.click();\n\t}\n\n\tprotected connect(signal: AbortSignal): void {\n\t\tconst button = this.#button;\n\t\tconst cap = requireChild(button, '.sonic-button-cap', HTMLSpanElement);\n\n\t\tthis.upgradeProperties(\n\t\t\t'armed',\n\t\t\t'busy',\n\t\t\t'defaultPressed',\n\t\t\t'momentary',\n\t\t\t'softDisabled',\n\t\t\t'latching',\n\t\t\t'pressed',\n\t\t\t'value',\n\t\t);\n\t\tthis.mirrorChildren(\n\t\t\t{\n\t\t\t\tcontrol: button,\n\t\t\t\tcopy: copyNode,\n\t\t\t\tplace: (copies) => {\n\t\t\t\t\tplaceChildren(cap, copies);\n\t\t\t\t},\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t\tthis.render();\n\t\tthis.checkStyles(button, 'button.css');\n\n\t\tbutton.addEventListener(\n\t\t\t'click',\n\t\t\t(event) => {\n\t\t\t\t// A native disabled button fires no click at all\n\t\t\t\tif (this.#isSoftDisabled()) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!this.latching) return;\n\n\t\t\t\tthis.pressed = !this.pressed;\n\t\t\t\tthis.dispatchEvent(new Event('change', { bubbles: true }));\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tthis.#bindMomentary(button, signal);\n\t}\n\n\tprotected override focusTarget(): HTMLElement {\n\t\treturn this.#button;\n\t}\n\n\tprotected render(): void {\n\t\tconst button = this.#button;\n\n\t\tbutton.disabled = this.isDisabled();\n\t\twriteAttribute(button, 'aria-disabled', this.#isSoftDisabled() ? 'true' : undefined);\n\t\twriteAttribute(button, 'aria-busy', this.busy ? 'true' : undefined);\n\t\tbutton.removeAttribute('aria-pressed');\n\t\tif (this.latching) button.setAttribute('aria-pressed', String(this.pressed));\n\t\tthis.toggleState('pressed', this.pressed);\n\t\tthis.forwardNaming(button, true);\n\n\t\t// eslint-disable-next-line unicorn/no-null -- `null` submits nothing\n\t\tconst submitted = this.latching && this.pressed ? this.value : null;\n\n\t\tthis.writeFormValue(submitted, String(this.pressed));\n\t}\n\n\tprotected restoreState(state: string): void {\n\t\tif (this.latching) this.pressed = state === 'true';\n\t}\n\n\t#bindMomentary(button: HTMLButtonElement, signal: AbortSignal): void {\n\t\tconst holding = bindHold(\n\t\t\tbutton,\n\t\t\t{\n\t\t\t\tcanHold: () => !this.isDisabled() && !this.#isSoftDisabled(),\n\t\t\t\tleave: 'blur',\n\t\t\t\tonHold: () => {\n\t\t\t\t\tthis.#press(true);\n\t\t\t\t},\n\t\t\t\tonRelease: () => {\n\t\t\t\t\tthis.#press(false);\n\t\t\t\t},\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\n\t\tthis.#holding = holding;\n\t\tbutton.addEventListener(\n\t\t\t'pointerdown',\n\t\t\t(event) => {\n\t\t\t\tif (event.button !== 0 || !this.#isMomentary()) return;\n\n\t\t\t\tbutton.setPointerCapture(event.pointerId);\n\t\t\t\tholding.hold(event.pointerId);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tbutton.addEventListener(\n\t\t\t'keydown',\n\t\t\t(event) => {\n\t\t\t\tif (event.repeat || !holdKeys.has(event.key) || !this.#isMomentary()) return;\n\n\t\t\t\tholding.hold(event.key);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t}\n\n\t#isMomentary(): boolean {\n\t\treturn this.momentary && !this.latching;\n\t}\n\n\t#isSoftDisabled(): boolean {\n\t\treturn this.softDisabled && !this.isDisabled();\n\t}\n\n\t#press(isPressed: boolean): void {\n\t\tthis.pressed = isPressed;\n\t\tthis.dispatchEvent(new Event('change', { bubbles: true }));\n\t}\n}\n"],"mappings":";;;;;;;AAcA,MAAM,eAAe,SACT;;IAGX,iBACD;AAEA,MAAM,2BAAW,IAAI,IAAI,CAAC,KAAK,OAAO,CAAC;AAEvC,IAAa,cAAb,cAAiC,iBAAiB;CACjD,OAAyB,qBAAqB;EAC7C,GAAG,iBAAiB;EACpB;EACA;EACA;EACA;EACA;EACA;CACD;CAEA,IAAI,QAAiB;EACpB,OAAO,KAAK,aAAa,OAAO;CACjC;CAEA,IAAI,MAAM,SAAkB;EAC3B,KAAK,QAAQ,SAAS,OAAO;CAC9B;CAEA,IAAI,OAAgB;EACnB,OAAO,KAAK,aAAa,MAAM;CAChC;CAEA,IAAI,KAAK,QAAiB;EACzB,KAAK,QAAQ,QAAQ,MAAM;CAC5B;CAEA,IAAI,iBAA0B;EAC7B,OAAO,KAAK,aAAa,SAAS;CACnC;CAEA,IAAI,eAAe,WAAoB;EACtC,KAAK,QAAQ,WAAW,SAAS;CAClC;CAEA,IAAI,WAAoB;EACvB,OAAO,KAAK,aAAa,UAAU;CACpC;CAEA,IAAI,SAAS,YAAqB;EACjC,KAAK,QAAQ,YAAY,UAAU;CACpC;CAEA,IAAI,YAAqB;EACxB,OAAO,KAAK,aAAa,WAAW;CACrC;CAEA,IAAI,UAAU,aAAsB;EACnC,KAAK,QAAQ,aAAa,WAAW;CACtC;CAEA,IAAI,UAAmB;EACtB,OAAO,KAAK,WAAW,KAAK,WAAW,KAAK;CAC7C;CAEA,IAAI,QAAQ,WAAgC;EAC3C,KAAK,WAAW;EAChB,KAAK,WAAW,cAAc;EAC9B,KAAK,OAAO;CACb;CAEA,IAAI,eAAwB;EAC3B,OAAO,KAAK,aAAa,eAAe;CACzC;CAEA,IAAI,aAAa,gBAAyB;EACzC,KAAK,QAAQ,iBAAiB,cAAc;CAC7C;CAEA,IAAI,QAAgB;EACnB,OAAO,KAAK,aAAa,OAAO,KAAK;CACtC;CAEA,IAAI,MAAM,OAA2B;EACpC,KAAK,QAAQ,SAAS,KAAK;CAC5B;CAEA,AAAS,UAAU,aAAa;CAEhC;CAEA,WAAW;CAEX,WAAW;CAEX,yBAAyB,MAAoB;EAC5C,IAAI,SAAS,WAAW,KAAK,WAAW;EACxC,IAAI,KAAK,WAAW,KAAK,KAAK,gBAAgB,GAAG,KAAK,UAAU,QAAQ;EACxE,KAAK,OAAO;CACb;CAEA,AAAS,oBAA0B;EAClC,KAAK,yBAAyB,SAAS;CACxC;CAEA,AAAmB,WAAiB;EACnC,KAAK,QAAQ,MAAM;CACpB;CAEA,AAAU,QAAQ,QAA2B;EAC5C,MAAM,SAAS,KAAK;EACpB,MAAM,MAAM,aAAa,QAAQ,qBAAqB,eAAe;EAErE,KAAK,kBACJ,SACA,QACA,kBACA,aACA,gBACA,YACA,WACA,OACD;EACA,KAAK,eACJ;GACC,SAAS;GACT,MAAM;GACN,QAAQ,WAAW;IAClB,cAAc,KAAK,MAAM;GAC1B;EACD,GACA,MACD;EACA,KAAK,OAAO;EACZ,KAAK,YAAY,QAAQ,YAAY;EAErC,OAAO,iBACN,UACC,UAAU;GAEV,IAAI,KAAK,gBAAgB,GAAG;IAC3B,MAAM,eAAe;IACrB,MAAM,yBAAyB;IAC/B;GACD;GACA,IAAI,CAAC,KAAK,UAAU;GAEpB,KAAK,UAAU,CAAC,KAAK;GACrB,KAAK,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;EAC1D,GACA,EAAE,OAAO,CACV;EACA,KAAK,eAAe,QAAQ,MAAM;CACnC;CAEA,AAAmB,cAA2B;EAC7C,OAAO,KAAK;CACb;CAEA,AAAU,SAAe;EACxB,MAAM,SAAS,KAAK;EAEpB,OAAO,WAAW,KAAK,WAAW;EAClC,eAAe,QAAQ,iBAAiB,KAAK,gBAAgB,IAAI,SAAS,MAAS;EACnF,eAAe,QAAQ,aAAa,KAAK,OAAO,SAAS,MAAS;EAClE,OAAO,gBAAgB,cAAc;EACrC,IAAI,KAAK,UAAU,OAAO,aAAa,gBAAgB,OAAO,KAAK,OAAO,CAAC;EAC3E,KAAK,YAAY,WAAW,KAAK,OAAO;EACxC,KAAK,cAAc,QAAQ,IAAI;EAG/B,MAAM,YAAY,KAAK,YAAY,KAAK,UAAU,KAAK,QAAQ;EAE/D,KAAK,eAAe,WAAW,OAAO,KAAK,OAAO,CAAC;CACpD;CAEA,AAAU,aAAa,OAAqB;EAC3C,IAAI,KAAK,UAAU,KAAK,UAAU,UAAU;CAC7C;CAEA,eAAe,QAA2B,QAA2B;EACpE,MAAM,UAAU,SACf,QACA;GACC,eAAe,CAAC,KAAK,WAAW,KAAK,CAAC,KAAK,gBAAgB;GAC3D,OAAO;GACP,cAAc;IACb,KAAK,OAAO,IAAI;GACjB;GACA,iBAAiB;IAChB,KAAK,OAAO,KAAK;GAClB;EACD,GACA,MACD;EAEA,KAAK,WAAW;EAChB,OAAO,iBACN,gBACC,UAAU;GACV,IAAI,MAAM,WAAW,KAAK,CAAC,KAAK,aAAa,GAAG;GAEhD,OAAO,kBAAkB,MAAM,SAAS;GACxC,QAAQ,KAAK,MAAM,SAAS;EAC7B,GACA,EAAE,OAAO,CACV;EACA,OAAO,iBACN,YACC,UAAU;GACV,IAAI,MAAM,UAAU,CAAC,SAAS,IAAI,MAAM,GAAG,KAAK,CAAC,KAAK,aAAa,GAAG;GAEtE,QAAQ,KAAK,MAAM,GAAG;EACvB,GACA,EAAE,OAAO,CACV;CACD;CAEA,eAAwB;EACvB,OAAO,KAAK,aAAa,CAAC,KAAK;CAChC;CAEA,kBAA2B;EAC1B,OAAO,KAAK,gBAAgB,CAAC,KAAK,WAAW;CAC9C;CAEA,OAAO,WAA0B;EAChC,KAAK,UAAU;EACf,KAAK,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;CAC1D;AACD"}
@@ -1,22 +1,24 @@
1
- import { SonicRangeElement } from "./range-element.js";
1
+ import { SonicValueElement } from "./value-element.js";
2
2
  //#region src/elements/dial.d.ts
3
3
  declare global {
4
4
  interface HTMLElementTagNameMap {
5
5
  'sonic-dial': SonicDial;
6
6
  }
7
7
  }
8
- export declare class SonicDial extends SonicRangeElement {
8
+ export declare class SonicDial extends SonicValueElement {
9
9
  #private;
10
10
  static readonly observedAttributes: string[];
11
11
  get endless(): boolean;
12
12
  set endless(isEndless: boolean);
13
13
  get modulation(): number;
14
14
  set modulation(amount: number | undefined);
15
+ get modulationValue(): number | undefined;
16
+ set modulationValue(value: number | undefined);
15
17
  connectedCallback(): void;
16
18
  protected connect(signal: AbortSignal): void;
19
+ protected draw(): void;
17
20
  protected focusTarget(): HTMLElement;
18
- protected render(): void;
19
- protected wraps(): boolean;
21
+ protected isWrapping(): boolean;
20
22
  }
21
23
  //#endregion
22
24
  //# sourceMappingURL=dial.d.ts.map
@@ -1,15 +1,15 @@
1
- import { template } from "../lib/render.js";
2
- import { SonicRangeElement } from "./range-element.js";
3
- import { readPxProperty } from "../lib/read-px-property.js";
1
+ import { requireChild, template } from "../lib/render.js";
2
+ import { SonicValueElement } from "./value-element.js";
4
3
 
5
4
  //#region src/elements/dial.ts
6
5
  const renderDial = template(`
7
6
  <div class="sonic-dial" role="slider" tabindex="0">
7
+ <div class="sonic-dial-scale" aria-hidden="true"></div>
8
8
  <div class="sonic-dial-notches"></div>
9
9
  <div class="sonic-dial-ring"></div>
10
10
  <div class="sonic-dial-modulation"></div>
11
11
  <div class="sonic-dial-cap"></div>
12
- <div class="sonic-dial-pointer"></div>
12
+ <div class="sonic-dial-indicator"></div>
13
13
  <div class="sonic-dial-readout" popover="manual">
14
14
  <span></span>
15
15
  <input
@@ -23,10 +23,9 @@ const renderDial = template(`
23
23
  </div>
24
24
  </div>
25
25
  `, HTMLDivElement);
26
- const fallbackTravelPx = 160;
27
- var SonicDial = class extends SonicRangeElement {
26
+ var SonicDial = class extends SonicValueElement {
28
27
  static observedAttributes = [
29
- ...SonicRangeElement.observedAttributes,
28
+ ...SonicValueElement.observedAttributes,
30
29
  "endless",
31
30
  "modulation"
32
31
  ];
@@ -42,37 +41,34 @@ var SonicDial = class extends SonicRangeElement {
42
41
  set modulation(amount) {
43
42
  this.reflect("modulation", amount);
44
43
  }
44
+ get modulationValue() {
45
+ return this.readModulationValue();
46
+ }
47
+ set modulationValue(value) {
48
+ this.writeModulationValue(this.#dial, "dial", value);
49
+ }
45
50
  #dial = renderDial();
46
51
  connectedCallback() {
47
- this.upgradeProperties("endless", "modulation");
52
+ this.upgradeProperties("endless", "modulationValue", "modulation");
48
53
  super.connectedCallback();
49
54
  }
50
55
  connect(signal) {
51
56
  const dial = this.#dial;
52
- this.appendOnce(dial);
57
+ this.bindScale(dial, requireChild(dial, ".sonic-dial-scale", HTMLDivElement), signal);
53
58
  this.render();
54
59
  this.checkStyles(dial, "dial.css");
55
60
  this.bindGestures(dial, signal, () => ({
56
61
  position: (event) => -event.clientY,
57
- travelPx: readPxProperty(getComputedStyle(dial), "--_sonic-dial-travel", fallbackTravelPx)
62
+ travelPx: this.travelPx(dial, "--_sonic-dial-travel")
58
63
  }));
59
64
  }
65
+ draw() {
66
+ this.writeProportions(this.#dial, "dial", this.endless ? 0 : this.modulation);
67
+ }
60
68
  focusTarget() {
61
69
  return this.#dial;
62
70
  }
63
- render() {
64
- const dial = this.#dial;
65
- const positions = this.positions();
66
- const [modulationFrom, modulationTo] = this.modulationFractions(this.endless ? 0 : this.modulation);
67
- dial.style.setProperty("--_sonic-dial-value", String(this.fraction(this.value)));
68
- dial.style.setProperty("--_sonic-dial-origin", String(this.originFraction()));
69
- dial.style.setProperty("--_sonic-dial-modulation-from", String(modulationFrom));
70
- dial.style.setProperty("--_sonic-dial-modulation-to", String(modulationTo));
71
- if (positions === void 0) dial.style.removeProperty("--_sonic-dial-positions");
72
- else dial.style.setProperty("--_sonic-dial-positions", String(positions));
73
- this.renderAria(dial);
74
- }
75
- wraps() {
71
+ isWrapping() {
76
72
  return this.endless;
77
73
  }
78
74
  };
@@ -1 +1 @@
1
- {"version":3,"file":"dial.js","names":[],"sources":["../../../src/elements/dial.ts"],"sourcesContent":["import { SonicRangeElement } from '#elements/range-element.ts';\nimport { readPxProperty } from '#lib/read-px-property.ts';\nimport { template } from '#lib/render.ts';\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sonic-dial': SonicDial;\n\t}\n}\n\nconst renderDial = template(\n\t/* HTML */ `\n\t\t<div class=\"sonic-dial\" role=\"slider\" tabindex=\"0\">\n\t\t\t<div class=\"sonic-dial-notches\"></div>\n\t\t\t<div class=\"sonic-dial-ring\"></div>\n\t\t\t<div class=\"sonic-dial-modulation\"></div>\n\t\t\t<div class=\"sonic-dial-cap\"></div>\n\t\t\t<div class=\"sonic-dial-pointer\"></div>\n\t\t\t<div class=\"sonic-dial-readout\" popover=\"manual\">\n\t\t\t\t<span></span>\n\t\t\t\t<input\n\t\t\t\t\tautocomplete=\"off\"\n\t\t\t\t\tclass=\"sonic-dial-entry\"\n\t\t\t\t\tenterkeyhint=\"done\"\n\t\t\t\t\thidden\n\t\t\t\t\tspellcheck=\"false\"\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</div>\n\t`,\n\tHTMLDivElement,\n);\n\nconst fallbackTravelPx = 160;\n\nexport class SonicDial extends SonicRangeElement {\n\tstatic override readonly observedAttributes = [\n\t\t...SonicRangeElement.observedAttributes,\n\t\t'endless',\n\t\t'modulation',\n\t];\n\n\tget endless(): boolean {\n\t\treturn this.hasAttribute('endless');\n\t}\n\n\tset endless(isEndless: boolean) {\n\t\tthis.reflect('endless', isEndless);\n\t}\n\n\tget modulation(): number {\n\t\treturn this.numberAttribute('modulation', 0);\n\t}\n\n\tset modulation(amount: number | undefined) {\n\t\tthis.reflect('modulation', amount);\n\t}\n\n\treadonly #dial = renderDial();\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties('endless', 'modulation');\n\t\tsuper.connectedCallback();\n\t}\n\n\tprotected connect(signal: AbortSignal): void {\n\t\tconst dial = this.#dial;\n\n\t\tthis.appendOnce(dial);\n\t\tthis.render();\n\t\tthis.checkStyles(dial, 'dial.css');\n\t\tthis.bindGestures(dial, signal, () => ({\n\t\t\tposition: (event) => -event.clientY,\n\t\t\t// Once per gesture; a computed style read per move forces a style recalc\n\t\t\ttravelPx: readPxProperty(getComputedStyle(dial), '--_sonic-dial-travel', fallbackTravelPx),\n\t\t}));\n\t}\n\n\tprotected override focusTarget(): HTMLElement {\n\t\treturn this.#dial;\n\t}\n\n\tprotected render(): void {\n\t\tconst dial = this.#dial;\n\t\tconst positions = this.positions();\n\t\tconst [modulationFrom, modulationTo] = this.modulationFractions(\n\t\t\tthis.endless ? 0 : this.modulation,\n\t\t);\n\n\t\tdial.style.setProperty('--_sonic-dial-value', String(this.fraction(this.value)));\n\t\tdial.style.setProperty('--_sonic-dial-origin', String(this.originFraction()));\n\t\tdial.style.setProperty('--_sonic-dial-modulation-from', String(modulationFrom));\n\t\tdial.style.setProperty('--_sonic-dial-modulation-to', String(modulationTo));\n\t\tif (positions === undefined) dial.style.removeProperty('--_sonic-dial-positions');\n\t\telse dial.style.setProperty('--_sonic-dial-positions', String(positions));\n\t\tthis.renderAria(dial);\n\t}\n\n\tprotected override wraps(): boolean {\n\t\treturn this.endless;\n\t}\n}\n"],"mappings":";;;;;AAUA,MAAM,aAAa,SACP;;;;;;;;;;;;;;;;;;;IAoBX,cACD;AAEA,MAAM,mBAAmB;AAEzB,IAAa,YAAb,cAA+B,kBAAkB;CAChD,OAAyB,qBAAqB;EAC7C,GAAG,kBAAkB;EACrB;EACA;CACD;CAEA,IAAI,UAAmB;EACtB,OAAO,KAAK,aAAa,SAAS;CACnC;CAEA,IAAI,QAAQ,WAAoB;EAC/B,KAAK,QAAQ,WAAW,SAAS;CAClC;CAEA,IAAI,aAAqB;EACxB,OAAO,KAAK,gBAAgB,cAAc,CAAC;CAC5C;CAEA,IAAI,WAAW,QAA4B;EAC1C,KAAK,QAAQ,cAAc,MAAM;CAClC;CAEA,AAAS,QAAQ,WAAW;CAE5B,AAAS,oBAA0B;EAClC,KAAK,kBAAkB,WAAW,YAAY;EAC9C,MAAM,kBAAkB;CACzB;CAEA,AAAU,QAAQ,QAA2B;EAC5C,MAAM,OAAO,KAAK;EAElB,KAAK,WAAW,IAAI;EACpB,KAAK,OAAO;EACZ,KAAK,YAAY,MAAM,UAAU;EACjC,KAAK,aAAa,MAAM,eAAe;GACtC,WAAW,UAAU,CAAC,MAAM;GAE5B,UAAU,eAAe,iBAAiB,IAAI,GAAG,wBAAwB,gBAAgB;EAC1F,EAAE;CACH;CAEA,AAAmB,cAA2B;EAC7C,OAAO,KAAK;CACb;CAEA,AAAU,SAAe;EACxB,MAAM,OAAO,KAAK;EAClB,MAAM,YAAY,KAAK,UAAU;EACjC,MAAM,CAAC,gBAAgB,gBAAgB,KAAK,oBAC3C,KAAK,UAAU,IAAI,KAAK,UACzB;EAEA,KAAK,MAAM,YAAY,uBAAuB,OAAO,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC;EAC/E,KAAK,MAAM,YAAY,wBAAwB,OAAO,KAAK,eAAe,CAAC,CAAC;EAC5E,KAAK,MAAM,YAAY,iCAAiC,OAAO,cAAc,CAAC;EAC9E,KAAK,MAAM,YAAY,+BAA+B,OAAO,YAAY,CAAC;EAC1E,IAAI,cAAc,QAAW,KAAK,MAAM,eAAe,yBAAyB;OAC3E,KAAK,MAAM,YAAY,2BAA2B,OAAO,SAAS,CAAC;EACxE,KAAK,WAAW,IAAI;CACrB;CAEA,AAAmB,QAAiB;EACnC,OAAO,KAAK;CACb;AACD"}
1
+ {"version":3,"file":"dial.js","names":[],"sources":["../../../src/elements/dial.ts"],"sourcesContent":["import { SonicValueElement } from '#elements/value-element.ts';\nimport { requireChild, template } from '#lib/render.ts';\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sonic-dial': SonicDial;\n\t}\n}\n\nconst renderDial = template(\n\t/* HTML */ `\n\t\t<div class=\"sonic-dial\" role=\"slider\" tabindex=\"0\">\n\t\t\t<div class=\"sonic-dial-scale\" aria-hidden=\"true\"></div>\n\t\t\t<div class=\"sonic-dial-notches\"></div>\n\t\t\t<div class=\"sonic-dial-ring\"></div>\n\t\t\t<div class=\"sonic-dial-modulation\"></div>\n\t\t\t<div class=\"sonic-dial-cap\"></div>\n\t\t\t<div class=\"sonic-dial-indicator\"></div>\n\t\t\t<div class=\"sonic-dial-readout\" popover=\"manual\">\n\t\t\t\t<span></span>\n\t\t\t\t<input\n\t\t\t\t\tautocomplete=\"off\"\n\t\t\t\t\tclass=\"sonic-dial-entry\"\n\t\t\t\t\tenterkeyhint=\"done\"\n\t\t\t\t\thidden\n\t\t\t\t\tspellcheck=\"false\"\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</div>\n\t`,\n\tHTMLDivElement,\n);\n\nexport class SonicDial extends SonicValueElement {\n\tstatic override readonly observedAttributes = [\n\t\t...SonicValueElement.observedAttributes,\n\t\t'endless',\n\t\t'modulation',\n\t];\n\n\tget endless(): boolean {\n\t\treturn this.hasAttribute('endless');\n\t}\n\n\tset endless(isEndless: boolean) {\n\t\tthis.reflect('endless', isEndless);\n\t}\n\n\t// fallow-ignore-next-line code-duplication -- one accessor pair per reflected attribute\n\tget modulation(): number {\n\t\treturn this.numberAttribute('modulation', 0);\n\t}\n\n\tset modulation(amount: number | undefined) {\n\t\tthis.reflect('modulation', amount);\n\t}\n\n\t// fallow-ignore-next-line code-duplication -- one accessor pair per property\n\tget modulationValue(): number | undefined {\n\t\treturn this.readModulationValue();\n\t}\n\n\tset modulationValue(value: number | undefined) {\n\t\tthis.writeModulationValue(this.#dial, 'dial', value);\n\t}\n\n\treadonly #dial = renderDial();\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties('endless', 'modulationValue', 'modulation');\n\t\tsuper.connectedCallback();\n\t}\n\n\tprotected connect(signal: AbortSignal): void {\n\t\tconst dial = this.#dial;\n\n\t\tthis.bindScale(dial, requireChild(dial, '.sonic-dial-scale', HTMLDivElement), signal);\n\t\tthis.render();\n\t\tthis.checkStyles(dial, 'dial.css');\n\t\tthis.bindGestures(dial, signal, () => ({\n\t\t\tposition: (event) => -event.clientY,\n\t\t\ttravelPx: this.travelPx(dial, '--_sonic-dial-travel'),\n\t\t}));\n\t}\n\n\tprotected draw(): void {\n\t\tthis.writeProportions(this.#dial, 'dial', this.endless ? 0 : this.modulation);\n\t}\n\n\tprotected override focusTarget(): HTMLElement {\n\t\treturn this.#dial;\n\t}\n\n\tprotected override isWrapping(): boolean {\n\t\treturn this.endless;\n\t}\n}\n"],"mappings":";;;;AASA,MAAM,aAAa,SACP;;;;;;;;;;;;;;;;;;;;IAqBX,cACD;AAEA,IAAa,YAAb,cAA+B,kBAAkB;CAChD,OAAyB,qBAAqB;EAC7C,GAAG,kBAAkB;EACrB;EACA;CACD;CAEA,IAAI,UAAmB;EACtB,OAAO,KAAK,aAAa,SAAS;CACnC;CAEA,IAAI,QAAQ,WAAoB;EAC/B,KAAK,QAAQ,WAAW,SAAS;CAClC;CAGA,IAAI,aAAqB;EACxB,OAAO,KAAK,gBAAgB,cAAc,CAAC;CAC5C;CAEA,IAAI,WAAW,QAA4B;EAC1C,KAAK,QAAQ,cAAc,MAAM;CAClC;CAGA,IAAI,kBAAsC;EACzC,OAAO,KAAK,oBAAoB;CACjC;CAEA,IAAI,gBAAgB,OAA2B;EAC9C,KAAK,qBAAqB,KAAK,OAAO,QAAQ,KAAK;CACpD;CAEA,AAAS,QAAQ,WAAW;CAE5B,AAAS,oBAA0B;EAClC,KAAK,kBAAkB,WAAW,mBAAmB,YAAY;EACjE,MAAM,kBAAkB;CACzB;CAEA,AAAU,QAAQ,QAA2B;EAC5C,MAAM,OAAO,KAAK;EAElB,KAAK,UAAU,MAAM,aAAa,MAAM,qBAAqB,cAAc,GAAG,MAAM;EACpF,KAAK,OAAO;EACZ,KAAK,YAAY,MAAM,UAAU;EACjC,KAAK,aAAa,MAAM,eAAe;GACtC,WAAW,UAAU,CAAC,MAAM;GAC5B,UAAU,KAAK,SAAS,MAAM,sBAAsB;EACrD,EAAE;CACH;CAEA,AAAU,OAAa;EACtB,KAAK,iBAAiB,KAAK,OAAO,QAAQ,KAAK,UAAU,IAAI,KAAK,UAAU;CAC7E;CAEA,AAAmB,cAA2B;EAC7C,OAAO,KAAK;CACb;CAEA,AAAmB,aAAsB;EACxC,OAAO,KAAK;CACb;AACD"}
@@ -0,0 +1,36 @@
1
+ import { SonicElement } from "./sonic-element.js";
2
+ //#region src/elements/envelope.d.ts
3
+ declare global {
4
+ interface HTMLElementTagNameMap {
5
+ 'sonic-envelope': SonicEnvelope;
6
+ }
7
+ }
8
+ export declare class SonicEnvelope extends SonicElement {
9
+ #private;
10
+ static readonly observedAttributes: string[];
11
+ get attack(): string;
12
+ set attack(id: string | undefined);
13
+ get attackCurve(): string;
14
+ set attackCurve(id: string | undefined);
15
+ get decay(): string;
16
+ set decay(id: string | undefined);
17
+ get decayCurve(): string;
18
+ set decayCurve(id: string | undefined);
19
+ get delay(): string;
20
+ set delay(id: string | undefined);
21
+ get hold(): string;
22
+ set hold(id: string | undefined);
23
+ get readout(): boolean;
24
+ set readout(isOn: boolean);
25
+ get release(): string;
26
+ set release(id: string | undefined);
27
+ get releaseCurve(): string;
28
+ set releaseCurve(id: string | undefined);
29
+ get sustain(): string;
30
+ set sustain(id: string | undefined);
31
+ attributeChangedCallback(name: string): void;
32
+ connectedCallback(): void;
33
+ protected connect(signal: AbortSignal): void;
34
+ }
35
+ //#endregion
36
+ //# sourceMappingURL=envelope.d.ts.map
@@ -0,0 +1,372 @@
1
+ import { requireChild, template } from "../lib/render.js";
2
+ import { writeAttribute } from "../lib/write-attribute.js";
3
+ import { SonicElement } from "./sonic-element.js";
4
+ import { ReadoutClaim } from "./readout-claim.js";
5
+ import { Readout } from "./readout.js";
6
+ import { dragThresholdPx } from "../lib/drag-step.js";
7
+ import { SonicValueElement, linkValue } from "./value-element.js";
8
+ import { adsrPath, adsrShape, adsrStages, timeStages } from "../lib/adsr-shape.js";
9
+ import { pointerMove, pointerPosition, startFieldDrag, stepFieldDrag } from "../lib/field.js";
10
+ import { bindDrag } from "../lib/pointer-drag.js";
11
+
12
+ //#region src/elements/envelope.ts
13
+ const curveStages = [
14
+ "attack",
15
+ "decay",
16
+ "release"
17
+ ];
18
+ const bindable = [
19
+ ...adsrStages,
20
+ "attack-curve",
21
+ "decay-curve",
22
+ "release-curve"
23
+ ];
24
+ const bindableNames = new Set(bindable);
25
+ function flip(point, isFlipped) {
26
+ return isFlipped ? {
27
+ ...point,
28
+ y: -point.y
29
+ } : point;
30
+ }
31
+ function isParent(node) {
32
+ return "querySelector" in node;
33
+ }
34
+ const renderEnvelope = template(`
35
+ <div class="sonic-envelope" aria-hidden="true">
36
+ <svg class="sonic-envelope-graph" preserveAspectRatio="none" viewBox="0 0 1 1">
37
+ <path class="sonic-envelope-fill" />
38
+ <path class="sonic-envelope-line" />
39
+ </svg>
40
+ <div class="sonic-envelope-handle" data-sonic-stage="delay" hidden></div>
41
+ <div class="sonic-envelope-handle" data-sonic-stage="attack" hidden></div>
42
+ <div class="sonic-envelope-handle" data-sonic-stage="hold" hidden></div>
43
+ <div class="sonic-envelope-handle" data-sonic-stage="decay" hidden></div>
44
+ <div class="sonic-envelope-handle" data-sonic-stage="release" hidden></div>
45
+ <div class="sonic-envelope-curve" data-sonic-stage="attack" hidden></div>
46
+ <div class="sonic-envelope-curve" data-sonic-stage="decay" hidden></div>
47
+ <div class="sonic-envelope-curve" data-sonic-stage="release" hidden></div>
48
+ <div class="sonic-envelope-readout" popover="manual"><span></span></div>
49
+ </div>
50
+ `, HTMLDivElement);
51
+ var SonicEnvelope = class extends SonicElement {
52
+ static observedAttributes = [
53
+ ...SonicElement.observedAttributes,
54
+ ...bindable,
55
+ "readout"
56
+ ];
57
+ get attack() {
58
+ return this.getAttribute("attack") ?? "";
59
+ }
60
+ set attack(id) {
61
+ this.reflect("attack", id);
62
+ }
63
+ get attackCurve() {
64
+ return this.getAttribute("attack-curve") ?? "";
65
+ }
66
+ set attackCurve(id) {
67
+ this.reflect("attack-curve", id);
68
+ }
69
+ get decay() {
70
+ return this.getAttribute("decay") ?? "";
71
+ }
72
+ set decay(id) {
73
+ this.reflect("decay", id);
74
+ }
75
+ get decayCurve() {
76
+ return this.getAttribute("decay-curve") ?? "";
77
+ }
78
+ set decayCurve(id) {
79
+ this.reflect("decay-curve", id);
80
+ }
81
+ get delay() {
82
+ return this.getAttribute("delay") ?? "";
83
+ }
84
+ set delay(id) {
85
+ this.reflect("delay", id);
86
+ }
87
+ get hold() {
88
+ return this.getAttribute("hold") ?? "";
89
+ }
90
+ set hold(id) {
91
+ this.reflect("hold", id);
92
+ }
93
+ get readout() {
94
+ return this.hasAttribute("readout");
95
+ }
96
+ set readout(isOn) {
97
+ this.reflect("readout", isOn);
98
+ }
99
+ get release() {
100
+ return this.getAttribute("release") ?? "";
101
+ }
102
+ set release(id) {
103
+ this.reflect("release", id);
104
+ }
105
+ get releaseCurve() {
106
+ return this.getAttribute("release-curve") ?? "";
107
+ }
108
+ set releaseCurve(id) {
109
+ this.reflect("release-curve", id);
110
+ }
111
+ get sustain() {
112
+ return this.getAttribute("sustain") ?? "";
113
+ }
114
+ set sustain(id) {
115
+ this.reflect("sustain", id);
116
+ }
117
+ #bindings = /* @__PURE__ */ new Map();
118
+ #claim = new ReadoutClaim(() => {
119
+ this.#renderReadout();
120
+ });
121
+ #envelope = renderEnvelope();
122
+ #fill = requireChild(this.#envelope, ".sonic-envelope-fill", SVGElement);
123
+ #graph = requireChild(this.#envelope, ".sonic-envelope-graph", SVGElement);
124
+ #line = requireChild(this.#envelope, ".sonic-envelope-line", SVGElement);
125
+ #pointerDrag;
126
+ #readout = new Readout(requireChild(this.#envelope, ".sonic-envelope-readout", HTMLDivElement));
127
+ #shape = adsrShape({});
128
+ #signal;
129
+ #waiting = /* @__PURE__ */ new Set();
130
+ #warned = /* @__PURE__ */ new Set();
131
+ attributeChangedCallback(name) {
132
+ if (!this.#signal) return;
133
+ if (name === "disabled") {
134
+ this.#pointerDrag?.end();
135
+ this.#draw();
136
+ return;
137
+ }
138
+ if (bindableNames.has(name)) this.#bind();
139
+ else this.#renderReadout();
140
+ }
141
+ connectedCallback() {
142
+ this.upgradeProperties(...adsrStages, "attackCurve", "decayCurve", "readout", "releaseCurve");
143
+ super.connectedCallback();
144
+ }
145
+ connect(signal) {
146
+ const envelope = this.#envelope;
147
+ this.#signal = signal;
148
+ this.appendOnce(envelope);
149
+ this.#bind();
150
+ this.checkStyles(envelope, "envelope.css");
151
+ this.#bindPointer(envelope, signal);
152
+ signal.addEventListener("abort", () => {
153
+ this.#signal = void 0;
154
+ this.#unbind();
155
+ }, { once: true });
156
+ }
157
+ #bind() {
158
+ this.#pointerDrag?.end();
159
+ this.#unbind();
160
+ for (const name of bindable) {
161
+ const element = this.#resolve(name);
162
+ if (!element) continue;
163
+ const link = linkValue(element);
164
+ const unwatch = link.watch(() => {
165
+ this.#draw();
166
+ });
167
+ this.#bindings.set(name, {
168
+ element,
169
+ link,
170
+ unwatch
171
+ });
172
+ }
173
+ this.#draw();
174
+ }
175
+ #bindPointer(envelope, signal) {
176
+ this.#pointerDrag = bindDrag(envelope, {
177
+ cancel: (drag) => {
178
+ for (const { binding, from } of drag.drives) binding.link.input(from);
179
+ },
180
+ grab: (event) => this.#grab(event),
181
+ move: (drag, event) => {
182
+ this.#moveDrag(drag, event);
183
+ },
184
+ release: (drag) => {
185
+ this.#claim.press(false);
186
+ for (const { binding, from } of drag.drives) {
187
+ if (binding.link.value() === from) continue;
188
+ binding.element.dispatchEvent(new Event("change", { bubbles: true }));
189
+ }
190
+ },
191
+ toggle: (isDragging) => {
192
+ this.toggleState("dragging", isDragging);
193
+ }
194
+ }, signal);
195
+ }
196
+ #curveDrives(stage) {
197
+ const binding = this.#bindings.get(`${stage}-curve`);
198
+ return binding ? [{
199
+ axis: "y",
200
+ binding
201
+ }] : [];
202
+ }
203
+ #draw() {
204
+ const shape = this.#readShape();
205
+ const path = this.#bindings.size === 0 ? {
206
+ fill: "",
207
+ stroke: ""
208
+ } : adsrPath(shape);
209
+ this.#shape = shape;
210
+ this.#line.setAttribute("d", path.stroke);
211
+ this.#fill.setAttribute("d", path.fill);
212
+ for (const stage of timeStages) this.#drawPoint(`.sonic-envelope-handle[data-sonic-stage="${stage}"]`, {
213
+ at: shape.handles.find((point) => point.stage === stage),
214
+ drives: this.#drives(stage)
215
+ });
216
+ for (const stage of curveStages) this.#drawPoint(`.sonic-envelope-curve[data-sonic-stage="${stage}"]`, {
217
+ at: shape.curveHandles.find((point) => point.stage === stage),
218
+ drives: this.#curveDrives(stage)
219
+ });
220
+ this.#renderReadout();
221
+ }
222
+ #drawPoint(selector, point) {
223
+ const part = requireChild(this.#envelope, selector, HTMLDivElement);
224
+ const { at, drives } = point;
225
+ part.hidden = !at;
226
+ if (!at) return;
227
+ const isStill = this.isDisabled() || drives.every(({ binding }) => binding.link.isDisabled());
228
+ part.style.setProperty("--_sonic-envelope-x", String(at.x));
229
+ part.style.setProperty("--_sonic-envelope-y", String(at.y));
230
+ part.dataset.sonicAxes = drives.map(({ axis }) => axis).join("");
231
+ writeAttribute(part, "data-sonic-disabled", isStill ? "" : void 0);
232
+ }
233
+ #drives(stage) {
234
+ const x = this.#bindings.get(stage);
235
+ const y = stage === "decay" ? this.#bindings.get("sustain") : void 0;
236
+ return [...x ? [{
237
+ axis: "x",
238
+ binding: x
239
+ }] : [], ...y ? [{
240
+ axis: "y",
241
+ binding: y
242
+ }] : []];
243
+ }
244
+ #grab(event) {
245
+ const pressed = this.#pressed(event);
246
+ if (!pressed || pressed.drives.length === 0) return void 0;
247
+ const { drives, isFlipped, part } = pressed;
248
+ this.#claim.press(true);
249
+ const box = this.#graph.getBoundingClientRect();
250
+ const travel = {
251
+ x: Math.max(1, box.width * this.#shape.share),
252
+ y: Math.max(1, box.height)
253
+ };
254
+ const start = (axis) => {
255
+ const link = drives.find((drive) => drive.axis === axis)?.binding.link;
256
+ if (!link) return;
257
+ const mapping = link.mapping();
258
+ const from = link.value();
259
+ return {
260
+ from,
261
+ mapping,
262
+ proportion: mapping.proportionOf(from),
263
+ travelPx: travel[axis]
264
+ };
265
+ };
266
+ return {
267
+ drives: drives.map((drive) => ({
268
+ ...drive,
269
+ from: drive.binding.link.value()
270
+ })),
271
+ isFlipped,
272
+ part,
273
+ state: startFieldDrag({
274
+ position: flip(pointerPosition(event), isFlipped),
275
+ thresholdPx: dragThresholdPx(event.pointerType),
276
+ x: start("x"),
277
+ y: start("y")
278
+ })
279
+ };
280
+ }
281
+ #moveDrag(drag, event) {
282
+ const mappings = {};
283
+ for (const { axis, binding } of drag.drives) mappings[axis] = binding.link.mapping();
284
+ const step = stepFieldDrag(mappings, drag.state, flip(pointerMove(event), drag.isFlipped));
285
+ drag.state = step.state;
286
+ if (step.state.isEngaged) this.#claim.reveal("drag");
287
+ for (const { axis, binding } of drag.drives) {
288
+ const next = step[axis];
289
+ if (next !== void 0) binding.link.input(next);
290
+ }
291
+ this.#renderReadout();
292
+ }
293
+ #pressed(event) {
294
+ const part = event.target instanceof Element ? event.target.closest(".sonic-envelope-handle, .sonic-envelope-curve") : void 0;
295
+ const stage = part?.dataset.sonicStage;
296
+ if (!part || stage === void 0 || this.isDisabled()) return void 0;
297
+ const isCurveHandle = part.classList.contains("sonic-envelope-curve");
298
+ return {
299
+ drives: (isCurveHandle ? this.#curveDrives(stage) : this.#drives(stage)).filter(({ binding }) => !binding.link.isDisabled()),
300
+ isFlipped: isCurveHandle && stage === "attack",
301
+ part
302
+ };
303
+ }
304
+ #readShape() {
305
+ const proportions = {};
306
+ const curves = {};
307
+ for (const stage of adsrStages) {
308
+ const link = this.#bindings.get(stage)?.link;
309
+ proportions[stage] = link?.mapping().proportionOf(link.value());
310
+ }
311
+ for (const stage of curveStages) curves[stage] = this.#bindings.get(`${stage}-curve`)?.link.value();
312
+ return adsrShape(proportions, curves);
313
+ }
314
+ #rebindOnce(key, arrives) {
315
+ if (this.#waiting.has(key)) return;
316
+ this.#waiting.add(key);
317
+ arrives(() => {
318
+ this.#waiting.delete(key);
319
+ if (this.#signal) this.#bind();
320
+ });
321
+ }
322
+ #renderReadout() {
323
+ const drag = this.#pointerDrag?.current();
324
+ if (!drag) {
325
+ this.#readout.close();
326
+ return;
327
+ }
328
+ this.#readout.show({
329
+ anchor: drag.part,
330
+ isOpen: this.#claim.isRevealed && this.readout,
331
+ text: drag.drives.map(({ binding }) => binding.element.valueText).join(", ")
332
+ });
333
+ }
334
+ #resolve(name) {
335
+ const id = this.getAttribute(name);
336
+ const root = this.getRootNode();
337
+ if (!id || !isParent(root)) return void 0;
338
+ const found = root.querySelector(`#${CSS.escape(id)}`);
339
+ if (found instanceof SonicValueElement) return found;
340
+ this.#wait(id, found);
341
+ }
342
+ #unbind() {
343
+ for (const { unwatch } of this.#bindings.values()) unwatch();
344
+ this.#bindings.clear();
345
+ }
346
+ #wait(id, found) {
347
+ const tag = found?.localName;
348
+ const { ownerDocument } = this;
349
+ if (tag?.includes("-") && !customElements.get(tag)) {
350
+ this.#rebindOnce(tag, (rebind) => {
351
+ customElements.whenDefined(tag).then(rebind);
352
+ });
353
+ return;
354
+ }
355
+ if (!found && ownerDocument.readyState === "loading") {
356
+ this.#rebindOnce(ownerDocument, (rebind) => {
357
+ ownerDocument.addEventListener("DOMContentLoaded", rebind, { once: true });
358
+ });
359
+ return;
360
+ }
361
+ this.#warn(id);
362
+ }
363
+ #warn(id) {
364
+ if (this.#warned.has(id)) return;
365
+ this.#warned.add(id);
366
+ console.warn(`<sonic-envelope> found no dial, slider or number box with the id "${id}"`);
367
+ }
368
+ };
369
+
370
+ //#endregion
371
+ export { SonicEnvelope };
372
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","names":[],"sources":["../../../src/elements/envelope.ts"],"sourcesContent":["import type { ValueLink } from '#elements/value-element.ts';\nimport type { AdsrCurves, AdsrProportions, AdsrShape } from '#lib/adsr-shape.ts';\nimport type { FieldAxis, FieldDragState, FieldMappings, FieldPoint } from '#lib/field.ts';\nimport type { PointerDrag } from '#lib/pointer-drag.ts';\n\nimport { ReadoutClaim } from '#elements/readout-claim.ts';\nimport { Readout } from '#elements/readout.ts';\nimport { SonicElement } from '#elements/sonic-element.ts';\nimport { linkValue, SonicValueElement } from '#elements/value-element.ts';\nimport { adsrPath, adsrShape, adsrStages, timeStages } from '#lib/adsr-shape.ts';\nimport { dragThresholdPx } from '#lib/drag-step.ts';\nimport { pointerMove, pointerPosition, startFieldDrag, stepFieldDrag } from '#lib/field.ts';\nimport { bindDrag } from '#lib/pointer-drag.ts';\nimport { requireChild, template } from '#lib/render.ts';\nimport { writeAttribute } from '#lib/write-attribute.ts';\n\n// eslint-disable-next-line unicorn/consistent-boolean-name -- the name bundlers and other kits use\ndeclare const __DEV__: boolean;\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sonic-envelope': SonicEnvelope;\n\t}\n}\n\ninterface Binding {\n\telement: SonicValueElement;\n\tlink: ValueLink;\n\tunwatch: () => void;\n}\n\ninterface Drive {\n\taxis: FieldAxis;\n\tbinding: Binding;\n}\n\ninterface HandleDrag {\n\tdrives: Array<Drive & { from: number }>;\n\tisFlipped: boolean;\n\tpart: HTMLElement;\n\tstate: FieldDragState;\n}\n\nconst curveStages = ['attack', 'decay', 'release'] as const;\n\nconst bindable = [...adsrStages, 'attack-curve', 'decay-curve', 'release-curve'] as const;\n\nconst bindableNames = new Set<string>(bindable);\n\nfunction flip<Point extends FieldPoint>(point: Point, isFlipped: boolean): Point {\n\treturn isFlipped ? { ...point, y: -point.y } : point;\n}\n\nfunction isParent(node: Node): node is Node & ParentNode {\n\treturn 'querySelector' in node;\n}\n\nconst renderEnvelope = template(\n\t/* HTML */ `\n\t\t<div class=\"sonic-envelope\" aria-hidden=\"true\">\n\t\t\t<svg class=\"sonic-envelope-graph\" preserveAspectRatio=\"none\" viewBox=\"0 0 1 1\">\n\t\t\t\t<path class=\"sonic-envelope-fill\" />\n\t\t\t\t<path class=\"sonic-envelope-line\" />\n\t\t\t</svg>\n\t\t\t<div class=\"sonic-envelope-handle\" data-sonic-stage=\"delay\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-handle\" data-sonic-stage=\"attack\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-handle\" data-sonic-stage=\"hold\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-handle\" data-sonic-stage=\"decay\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-handle\" data-sonic-stage=\"release\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-curve\" data-sonic-stage=\"attack\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-curve\" data-sonic-stage=\"decay\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-curve\" data-sonic-stage=\"release\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-readout\" popover=\"manual\"><span></span></div>\n\t\t</div>\n\t`,\n\tHTMLDivElement,\n);\n\nexport class SonicEnvelope extends SonicElement {\n\tstatic override readonly observedAttributes = [\n\t\t...SonicElement.observedAttributes,\n\t\t...bindable,\n\t\t'readout',\n\t];\n\n\tget attack(): string {\n\t\treturn this.getAttribute('attack') ?? '';\n\t}\n\n\tset attack(id: string | undefined) {\n\t\tthis.reflect('attack', id);\n\t}\n\n\tget attackCurve(): string {\n\t\treturn this.getAttribute('attack-curve') ?? '';\n\t}\n\n\tset attackCurve(id: string | undefined) {\n\t\tthis.reflect('attack-curve', id);\n\t}\n\n\tget decay(): string {\n\t\treturn this.getAttribute('decay') ?? '';\n\t}\n\n\tset decay(id: string | undefined) {\n\t\tthis.reflect('decay', id);\n\t}\n\n\tget decayCurve(): string {\n\t\treturn this.getAttribute('decay-curve') ?? '';\n\t}\n\n\tset decayCurve(id: string | undefined) {\n\t\tthis.reflect('decay-curve', id);\n\t}\n\n\tget delay(): string {\n\t\treturn this.getAttribute('delay') ?? '';\n\t}\n\n\tset delay(id: string | undefined) {\n\t\tthis.reflect('delay', id);\n\t}\n\n\tget hold(): string {\n\t\treturn this.getAttribute('hold') ?? '';\n\t}\n\n\tset hold(id: string | undefined) {\n\t\tthis.reflect('hold', id);\n\t}\n\n\tget readout(): boolean {\n\t\treturn this.hasAttribute('readout');\n\t}\n\n\tset readout(isOn: boolean) {\n\t\tthis.reflect('readout', isOn);\n\t}\n\n\tget release(): string {\n\t\treturn this.getAttribute('release') ?? '';\n\t}\n\n\tset release(id: string | undefined) {\n\t\tthis.reflect('release', id);\n\t}\n\n\tget releaseCurve(): string {\n\t\treturn this.getAttribute('release-curve') ?? '';\n\t}\n\n\tset releaseCurve(id: string | undefined) {\n\t\tthis.reflect('release-curve', id);\n\t}\n\n\tget sustain(): string {\n\t\treturn this.getAttribute('sustain') ?? '';\n\t}\n\n\tset sustain(id: string | undefined) {\n\t\tthis.reflect('sustain', id);\n\t}\n\n\treadonly #bindings = new Map<string, Binding>();\n\n\treadonly #claim = new ReadoutClaim(() => {\n\t\tthis.#renderReadout();\n\t});\n\n\treadonly #envelope = renderEnvelope();\n\n\treadonly #fill = requireChild(this.#envelope, '.sonic-envelope-fill', SVGElement);\n\n\treadonly #graph = requireChild(this.#envelope, '.sonic-envelope-graph', SVGElement);\n\n\treadonly #line = requireChild(this.#envelope, '.sonic-envelope-line', SVGElement);\n\n\t#pointerDrag: PointerDrag<HandleDrag> | undefined;\n\n\treadonly #readout = new Readout(\n\t\trequireChild(this.#envelope, '.sonic-envelope-readout', HTMLDivElement),\n\t);\n\n\t#shape: AdsrShape = adsrShape({});\n\n\t#signal: AbortSignal | undefined;\n\n\treadonly #waiting = new Set<unknown>();\n\n\treadonly #warned = new Set<string>();\n\n\tattributeChangedCallback(name: string): void {\n\t\tif (!this.#signal) return;\n\t\tif (name === 'disabled') {\n\t\t\tthis.#pointerDrag?.end();\n\t\t\tthis.#draw();\n\t\t\treturn;\n\t\t}\n\t\tif (bindableNames.has(name)) this.#bind();\n\t\telse this.#renderReadout();\n\t}\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties(...adsrStages, 'attackCurve', 'decayCurve', 'readout', 'releaseCurve');\n\t\tsuper.connectedCallback();\n\t}\n\n\tprotected connect(signal: AbortSignal): void {\n\t\tconst envelope = this.#envelope;\n\n\t\tthis.#signal = signal;\n\t\tthis.appendOnce(envelope);\n\t\tthis.#bind();\n\t\tthis.checkStyles(envelope, 'envelope.css');\n\t\tthis.#bindPointer(envelope, signal);\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tthis.#signal = undefined;\n\t\t\t\tthis.#unbind();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\t#bind(): void {\n\t\tthis.#pointerDrag?.end();\n\t\tthis.#unbind();\n\t\tfor (const name of bindable) {\n\t\t\tconst element = this.#resolve(name);\n\t\t\tif (!element) continue;\n\n\t\t\tconst link = linkValue(element);\n\t\t\tconst unwatch = link.watch(() => {\n\t\t\t\tthis.#draw();\n\t\t\t});\n\n\t\t\tthis.#bindings.set(name, { element, link, unwatch });\n\t\t}\n\t\tthis.#draw();\n\t}\n\n\t#bindPointer(envelope: HTMLElement, signal: AbortSignal): void {\n\t\tthis.#pointerDrag = bindDrag(\n\t\t\tenvelope,\n\t\t\t{\n\t\t\t\tcancel: (drag) => {\n\t\t\t\t\tfor (const { binding, from } of drag.drives) binding.link.input(from);\n\t\t\t\t},\n\t\t\t\tgrab: (event) => this.#grab(event),\n\t\t\t\tmove: (drag, event) => {\n\t\t\t\t\tthis.#moveDrag(drag, event);\n\t\t\t\t},\n\t\t\t\trelease: (drag) => {\n\t\t\t\t\tthis.#claim.press(false);\n\t\t\t\t\tfor (const { binding, from } of drag.drives) {\n\t\t\t\t\t\tif (binding.link.value() === from) continue;\n\n\t\t\t\t\t\tbinding.element.dispatchEvent(new Event('change', { bubbles: true }));\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\ttoggle: (isDragging) => {\n\t\t\t\t\tthis.toggleState('dragging', isDragging);\n\t\t\t\t},\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t#curveDrives(stage: string): Array<Drive> {\n\t\tconst binding = this.#bindings.get(`${stage}-curve`);\n\n\t\treturn binding ? [{ axis: 'y', binding }] : [];\n\t}\n\n\t#draw(): void {\n\t\tconst shape = this.#readShape();\n\t\tconst path = this.#bindings.size === 0 ? { fill: '', stroke: '' } : adsrPath(shape);\n\n\t\tthis.#shape = shape;\n\t\tthis.#line.setAttribute('d', path.stroke);\n\t\tthis.#fill.setAttribute('d', path.fill);\n\t\tfor (const stage of timeStages) {\n\t\t\tthis.#drawPoint(`.sonic-envelope-handle[data-sonic-stage=\"${stage}\"]`, {\n\t\t\t\tat: shape.handles.find((point) => point.stage === stage),\n\t\t\t\tdrives: this.#drives(stage),\n\t\t\t});\n\t\t}\n\t\tfor (const stage of curveStages) {\n\t\t\tthis.#drawPoint(`.sonic-envelope-curve[data-sonic-stage=\"${stage}\"]`, {\n\t\t\t\tat: shape.curveHandles.find((point) => point.stage === stage),\n\t\t\t\tdrives: this.#curveDrives(stage),\n\t\t\t});\n\t\t}\n\t\tthis.#renderReadout();\n\t}\n\n\t#drawPoint(selector: string, point: { at: FieldPoint | undefined; drives: Array<Drive> }): void {\n\t\tconst part = requireChild(this.#envelope, selector, HTMLDivElement);\n\t\tconst { at, drives } = point;\n\n\t\tpart.hidden = !at;\n\t\tif (!at) return;\n\n\t\tconst isStill = this.isDisabled() || drives.every(({ binding }) => binding.link.isDisabled());\n\n\t\tpart.style.setProperty('--_sonic-envelope-x', String(at.x));\n\t\tpart.style.setProperty('--_sonic-envelope-y', String(at.y));\n\t\tpart.dataset.sonicAxes = drives.map(({ axis }) => axis).join('');\n\t\twriteAttribute(part, 'data-sonic-disabled', isStill ? '' : undefined);\n\t}\n\n\t#drives(stage: string): Array<Drive> {\n\t\tconst x = this.#bindings.get(stage);\n\t\tconst y = stage === 'decay' ? this.#bindings.get('sustain') : undefined;\n\n\t\treturn [\n\t\t\t...(x ? [{ axis: 'x' as const, binding: x }] : []),\n\t\t\t...(y ? [{ axis: 'y' as const, binding: y }] : []),\n\t\t];\n\t}\n\n\t#grab(event: PointerEvent): HandleDrag | undefined {\n\t\tconst pressed = this.#pressed(event);\n\t\tif (!pressed || pressed.drives.length === 0) return undefined;\n\n\t\tconst { drives, isFlipped, part } = pressed;\n\n\t\tthis.#claim.press(true);\n\t\tconst box = this.#graph.getBoundingClientRect();\n\t\tconst travel = { x: Math.max(1, box.width * this.#shape.share), y: Math.max(1, box.height) };\n\t\tconst start = (axis: FieldAxis) => {\n\t\t\tconst link = drives.find((drive) => drive.axis === axis)?.binding.link;\n\t\t\tif (!link) return;\n\n\t\t\tconst mapping = link.mapping();\n\t\t\tconst from = link.value();\n\n\t\t\treturn { from, mapping, proportion: mapping.proportionOf(from), travelPx: travel[axis] };\n\t\t};\n\n\t\treturn {\n\t\t\tdrives: drives.map((drive) => ({ ...drive, from: drive.binding.link.value() })),\n\t\t\tisFlipped,\n\t\t\tpart,\n\t\t\tstate: startFieldDrag({\n\t\t\t\tposition: flip(pointerPosition(event), isFlipped),\n\t\t\t\tthresholdPx: dragThresholdPx(event.pointerType),\n\t\t\t\tx: start('x'),\n\t\t\t\ty: start('y'),\n\t\t\t}),\n\t\t};\n\t}\n\n\t#moveDrag(drag: HandleDrag, event: PointerEvent): void {\n\t\tconst mappings: FieldMappings = {};\n\n\t\tfor (const { axis, binding } of drag.drives) mappings[axis] = binding.link.mapping();\n\n\t\tconst step = stepFieldDrag(mappings, drag.state, flip(pointerMove(event), drag.isFlipped));\n\n\t\tdrag.state = step.state;\n\t\tif (step.state.isEngaged) this.#claim.reveal('drag');\n\t\tfor (const { axis, binding } of drag.drives) {\n\t\t\tconst next = step[axis];\n\n\t\t\tif (next !== undefined) binding.link.input(next);\n\t\t}\n\t\tthis.#renderReadout();\n\t}\n\n\t#pressed(\n\t\tevent: PointerEvent,\n\t): (Pick<HandleDrag, 'isFlipped' | 'part'> & { drives: Array<Drive> }) | undefined {\n\t\tconst part =\n\t\t\tevent.target instanceof Element\n\t\t\t\t? event.target.closest<HTMLElement>('.sonic-envelope-handle, .sonic-envelope-curve')\n\t\t\t\t: undefined;\n\t\tconst stage = part?.dataset.sonicStage;\n\t\tif (!part || stage === undefined || this.isDisabled()) return undefined;\n\n\t\tconst isCurveHandle = part.classList.contains('sonic-envelope-curve');\n\t\tconst drives = isCurveHandle ? this.#curveDrives(stage) : this.#drives(stage);\n\n\t\treturn {\n\t\t\tdrives: drives.filter(({ binding }) => !binding.link.isDisabled()),\n\t\t\tisFlipped: isCurveHandle && stage === 'attack',\n\t\t\tpart,\n\t\t};\n\t}\n\n\t#readShape(): AdsrShape {\n\t\tconst proportions: AdsrProportions = {};\n\t\tconst curves: AdsrCurves = {};\n\n\t\tfor (const stage of adsrStages) {\n\t\t\tconst link = this.#bindings.get(stage)?.link;\n\n\t\t\tproportions[stage] = link?.mapping().proportionOf(link.value());\n\t\t}\n\t\tfor (const stage of curveStages) {\n\t\t\tcurves[stage] = this.#bindings.get(`${stage}-curve`)?.link.value();\n\t\t}\n\n\t\treturn adsrShape(proportions, curves);\n\t}\n\n\t#rebindOnce(key: unknown, arrives: (rebind: () => void) => void): void {\n\t\tif (this.#waiting.has(key)) return;\n\n\t\tthis.#waiting.add(key);\n\t\tarrives(() => {\n\t\t\tthis.#waiting.delete(key);\n\t\t\tif (this.#signal) this.#bind();\n\t\t});\n\t}\n\n\t#renderReadout(): void {\n\t\tconst drag = this.#pointerDrag?.current();\n\n\t\tif (!drag) {\n\t\t\tthis.#readout.close();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#readout.show({\n\t\t\tanchor: drag.part,\n\t\t\tisOpen: this.#claim.isRevealed && this.readout,\n\t\t\ttext: drag.drives.map(({ binding }) => binding.element.valueText).join(', '),\n\t\t});\n\t}\n\n\t#resolve(name: string): SonicValueElement | undefined {\n\t\tconst id = this.getAttribute(name);\n\t\tconst root = this.getRootNode();\n\t\tif (!id || !isParent(root)) return undefined;\n\n\t\tconst found = root.querySelector(`#${CSS.escape(id)}`);\n\t\tif (found instanceof SonicValueElement) return found;\n\n\t\tthis.#wait(id, found);\n\n\t\treturn undefined;\n\t}\n\n\t#unbind(): void {\n\t\tfor (const { unwatch } of this.#bindings.values()) unwatch();\n\n\t\tthis.#bindings.clear();\n\t}\n\n\t#wait(id: string, found: Element | null): void {\n\t\tconst tag = found?.localName;\n\t\tconst { ownerDocument } = this;\n\n\t\tif (tag?.includes('-') && !customElements.get(tag)) {\n\t\t\tthis.#rebindOnce(tag, (rebind) => {\n\t\t\t\tvoid customElements.whenDefined(tag).then(rebind);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tif (!found && ownerDocument.readyState === 'loading') {\n\t\t\tthis.#rebindOnce(ownerDocument, (rebind) => {\n\t\t\t\townerDocument.addEventListener('DOMContentLoaded', rebind, { once: true });\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#warn(id);\n\t}\n\n\t#warn(id: string): void {\n\t\tif (!__DEV__) return;\n\t\tif (this.#warned.has(id)) return;\n\n\t\tthis.#warned.add(id);\n\t\tconsole.warn(`<sonic-envelope> found no dial, slider or number box with the id \"${id}\"`);\n\t}\n}\n"],"mappings":"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"}
@@ -16,7 +16,7 @@ export declare abstract class SonicFormElement extends SonicElement {
16
16
  protected namingLabels(): Array<Element>;
17
17
  protected abstract render(): void;
18
18
  protected abstract restoreState(state: string): void;
19
- protected writeFormValue(value: null | string, state: string): void;
19
+ protected writeFormValue(value: FormData | null | string, state: string): void;
20
20
  }
21
21
  //#endregion
22
22
  //# sourceMappingURL=form-element.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"form-element.js","names":[],"sources":["../../../src/elements/form-element.ts"],"sourcesContent":["import { SonicElement } from '#elements/sonic-element.ts';\n\n// A `<label>` names and clicks the host, which has no role and no box, so both pass to the control\nexport abstract class SonicFormElement extends SonicElement {\n\tstatic readonly formAssociated = true;\n\n\tget form(): HTMLFormElement | null {\n\t\t// eslint-disable-next-line unicorn/no-null -- as on native inputs\n\t\treturn this.internals?.form ?? null;\n\t}\n\n\tget labels(): NodeList | null {\n\t\t// eslint-disable-next-line unicorn/no-null -- as on native inputs\n\t\treturn this.internals?.labels ?? null;\n\t}\n\n\tget name(): string {\n\t\treturn this.getAttribute('name') ?? '';\n\t}\n\n\tset name(value: string | undefined) {\n\t\tthis.reflect('name', value);\n\t}\n\n\tconstructor() {\n\t\tsuper();\n\n\t\t// Otherwise the host takes the label's name and shows as a named generic beside the control\n\t\tif (this.internals) this.internals.role = 'none';\n\n\t\t// Only a label's click targets the host itself; a click inside the control bubbles here from its own target\n\t\tthis.addEventListener('click', (event) => {\n\t\t\tif (event.target === this) this.activate();\n\t\t});\n\n\t\t// No event fires when a label arrives, so focus picks it up\n\t\tthis.addEventListener('focusin', () => {\n\t\t\tthis.render();\n\t\t});\n\t}\n\n\tabstract attributeChangedCallback(name: string): void;\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties('name');\n\t\tsuper.connectedCallback();\n\t}\n\n\t// Never writes the attribute, or re-enabling the fieldset would leave the control disabled\n\tformDisabledCallback(): void {\n\t\tthis.attributeChangedCallback('disabled');\n\t}\n\n\t// Back to the `value` attribute; the key overrides it to return to `pressed`\n\tformResetCallback(): void {\n\t\tthis.attributeChangedCallback('value');\n\t}\n\n\t// Firefox hands a restored state to the wrong control when tags upgrade out of document order\n\t// Each state names its tag, and a control drops one another tag wrote\n\tformStateRestoreCallback(state: File | FormData | null | string): void {\n\t\tconst prefix = `${this.localName}:`;\n\n\t\tif (typeof state === 'string' && state.startsWith(prefix)) {\n\t\t\tthis.restoreState(state.slice(prefix.length));\n\t\t}\n\t}\n\n\tprotected activate(): void {\n\t\tthis.focus();\n\t}\n\n\t// An author's `aria-label` or `aria-labelledby` wins over a label, as on native inputs\n\tprotected override namingLabels(): Array<Element> {\n\t\tconst internals = this.internals;\n\t\tif (!internals || this.hasAttribute('aria-label') || this.hasAttribute('aria-labelledby')) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn [...internals.labels].filter((label) => label instanceof Element);\n\t}\n\n\tprotected abstract render(): void;\n\n\tprotected abstract restoreState(state: string): void;\n\n\tprotected writeFormValue(value: null | string, state: string): void {\n\t\tthis.internals?.setFormValue(value, `${this.localName}:${state}`);\n\t}\n}\n"],"mappings":";;;AAGA,IAAsB,mBAAtB,cAA+C,aAAa;CAC3D,OAAgB,iBAAiB;CAEjC,IAAI,OAA+B;EAElC,OAAO,KAAK,WAAW,QAAQ;CAChC;CAEA,IAAI,SAA0B;EAE7B,OAAO,KAAK,WAAW,UAAU;CAClC;CAEA,IAAI,OAAe;EAClB,OAAO,KAAK,aAAa,MAAM,KAAK;CACrC;CAEA,IAAI,KAAK,OAA2B;EACnC,KAAK,QAAQ,QAAQ,KAAK;CAC3B;CAEA,cAAc;EACb,MAAM;EAGN,IAAI,KAAK,WAAW,KAAK,UAAU,OAAO;EAG1C,KAAK,iBAAiB,UAAU,UAAU;GACzC,IAAI,MAAM,WAAW,MAAM,KAAK,SAAS;EAC1C,CAAC;EAGD,KAAK,iBAAiB,iBAAiB;GACtC,KAAK,OAAO;EACb,CAAC;CACF;CAIA,AAAS,oBAA0B;EAClC,KAAK,kBAAkB,MAAM;EAC7B,MAAM,kBAAkB;CACzB;CAGA,uBAA6B;EAC5B,KAAK,yBAAyB,UAAU;CACzC;CAGA,oBAA0B;EACzB,KAAK,yBAAyB,OAAO;CACtC;CAIA,yBAAyB,OAA8C;EACtE,MAAM,SAAS,GAAG,KAAK,UAAU;EAEjC,IAAI,OAAO,UAAU,YAAY,MAAM,WAAW,MAAM,GACvD,KAAK,aAAa,MAAM,MAAM,OAAO,MAAM,CAAC;CAE9C;CAEA,AAAU,WAAiB;EAC1B,KAAK,MAAM;CACZ;CAGA,AAAmB,eAA+B;EACjD,MAAM,YAAY,KAAK;EACvB,IAAI,CAAC,aAAa,KAAK,aAAa,YAAY,KAAK,KAAK,aAAa,iBAAiB,GACvF,OAAO,CAAC;EAGT,OAAO,CAAC,GAAG,UAAU,MAAM,CAAC,CAAC,QAAQ,UAAU,iBAAiB,OAAO;CACxE;CAMA,AAAU,eAAe,OAAsB,OAAqB;EACnE,KAAK,WAAW,aAAa,OAAO,GAAG,KAAK,UAAU,GAAG,OAAO;CACjE;AACD"}
1
+ {"version":3,"file":"form-element.js","names":[],"sources":["../../../src/elements/form-element.ts"],"sourcesContent":["import { SonicElement } from '#elements/sonic-element.ts';\n\nexport abstract class SonicFormElement extends SonicElement {\n\tstatic readonly formAssociated = true;\n\n\tget form(): HTMLFormElement | null {\n\t\t// eslint-disable-next-line unicorn/no-null -- as on native inputs\n\t\treturn this.internals?.form ?? null;\n\t}\n\n\tget labels(): NodeList | null {\n\t\t// eslint-disable-next-line unicorn/no-null -- as on native inputs\n\t\treturn this.internals?.labels ?? null;\n\t}\n\n\tget name(): string {\n\t\treturn this.getAttribute('name') ?? '';\n\t}\n\n\tset name(value: string | undefined) {\n\t\tthis.reflect('name', value);\n\t}\n\n\tconstructor() {\n\t\tsuper();\n\n\t\t// Otherwise the host takes the label's name and shows as a named generic beside the control\n\t\tif (this.internals) this.internals.role = 'none';\n\n\t\t// A click inside the control bubbles here with its own target; only a label's click targets the host\n\t\tthis.addEventListener('click', (event) => {\n\t\t\tif (event.target === this) this.activate();\n\t\t});\n\n\t\t// No event fires when a label arrives, so focus picks it up\n\t\tthis.addEventListener('focusin', () => {\n\t\t\tthis.render();\n\t\t});\n\t}\n\n\tabstract attributeChangedCallback(name: string): void;\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties('name');\n\t\tsuper.connectedCallback();\n\t}\n\n\t// Never writes the attribute, or re-enabling the fieldset would leave the control disabled\n\tformDisabledCallback(): void {\n\t\tthis.attributeChangedCallback('disabled');\n\t}\n\n\tformResetCallback(): void {\n\t\tthis.attributeChangedCallback('value');\n\t}\n\n\t// Firefox hands a restored state to the wrong control when tags upgrade out of document order\n\tformStateRestoreCallback(state: File | FormData | null | string): void {\n\t\tconst prefix = `${this.localName}:`;\n\n\t\tif (typeof state === 'string' && state.startsWith(prefix)) {\n\t\t\tthis.restoreState(state.slice(prefix.length));\n\t\t}\n\t}\n\n\tprotected activate(): void {\n\t\tthis.focus();\n\t}\n\n\tprotected override namingLabels(): Array<Element> {\n\t\tconst internals = this.internals;\n\t\tif (!internals || this.hasAttribute('aria-label') || this.hasAttribute('aria-labelledby')) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn [...internals.labels].filter((label) => label instanceof Element);\n\t}\n\n\tprotected abstract render(): void;\n\n\tprotected abstract restoreState(state: string): void;\n\n\tprotected writeFormValue(value: FormData | null | string, state: string): void {\n\t\tthis.internals?.setFormValue(value, `${this.localName}:${state}`);\n\t}\n}\n"],"mappings":";;;AAEA,IAAsB,mBAAtB,cAA+C,aAAa;CAC3D,OAAgB,iBAAiB;CAEjC,IAAI,OAA+B;EAElC,OAAO,KAAK,WAAW,QAAQ;CAChC;CAEA,IAAI,SAA0B;EAE7B,OAAO,KAAK,WAAW,UAAU;CAClC;CAEA,IAAI,OAAe;EAClB,OAAO,KAAK,aAAa,MAAM,KAAK;CACrC;CAEA,IAAI,KAAK,OAA2B;EACnC,KAAK,QAAQ,QAAQ,KAAK;CAC3B;CAEA,cAAc;EACb,MAAM;EAGN,IAAI,KAAK,WAAW,KAAK,UAAU,OAAO;EAG1C,KAAK,iBAAiB,UAAU,UAAU;GACzC,IAAI,MAAM,WAAW,MAAM,KAAK,SAAS;EAC1C,CAAC;EAGD,KAAK,iBAAiB,iBAAiB;GACtC,KAAK,OAAO;EACb,CAAC;CACF;CAIA,AAAS,oBAA0B;EAClC,KAAK,kBAAkB,MAAM;EAC7B,MAAM,kBAAkB;CACzB;CAGA,uBAA6B;EAC5B,KAAK,yBAAyB,UAAU;CACzC;CAEA,oBAA0B;EACzB,KAAK,yBAAyB,OAAO;CACtC;CAGA,yBAAyB,OAA8C;EACtE,MAAM,SAAS,GAAG,KAAK,UAAU;EAEjC,IAAI,OAAO,UAAU,YAAY,MAAM,WAAW,MAAM,GACvD,KAAK,aAAa,MAAM,MAAM,OAAO,MAAM,CAAC;CAE9C;CAEA,AAAU,WAAiB;EAC1B,KAAK,MAAM;CACZ;CAEA,AAAmB,eAA+B;EACjD,MAAM,YAAY,KAAK;EACvB,IAAI,CAAC,aAAa,KAAK,aAAa,YAAY,KAAK,KAAK,aAAa,iBAAiB,GACvF,OAAO,CAAC;EAGT,OAAO,CAAC,GAAG,UAAU,MAAM,CAAC,CAAC,QAAQ,UAAU,iBAAiB,OAAO;CACxE;CAMA,AAAU,eAAe,OAAiC,OAAqB;EAC9E,KAAK,WAAW,aAAa,OAAO,GAAG,KAAK,UAAU,GAAG,OAAO;CACjE;AACD"}