@xsynaptic/sonic-ui 0.6.0 → 0.6.1
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.
- package/dist/default/elements/button.js +3 -2
- package/dist/default/elements/dial.js +5 -1
- package/dist/default/elements/envelope.js +14 -2
- package/dist/default/elements/meter.js +1 -1
- package/dist/default/elements/radio-group.js +3 -2
- package/dist/default/elements/readout-claim.js +0 -29
- package/dist/default/elements/scale.js +43 -0
- package/dist/default/elements/slider.js +16 -3
- package/dist/default/elements/sonic-element.js +2 -67
- package/dist/default/elements/switch.js +1 -1
- package/dist/default/elements/value-element.js +35 -83
- package/dist/default/elements/wavestrip.js +42 -4
- package/dist/default/elements/xy.js +2 -1
- package/dist/default/lib/mirror-children.js +64 -0
- package/dist/default/lib/owned-control.js +10 -0
- package/dist/default/lib/time-regions.js +4 -1
- package/dist/dev/elements/button.js +3 -2
- package/dist/dev/elements/button.js.map +1 -1
- package/dist/dev/elements/dial.js +5 -1
- package/dist/dev/elements/dial.js.map +1 -1
- package/dist/dev/elements/envelope.js +14 -2
- package/dist/dev/elements/envelope.js.map +1 -1
- package/dist/dev/elements/meter.js +1 -1
- package/dist/dev/elements/radio-group.js +3 -2
- package/dist/dev/elements/radio-group.js.map +1 -1
- package/dist/dev/elements/readout-claim.js +0 -29
- package/dist/dev/elements/readout-claim.js.map +1 -1
- package/dist/dev/elements/scale.js +44 -0
- package/dist/dev/elements/scale.js.map +1 -0
- package/dist/dev/elements/slider.d.ts +3 -0
- package/dist/dev/elements/slider.js +16 -3
- package/dist/dev/elements/slider.js.map +1 -1
- package/dist/dev/elements/sonic-element.d.ts +0 -8
- package/dist/dev/elements/sonic-element.js +3 -90
- package/dist/dev/elements/sonic-element.js.map +1 -1
- package/dist/dev/elements/switch.js +1 -1
- package/dist/dev/elements/value-element.d.ts +3 -5
- package/dist/dev/elements/value-element.js +35 -83
- package/dist/dev/elements/value-element.js.map +1 -1
- package/dist/dev/elements/wavestrip.d.ts +4 -0
- package/dist/dev/elements/wavestrip.js +42 -4
- package/dist/dev/elements/wavestrip.js.map +1 -1
- package/dist/dev/elements/xy.js +2 -1
- package/dist/dev/elements/xy.js.map +1 -1
- package/dist/dev/lib/mirror-children.js +80 -0
- package/dist/dev/lib/mirror-children.js.map +1 -0
- package/dist/dev/lib/owned-control.js +23 -0
- package/dist/dev/lib/owned-control.js.map +1 -0
- package/dist/dev/lib/time-regions.js +4 -1
- package/dist/dev/lib/time-regions.js.map +1 -1
- package/dist/skins/flat.css +2 -1
- package/dist/styles/button.css +21 -0
- package/dist/styles/envelope.css +30 -30
- package/dist/styles/led.css +18 -2
- package/dist/styles/material.css +72 -26
- package/dist/styles/panel.css +2 -1
- package/dist/styles/switch.css +10 -7
- package/dist/styles/xy.css +14 -30
- package/package.json +1 -1
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { clamp, toNumber } from "../lib/math.js";
|
|
2
|
-
import { placeChildren, requireChild } from "../lib/render.js";
|
|
3
2
|
import { writeAttribute } from "../lib/write-attribute.js";
|
|
4
3
|
import { SonicFormElement } from "./form-element.js";
|
|
5
|
-
import {
|
|
4
|
+
import { requireChild } from "../lib/render.js";
|
|
6
5
|
import { ReadoutClaim } from "./readout-claim.js";
|
|
7
6
|
import { Readout } from "./readout.js";
|
|
8
7
|
import { ValueEntry } from "./value-entry.js";
|
|
@@ -12,7 +11,6 @@ import { isMenuPress, isResetPress } from "../lib/modifier-press.js";
|
|
|
12
11
|
import { parseNumberList } from "../lib/number-list.js";
|
|
13
12
|
import { bindDrag } from "../lib/pointer-drag.js";
|
|
14
13
|
import { readPxProperty } from "../lib/read-px-property.js";
|
|
15
|
-
import { readRegions } from "../lib/time-regions.js";
|
|
16
14
|
import { resetKeys, valueMapping } from "../lib/value-mapping.js";
|
|
17
15
|
|
|
18
16
|
//#region src/elements/value-element.ts
|
|
@@ -37,18 +35,6 @@ const roleAttributes = [
|
|
|
37
35
|
"role",
|
|
38
36
|
"tabindex"
|
|
39
37
|
];
|
|
40
|
-
function scaleValue(mark) {
|
|
41
|
-
const text = mark.dataset.sonicValue?.trim();
|
|
42
|
-
return text ? Number(text) : NaN;
|
|
43
|
-
}
|
|
44
|
-
function scaleMark(original) {
|
|
45
|
-
const mark = copyNode(original);
|
|
46
|
-
if (!(mark instanceof HTMLElement || mark instanceof SVGElement)) return void 0;
|
|
47
|
-
if (!Number.isFinite(scaleValue(mark))) return void 0;
|
|
48
|
-
const isTick = mark.childElementCount === 0 && mark.textContent.trim() === "";
|
|
49
|
-
mark.classList.add(isTick ? "sonic-scale-tick" : "sonic-scale-label");
|
|
50
|
-
return mark;
|
|
51
|
-
}
|
|
52
38
|
let link;
|
|
53
39
|
function linkValue(element) {
|
|
54
40
|
return link(element);
|
|
@@ -64,6 +50,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
64
50
|
"origin",
|
|
65
51
|
"readout",
|
|
66
52
|
"step",
|
|
53
|
+
"tabindex",
|
|
67
54
|
"taper",
|
|
68
55
|
"value",
|
|
69
56
|
"positions"
|
|
@@ -89,13 +76,6 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
89
76
|
}
|
|
90
77
|
});
|
|
91
78
|
}
|
|
92
|
-
get buffered() {
|
|
93
|
-
return this.#buffered.map(([start, end]) => [start, end]);
|
|
94
|
-
}
|
|
95
|
-
set buffered(regions) {
|
|
96
|
-
this.#buffered = regions ? readRegions(regions).toSorted((first, second) => first[0] - second[0]) : [];
|
|
97
|
-
this.render();
|
|
98
|
-
}
|
|
99
79
|
get default() {
|
|
100
80
|
return this.optionalNumberAttribute("default");
|
|
101
81
|
}
|
|
@@ -220,12 +200,10 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
220
200
|
return this.#textFor(this.#value);
|
|
221
201
|
}
|
|
222
202
|
#asked;
|
|
223
|
-
#buffered = [];
|
|
224
203
|
#claim = new ReadoutClaim(() => {
|
|
225
204
|
this.#renderHold();
|
|
226
205
|
});
|
|
227
206
|
#entry;
|
|
228
|
-
#escapeWatch;
|
|
229
207
|
#formatSpokenValue;
|
|
230
208
|
#formatValue;
|
|
231
209
|
#instance = String(instanceCount += 1);
|
|
@@ -239,7 +217,6 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
239
217
|
#pointerDrag;
|
|
240
218
|
#positions;
|
|
241
219
|
#readout;
|
|
242
|
-
#scaleMarks;
|
|
243
220
|
#value = 0;
|
|
244
221
|
#watchers = /* @__PURE__ */ new Set();
|
|
245
222
|
attributeChangedCallback(name) {
|
|
@@ -258,7 +235,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
258
235
|
this.render();
|
|
259
236
|
}
|
|
260
237
|
connectedCallback() {
|
|
261
|
-
this.upgradeProperties("
|
|
238
|
+
this.upgradeProperties("default", "dimmed", "doublePress", "max", "midpoint", "min", "notched", "origin", "readout", "step", "taper", "positions", "detent", "formatValue", "formatSpokenValue", "keyStep", "parseValue", "value");
|
|
262
239
|
super.connectedCallback();
|
|
263
240
|
}
|
|
264
241
|
bindGestures(control, signal, grab) {
|
|
@@ -322,19 +299,6 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
322
299
|
this.#concealKeyReveal();
|
|
323
300
|
}, { once: true });
|
|
324
301
|
}
|
|
325
|
-
bindScale(control, marks, signal) {
|
|
326
|
-
this.#scaleMarks = marks;
|
|
327
|
-
this.mirrorChildren({
|
|
328
|
-
control,
|
|
329
|
-
copy: scaleMark,
|
|
330
|
-
isCopied: (child) => child instanceof Element && child.matches("[data-sonic-value]"),
|
|
331
|
-
isPassed: (child) => child instanceof Element && child.matches(".sonic-led"),
|
|
332
|
-
place: (copies) => {
|
|
333
|
-
placeChildren(marks, copies);
|
|
334
|
-
this.#renderScale();
|
|
335
|
-
}
|
|
336
|
-
}, signal);
|
|
337
|
-
}
|
|
338
302
|
controlOrientation() {}
|
|
339
303
|
controlRole() {
|
|
340
304
|
return "slider";
|
|
@@ -344,11 +308,6 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
344
308
|
}
|
|
345
309
|
heldWrite(_next) {}
|
|
346
310
|
holdChanged() {}
|
|
347
|
-
hoverReadout(value) {
|
|
348
|
-
this.#claim.hover(value);
|
|
349
|
-
this.#renderReadout();
|
|
350
|
-
this.#watchEscape(value !== void 0);
|
|
351
|
-
}
|
|
352
311
|
input(next) {
|
|
353
312
|
const previous = this.#value;
|
|
354
313
|
this.#write(this.#limit ? clamp(next, ...this.#limit) : next);
|
|
@@ -359,6 +318,9 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
359
318
|
}));
|
|
360
319
|
return true;
|
|
361
320
|
}
|
|
321
|
+
isEditing() {
|
|
322
|
+
return this.#entry?.isOpen === true;
|
|
323
|
+
}
|
|
362
324
|
isRevealed() {
|
|
363
325
|
return this.#claim.isRevealed;
|
|
364
326
|
}
|
|
@@ -384,17 +346,28 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
384
346
|
originValue() {
|
|
385
347
|
return this.origin ?? this.mapping().bounds[0];
|
|
386
348
|
}
|
|
349
|
+
previewValue() {}
|
|
387
350
|
proportionsChanged() {}
|
|
388
351
|
readModulationValue() {
|
|
389
352
|
return this.#modulationValue;
|
|
390
353
|
}
|
|
391
354
|
readoutValue() {
|
|
392
|
-
return this.#
|
|
355
|
+
return this.#shown().value ?? this.#value;
|
|
393
356
|
}
|
|
394
357
|
render() {
|
|
395
358
|
if (this.isBound()) this.#renderControl();
|
|
396
359
|
for (const listener of this.#watchers) listener();
|
|
397
360
|
}
|
|
361
|
+
renderReadout() {
|
|
362
|
+
const readout = this.#readout;
|
|
363
|
+
if (!readout) return;
|
|
364
|
+
const { isOpen, value } = this.#shown();
|
|
365
|
+
readout.bubble.show({
|
|
366
|
+
anchor: readout.anchor,
|
|
367
|
+
isOpen,
|
|
368
|
+
text: value === void 0 ? void 0 : this.#textFor(value)
|
|
369
|
+
});
|
|
370
|
+
}
|
|
398
371
|
restoreState(state) {
|
|
399
372
|
this.value = Number(state);
|
|
400
373
|
}
|
|
@@ -440,7 +413,6 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
440
413
|
},
|
|
441
414
|
text: () => this.#parseValue ? this.valueText : String(this.#value),
|
|
442
415
|
toggle: (isOpen) => {
|
|
443
|
-
this.#claim.edit(isOpen);
|
|
444
416
|
if (isOpen) this.forwardNaming(input, true);
|
|
445
417
|
this.toggleState("editing", isOpen);
|
|
446
418
|
this.render();
|
|
@@ -545,7 +517,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
545
517
|
if (this.#entry?.isOpen) {
|
|
546
518
|
for (const name of roleAttributes) control.removeAttribute(name);
|
|
547
519
|
this.forwardNaming(control, false);
|
|
548
|
-
this
|
|
520
|
+
this.renderReadout();
|
|
549
521
|
return;
|
|
550
522
|
}
|
|
551
523
|
const [low, high] = this.mapping().bounds;
|
|
@@ -557,18 +529,18 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
557
529
|
writeAttribute(control, "aria-valuetext", (this.#formatSpokenValue ?? this.#formatValue)?.(this.#value));
|
|
558
530
|
this.forwardNaming(control, true);
|
|
559
531
|
this.#renderDisabled(control);
|
|
560
|
-
this
|
|
532
|
+
this.renderReadout();
|
|
561
533
|
}
|
|
562
534
|
#renderControl() {
|
|
563
535
|
this.draw();
|
|
564
|
-
this.#renderScale();
|
|
565
536
|
this.toggleState("at-origin", !this.isWrapping() && this.#value === this.mapping().snap(this.originValue()));
|
|
566
537
|
this.#renderAria(this.focusTarget(), this.controlOrientation());
|
|
567
538
|
}
|
|
568
539
|
#renderDisabled(control) {
|
|
569
540
|
const isDisabled = this.isDisabled();
|
|
570
541
|
writeAttribute(control, "aria-disabled", isDisabled ? "true" : void 0);
|
|
571
|
-
|
|
542
|
+
const stop = this.getAttribute("tabindex") === "-1" ? "-1" : "0";
|
|
543
|
+
writeAttribute(control, "tabindex", isDisabled ? void 0 : stop);
|
|
572
544
|
}
|
|
573
545
|
#renderDragReveal(drag) {
|
|
574
546
|
if (drag.isRevealed && !drag.isOutside) this.#claim.reveal("drag");
|
|
@@ -576,28 +548,9 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
576
548
|
this.#renderHold();
|
|
577
549
|
}
|
|
578
550
|
#renderHold() {
|
|
579
|
-
this
|
|
551
|
+
this.renderReadout();
|
|
580
552
|
this.holdChanged();
|
|
581
553
|
}
|
|
582
|
-
#renderReadout() {
|
|
583
|
-
const readout = this.#readout;
|
|
584
|
-
if (!readout) return;
|
|
585
|
-
const { isOpen, value } = this.#claim.shown(this.#value, this.readout);
|
|
586
|
-
readout.bubble.show({
|
|
587
|
-
anchor: readout.anchor,
|
|
588
|
-
isOpen,
|
|
589
|
-
text: value === void 0 ? void 0 : this.#textFor(value)
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
#renderScale() {
|
|
593
|
-
const marks = this.#scaleMarks?.children ?? [];
|
|
594
|
-
const mapping = this.mapping();
|
|
595
|
-
for (const mark of marks) {
|
|
596
|
-
if (!(mark instanceof HTMLElement || mark instanceof SVGElement)) continue;
|
|
597
|
-
const at = String(mapping.proportionOf(scaleValue(mark)));
|
|
598
|
-
if (mark.style.getPropertyValue("--_sonic-scale-at") !== at) mark.style.setProperty("--_sonic-scale-at", at);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
554
|
#reset() {
|
|
602
555
|
this.#commit(this.default ?? NaN);
|
|
603
556
|
}
|
|
@@ -616,6 +569,18 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
616
569
|
}
|
|
617
570
|
this.input(next);
|
|
618
571
|
}
|
|
572
|
+
#shown() {
|
|
573
|
+
if (this.isEditing()) return {
|
|
574
|
+
isOpen: true,
|
|
575
|
+
value: void 0
|
|
576
|
+
};
|
|
577
|
+
const isRevealed = this.#claim.isRevealed;
|
|
578
|
+
const preview = isRevealed ? void 0 : this.previewValue();
|
|
579
|
+
return {
|
|
580
|
+
isOpen: (isRevealed || preview !== void 0) && this.readout,
|
|
581
|
+
value: preview ?? this.#value
|
|
582
|
+
};
|
|
583
|
+
}
|
|
619
584
|
#springBack() {
|
|
620
585
|
const target = this.springTarget();
|
|
621
586
|
if (target === void 0) return;
|
|
@@ -645,19 +610,6 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
645
610
|
#textFor(value) {
|
|
646
611
|
return this.#formatValue?.(value) ?? String(value);
|
|
647
612
|
}
|
|
648
|
-
#watchEscape(isHovered) {
|
|
649
|
-
if (!isHovered) {
|
|
650
|
-
this.#escapeWatch?.abort();
|
|
651
|
-
this.#escapeWatch = void 0;
|
|
652
|
-
return;
|
|
653
|
-
}
|
|
654
|
-
if (this.#escapeWatch) return;
|
|
655
|
-
const watch = new AbortController();
|
|
656
|
-
this.#escapeWatch = watch;
|
|
657
|
-
this.ownerDocument.addEventListener("keydown", (event) => {
|
|
658
|
-
if (event.key === "Escape" && this.#claim.dismiss()) this.#renderHold();
|
|
659
|
-
}, { signal: watch.signal });
|
|
660
|
-
}
|
|
661
613
|
#withinLimit(mapping, state) {
|
|
662
614
|
const limit = this.#limit;
|
|
663
615
|
if (!limit || mapping.isWrapping) return state;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"value-element.js","names":[],"sources":["../../../src/elements/value-element.ts"],"sourcesContent":["import type { DragState } from '#lib/drag-step.ts';\nimport type { PointerDrag } from '#lib/pointer-drag.ts';\nimport type { TimeRegions } from '#lib/time-regions.ts';\nimport type { ValueMapping } from '#lib/value-mapping.ts';\n\nimport { SonicFormElement } from '#elements/form-element.ts';\nimport { ReadoutClaim, revealMs } from '#elements/readout-claim.ts';\nimport { Readout } from '#elements/readout.ts';\nimport { ValueEntry } from '#elements/value-entry.ts';\nimport { copyNode } from '#lib/copy-node.ts';\nimport { dragThresholdPx, startDrag, stepDrag } from '#lib/drag-step.ts';\nimport { focusByPointer } from '#lib/focus-by-pointer.ts';\nimport { clamp, toNumber } from '#lib/math.ts';\nimport { isMenuPress, isResetPress } from '#lib/modifier-press.ts';\nimport { parseNumberList } from '#lib/number-list.ts';\nimport { bindDrag } from '#lib/pointer-drag.ts';\nimport { readPxProperty } from '#lib/read-px-property.ts';\nimport { placeChildren, requireChild } from '#lib/render.ts';\nimport { readRegions } from '#lib/time-regions.ts';\nimport { resetKeys, valueMapping } from '#lib/value-mapping.ts';\nimport { writeAttribute } from '#lib/write-attribute.ts';\n\nexport interface ValueAxis {\n\tfromProportion?: number;\n\tisKeptOnCancel?: boolean;\n\toutside?: (event: PointerEvent) => boolean;\n\tposition: (event: PointerEvent) => number;\n\ttravelPx: number;\n}\n\ninterface ValueDrag extends ValueAxis {\n\tfromValue: number;\n\tisOutside: boolean;\n\tisRevealed: boolean;\n\trevealTimer: ReturnType<typeof setTimeout> | undefined;\n\tstate: DragState;\n}\n\ninterface KeyScrub {\n\tfromValue: number;\n\tkey: string;\n}\n\nconst detentZonePx = 8;\nconst fallbackTravelPx = 160;\n\nlet instanceCount = 0;\n\nconst proportionAttributes = new Set(['max', 'midpoint', 'min', 'notched', 'positions', 'taper']);\n\nconst roleAttributes = [\n\t'aria-disabled',\n\t'aria-orientation',\n\t'aria-valuemax',\n\t'aria-valuemin',\n\t'aria-valuenow',\n\t'aria-valuetext',\n\t'role',\n\t'tabindex',\n];\n\ntype ScaleMark = HTMLElement | SVGElement;\n\nfunction scaleValue(mark: ScaleMark): number {\n\tconst text = mark.dataset.sonicValue?.trim();\n\n\treturn text ? Number(text) : NaN;\n}\n\nfunction scaleMark(original: ChildNode): ScaleMark | undefined {\n\tconst mark = copyNode(original);\n\tif (!(mark instanceof HTMLElement || mark instanceof SVGElement)) return undefined;\n\tif (!Number.isFinite(scaleValue(mark))) return undefined;\n\n\tconst isTick = mark.childElementCount === 0 && mark.textContent.trim() === '';\n\n\tmark.classList.add(isTick ? 'sonic-scale-tick' : 'sonic-scale-label');\n\n\treturn mark;\n}\n\ntype ValueLanding = (target: number, direction: -1 | 0 | 1) => number;\n\nexport interface ValueLink {\n\tinput: (next: number, isMover?: boolean) => boolean;\n\tisDisabled: () => boolean;\n\tisHeld: () => boolean;\n\tland: (resolve: undefined | ValueLanding) => void;\n\tlimit: (bounds: [number, number] | undefined) => void;\n\tmapping: () => ValueMapping;\n\tvalue: () => number;\n\twatch: (listener: () => void) => () => void;\n}\n\n// Filled from inside the class, so it reaches protected members and nothing lands on the element's public type\nlet link: (element: SonicValueElement) => ValueLink;\n\nexport function linkValue(element: SonicValueElement): ValueLink {\n\treturn link(element);\n}\n\nexport abstract class SonicValueElement extends SonicFormElement {\n\tstatic override readonly observedAttributes = [\n\t\t...SonicFormElement.observedAttributes,\n\t\t'detent',\n\t\t'max',\n\t\t'midpoint',\n\t\t'min',\n\t\t'notched',\n\t\t'origin',\n\t\t'readout',\n\t\t'step',\n\t\t'taper',\n\t\t'value',\n\t\t'positions',\n\t];\n\n\tstatic {\n\t\tlink = (element) => ({\n\t\t\tinput: (next, isMover = false) => (isMover || !element.#isHeld()) && element.input(next),\n\t\t\tisDisabled: () => element.isDisabled(),\n\t\t\tisHeld: () => element.#isHeld(),\n\t\t\tland: (resolve) => {\n\t\t\t\telement.#land = resolve;\n\t\t\t},\n\t\t\tlimit: (bounds) => {\n\t\t\t\telement.#limit = bounds;\n\t\t\t},\n\t\t\tmapping: () => element.mapping(),\n\t\t\tvalue: () => element.#value,\n\t\t\twatch: (listener) => {\n\t\t\t\telement.#watchers.add(listener);\n\n\t\t\t\treturn () => {\n\t\t\t\t\telement.#watchers.delete(listener);\n\t\t\t\t};\n\t\t\t},\n\t\t});\n\t}\n\n\tget buffered(): Array<[number, number]> {\n\t\treturn this.#buffered.map(([start, end]) => [start, end]);\n\t}\n\n\tset buffered(regions: TimeRegions | undefined) {\n\t\tthis.#buffered = regions\n\t\t\t? readRegions(regions).toSorted((first, second) => first[0] - second[0])\n\t\t\t: [];\n\t\tthis.render();\n\t}\n\n\tget default(): number | undefined {\n\t\treturn this.optionalNumberAttribute('default');\n\t}\n\n\tset default(value: number | undefined) {\n\t\tthis.reflect('default', value);\n\t}\n\n\tget detent(): number | undefined {\n\t\treturn this.optionalNumberAttribute('detent');\n\t}\n\n\tset detent(value: number | undefined) {\n\t\tthis.reflect('detent', value);\n\t}\n\n\tget dimmed(): boolean {\n\t\treturn this.hasAttribute('dimmed');\n\t}\n\n\tset dimmed(isDimmed: boolean) {\n\t\tthis.reflect('dimmed', isDimmed);\n\t}\n\n\tget doublePress(): 'entry' | 'reset' {\n\t\treturn this.getAttribute('double-press') === 'reset' ? 'reset' : 'entry';\n\t}\n\n\tset doublePress(gesture: 'entry' | 'reset' | undefined) {\n\t\tthis.reflect('double-press', gesture);\n\t}\n\n\tget formatSpokenValue(): ((value: number) => string) | undefined {\n\t\treturn this.#formatSpokenValue;\n\t}\n\n\tset formatSpokenValue(format: ((value: number) => string) | undefined) {\n\t\tthis.#formatSpokenValue = format;\n\t\tthis.render();\n\t}\n\n\tget formatValue(): ((value: number) => string) | undefined {\n\t\treturn this.#formatValue;\n\t}\n\n\tset formatValue(format: ((value: number) => string) | undefined) {\n\t\tthis.#formatValue = format;\n\t\tthis.render();\n\t}\n\n\tget keyStep(): number | undefined {\n\t\treturn this.optionalNumberAttribute('key-step');\n\t}\n\n\tset keyStep(value: number | undefined) {\n\t\tthis.reflect('key-step', value);\n\t}\n\n\tget max(): number {\n\t\treturn this.numberAttribute('max', 100);\n\t}\n\n\tset max(value: number | undefined) {\n\t\tthis.reflect('max', value);\n\t}\n\n\tget midpoint(): number | undefined {\n\t\treturn this.optionalNumberAttribute('midpoint');\n\t}\n\n\tset midpoint(value: number | undefined) {\n\t\tthis.reflect('midpoint', value);\n\t}\n\n\tget min(): number {\n\t\treturn this.numberAttribute('min', 0);\n\t}\n\n\tset min(value: number | undefined) {\n\t\tthis.reflect('min', value);\n\t}\n\n\tget notched(): boolean {\n\t\treturn this.hasAttribute('notched');\n\t}\n\n\tset notched(isNotched: boolean) {\n\t\tthis.reflect('notched', isNotched);\n\t}\n\n\tget origin(): number | undefined {\n\t\treturn this.optionalNumberAttribute('origin');\n\t}\n\n\tset origin(value: number | undefined) {\n\t\tthis.reflect('origin', value);\n\t}\n\n\tget parseValue(): ((text: string) => number) | undefined {\n\t\treturn this.#parseValue;\n\t}\n\n\tset parseValue(parse: ((text: string) => number) | undefined) {\n\t\tthis.#parseValue = parse;\n\t}\n\n\tget positions(): Array<number> | undefined {\n\t\treturn parseNumberList(this.getAttribute('positions'));\n\t}\n\n\tset positions(positions: Array<number> | undefined) {\n\t\tthis.reflect('positions', positions?.join(' '));\n\t}\n\n\tget readout(): boolean {\n\t\treturn this.hasAttribute('readout');\n\t}\n\n\tset readout(isShown: boolean) {\n\t\tthis.reflect('readout', isShown);\n\t}\n\n\tget step(): number {\n\t\treturn this.numberAttribute('step', 1);\n\t}\n\n\tset step(value: number | undefined) {\n\t\tthis.reflect('step', value);\n\t}\n\n\tget taper(): 'linear' | 'log' {\n\t\treturn this.getAttribute('taper') === 'log' ? 'log' : 'linear';\n\t}\n\n\tset taper(curve: 'linear' | 'log' | undefined) {\n\t\tthis.reflect('taper', curve);\n\t}\n\n\tget value(): number {\n\t\treturn this.#value;\n\t}\n\n\tset value(next: null | number | undefined) {\n\t\t// A framework removes a prop by setting the property to `undefined`\n\t\tif (next === undefined || next === null) {\n\t\t\tthis.formResetCallback();\n\t\t\treturn;\n\t\t}\n\n\t\tconst value = toNumber(next);\n\n\t\tif (this.#isHeld()) {\n\t\t\tthis.heldWrite(value);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#write(value);\n\t\tif (Number.isFinite(value)) this.#asked = value;\n\t}\n\n\tget valueText(): string {\n\t\treturn this.#textFor(this.#value);\n\t}\n\n\t#asked: number | undefined;\n\n\t#buffered: Array<[number, number]> = [];\n\n\treadonly #claim = new ReadoutClaim(() => {\n\t\tthis.#renderHold();\n\t});\n\n\t#entry: undefined | ValueEntry;\n\n\t#escapeWatch: AbortController | undefined;\n\n\t#formatSpokenValue: ((value: number) => string) | undefined;\n\n\t#formatValue: ((value: number) => string) | undefined;\n\n\treadonly #instance = String((instanceCount += 1));\n\n\t#isModulated = false;\n\n\t#keyScrub: KeyScrub | undefined;\n\n\t#land: undefined | ValueLanding;\n\n\t#limit: [number, number] | undefined;\n\n\t// Every attribute it reads is observed; a subclass adding an input to `isWrapping()` has to observe it\n\t#mapping: undefined | ValueMapping;\n\n\t#modulationValue: number | undefined;\n\n\t#parseValue: ((text: string) => number) | undefined;\n\n\t#pointerDrag: PointerDrag<ValueDrag> | undefined;\n\n\t#positions: Array<number> | undefined;\n\n\t#readout: undefined | { anchor: HTMLElement; bubble: Readout };\n\n\t#scaleMarks: HTMLElement | undefined;\n\n\t#value = 0;\n\n\treadonly #watchers = new Set<() => void>();\n\n\tattributeChangedCallback(name: string): void {\n\t\tthis.#mapping = undefined;\n\t\tthis.#positions = parseNumberList(this.getAttribute('positions'));\n\t\tif (name === 'value') {\n\t\t\tif (this.#isHeld()) {\n\t\t\t\tthis.heldWrite(this.numberAttribute('value', this.min));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.#asked = undefined;\n\t\t}\n\t\tif (name === 'disabled' && this.isDisabled()) this.#endHolds();\n\n\t\tthis.#value = this.mapping().snap(this.#asked ?? this.numberAttribute('value', this.min));\n\t\tif (proportionAttributes.has(name) && this.isBound()) this.proportionsChanged();\n\t\tthis.render();\n\t}\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties(\n\t\t\t'buffered',\n\t\t\t'default',\n\t\t\t'dimmed',\n\t\t\t'doublePress',\n\t\t\t'max',\n\t\t\t'midpoint',\n\t\t\t'min',\n\t\t\t'notched',\n\t\t\t'origin',\n\t\t\t'readout',\n\t\t\t'step',\n\t\t\t'taper',\n\t\t\t'positions',\n\t\t\t'detent',\n\t\t\t'formatValue',\n\t\t\t'formatSpokenValue',\n\t\t\t'keyStep',\n\t\t\t'parseValue',\n\t\t\t'value',\n\t\t);\n\t\tsuper.connectedCallback();\n\t}\n\n\tprotected bindGestures(\n\t\tcontrol: HTMLElement,\n\t\tsignal: AbortSignal,\n\t\tgrab: (event: PointerEvent) => undefined | ValueAxis,\n\t): void {\n\t\tconst entry = this.#bindEntry(control, signal);\n\n\t\tthis.#pointerDrag = bindDrag<ValueDrag>(\n\t\t\tcontrol,\n\t\t\t{\n\t\t\t\tcancel: (drag) => {\n\t\t\t\t\tif (drag.isKeptOnCancel !== true) this.input(drag.fromValue);\n\t\t\t\t},\n\t\t\t\tgrab: (event) => {\n\t\t\t\t\tif (isMenuPress(event) || this.isDisabled() || entry.isOpen) return;\n\n\t\t\t\t\tthis.toggleState('springing', false);\n\t\t\t\t\t// A click listener above makes WebKit send a tap's compatibility mousedown, which blurs the entry a double tap just opened\n\t\t\t\t\tif (event.pointerType === 'touch') event.preventDefault();\n\t\t\t\t\tfocusByPointer(control);\n\t\t\t\t\tif (isResetPress(event)) {\n\t\t\t\t\t\tthis.#reset();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst fromValue = this.#value;\n\t\t\t\t\tconst axis = grab(event);\n\t\t\t\t\tif (!axis) return;\n\n\t\t\t\t\tconst drag: ValueDrag = {\n\t\t\t\t\t\t...axis,\n\t\t\t\t\t\tfromValue,\n\t\t\t\t\t\tisOutside: false,\n\t\t\t\t\t\tisRevealed: false,\n\t\t\t\t\t\trevealTimer: undefined,\n\t\t\t\t\t\tstate: this.#startDrag(control, axis, event),\n\t\t\t\t\t};\n\n\t\t\t\t\tdrag.revealTimer = setTimeout(() => {\n\t\t\t\t\t\tthis.#reveal(drag);\n\t\t\t\t\t}, revealMs);\n\n\t\t\t\t\treturn drag;\n\t\t\t\t},\n\t\t\t\tlift: (drag, event) => {\n\t\t\t\t\tconst tap = drag.state.isEngaged ? undefined : this.tapTarget();\n\n\t\t\t\t\tif (tap !== undefined) {\n\t\t\t\t\t\tentry.forgetPress();\n\t\t\t\t\t\tthis.#commit(tap);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (!entry.press(event) || this.springTarget() !== undefined) return;\n\n\t\t\t\t\tif (this.doublePress === 'reset') this.#reset();\n\t\t\t\t\telse entry.open();\n\t\t\t\t},\n\t\t\t\tmove: (drag, event) => {\n\t\t\t\t\tthis.#dragTo(drag, event);\n\t\t\t\t},\n\t\t\t\trelease: (drag) => {\n\t\t\t\t\tthis.#releaseDrag(drag);\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\tcontrol.addEventListener(\n\t\t\t'pointercancel',\n\t\t\t() => {\n\t\t\t\tentry.forgetPress();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tthis.#bindKeys(control, entry, signal);\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tthis.#endKeyScrub();\n\t\t\t\tthis.#concealKeyReveal();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\tprotected bindScale(control: HTMLElement, marks: HTMLElement, signal: AbortSignal): void {\n\t\tthis.#scaleMarks = marks;\n\t\tthis.mirrorChildren(\n\t\t\t{\n\t\t\t\tcontrol,\n\t\t\t\tcopy: scaleMark,\n\t\t\t\tisCopied: (child) => child instanceof Element && child.matches('[data-sonic-value]'),\n\t\t\t\tisPassed: (child) => child instanceof Element && child.matches('.sonic-led'),\n\t\t\t\tplace: (copies) => {\n\t\t\t\t\tplaceChildren(marks, copies);\n\t\t\t\t\tthis.#renderScale();\n\t\t\t\t},\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tprotected controlOrientation(): 'horizontal' | 'vertical' | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected controlRole(): 'slider' | 'spinbutton' {\n\t\treturn 'slider';\n\t}\n\n\tprotected abstract draw(): void;\n\n\tprotected abstract override focusTarget(): HTMLElement;\n\n\tprotected heldFrom(): number | undefined {\n\t\treturn this.#dragging()?.fromValue ?? this.#keyScrub?.fromValue;\n\t}\n\n\tprotected heldWrite(_next: number): void {\n\t\t// Dropped unless a subclass draws where playback carries on\n\t}\n\n\tprotected holdChanged(): void {\n\t\t// Only a subclass draws a hold\n\t}\n\n\tprotected hoverReadout(value: number | undefined): void {\n\t\tthis.#claim.hover(value);\n\t\tthis.#renderReadout();\n\t\tthis.#watchEscape(value !== undefined);\n\t}\n\n\tprotected input(next: number): boolean {\n\t\tconst previous = this.#value;\n\n\t\tthis.#write(this.#limit ? clamp(next, ...this.#limit) : next);\n\t\tif (this.#value === previous) return false;\n\n\t\tthis.dispatchEvent(new Event('input', { bubbles: true, composed: true }));\n\n\t\treturn true;\n\t}\n\n\tprotected isRevealed(): boolean {\n\t\treturn this.#claim.isRevealed;\n\t}\n\n\tprotected isWrapping(): boolean {\n\t\treturn false;\n\t}\n\n\tprotected mapping(): ValueMapping {\n\t\tif (this.#mapping) return this.#mapping;\n\n\t\tconst { detent, midpoint } = this;\n\n\t\tthis.#mapping = valueMapping({\n\t\t\t...(detent === undefined ? {} : { detent }),\n\t\t\t...(this.#positions ? { positions: this.#positions } : {}),\n\t\t\tmax: this.max,\n\t\t\t...(midpoint === undefined ? {} : { midpoint }),\n\t\t\tisNotched: this.notched,\n\t\t\tisWrapping: this.isWrapping(),\n\t\t\tmin: this.min,\n\t\t\tstep: this.step,\n\t\t\ttaper: this.taper,\n\t\t});\n\n\t\treturn this.#mapping;\n\t}\n\n\tprotected originValue(): number {\n\t\treturn this.origin ?? this.mapping().bounds[0];\n\t}\n\n\tprotected proportionsChanged(): void {\n\t\t// Runs when every proportion moves, never per input\n\t}\n\n\tprotected readModulationValue(): number | undefined {\n\t\treturn this.#modulationValue;\n\t}\n\n\tprotected readoutValue(): number {\n\t\treturn this.#claim.shown(this.#value, this.readout).value ?? this.#value;\n\t}\n\n\tprotected render(): void {\n\t\tif (this.isBound()) this.#renderControl();\n\t\tfor (const listener of this.#watchers) listener();\n\t}\n\n\tprotected restoreState(state: string): void {\n\t\tthis.value = Number(state);\n\t}\n\n\tprotected scrubsKeyRepeat(): boolean {\n\t\treturn false;\n\t}\n\n\tprotected springTarget(): number | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected tapTarget(): number | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected travelPx(control: HTMLElement, property: `--_sonic-${string}`): number {\n\t\treturn Math.max(1, readPxProperty(getComputedStyle(control), property, fallbackTravelPx));\n\t}\n\n\tprotected writeModulationValue(\n\t\tcontrol: HTMLElement,\n\t\tprefix: 'dial' | 'slider',\n\t\tnext: null | number | undefined,\n\t): void {\n\t\tconst value = next === undefined || next === null ? undefined : toNumber(next);\n\t\tif (value !== undefined && !Number.isFinite(value)) return;\n\n\t\tthis.#modulationValue = value;\n\t\tif (this.isBound()) this.#writeModulationProportion(control, prefix);\n\t}\n\n\tprotected writeProportions(\n\t\tcontrol: HTMLElement,\n\t\tprefix: 'dial' | 'slider',\n\t\tmodulation: number,\n\t): void {\n\t\tconst { style } = control;\n\t\tconst mapping = this.mapping();\n\t\tconst value = mapping.proportionOf(this.#value);\n\t\tconst reach = mapping.proportionOf(this.#value + modulation);\n\t\tconst { positionCount } = mapping;\n\n\t\tstyle.setProperty(`--_sonic-${prefix}-value`, String(value));\n\t\tstyle.setProperty(\n\t\t\t`--_sonic-${prefix}-origin`,\n\t\t\tString(mapping.proportionOf(this.originValue())),\n\t\t);\n\t\tstyle.setProperty(`--_sonic-${prefix}-modulation-from`, String(Math.min(value, reach)));\n\t\tstyle.setProperty(`--_sonic-${prefix}-modulation-to`, String(Math.max(value, reach)));\n\t\tif (positionCount === undefined) style.removeProperty(`--_sonic-${prefix}-position-count`);\n\t\telse style.setProperty(`--_sonic-${prefix}-position-count`, String(positionCount));\n\t\tthis.#writeModulationProportion(control, prefix);\n\t}\n\n\t#bindEntry(control: HTMLElement, signal: AbortSignal): ValueEntry {\n\t\tconst input = requireChild(control, 'input', HTMLInputElement);\n\t\tconst bubble = control.querySelector<HTMLElement>('[popover]');\n\n\t\t// Chrome's issues panel flags a form field with no id or name; a `name` would submit it\n\t\tinput.id = `sonic-entry-${this.#instance}`;\n\t\tif (bubble) this.#readout = { anchor: control, bubble: new Readout(bubble) };\n\n\t\tconst entry = new ValueEntry(input, {\n\t\t\tcommit: (text) => {\n\t\t\t\t// eslint-disable-next-line unicorn/prefer-number-coercion -- `Number('')` is 0; an emptied field should leave the value alone\n\t\t\t\tthis.#commit((this.#parseValue ?? Number.parseFloat)(text));\n\t\t\t},\n\t\t\t// `Number.parseFloat` reads \"5 kHz\" as 5\n\t\t\ttext: () => (this.#parseValue ? this.valueText : String(this.#value)),\n\t\t\ttoggle: (isOpen) => {\n\t\t\t\tthis.#claim.edit(isOpen);\n\t\t\t\tif (isOpen) this.forwardNaming(input, true);\n\t\t\t\tthis.toggleState('editing', isOpen);\n\t\t\t\tthis.render();\n\t\t\t},\n\t\t});\n\n\t\tthis.#entry = entry;\n\t\tentry.bind(control, signal);\n\n\t\treturn entry;\n\t}\n\n\t#bindKeys(control: HTMLElement, entry: ValueEntry, signal: AbortSignal): void {\n\t\tcontrol.addEventListener(\n\t\t\t'keydown',\n\t\t\t(event) => {\n\t\t\t\tif (this.isDisabled() || event.defaultPrevented || event.target !== control) return;\n\n\t\t\t\tthis.toggleState('springing', false);\n\t\t\t\tif (event.key === 'Enter') {\n\t\t\t\t\tif (this.springTarget() !== undefined) return;\n\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tentry.open();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst next = this.#keyTarget(event.key);\n\t\t\t\tif (next === undefined) return;\n\n\t\t\t\tevent.preventDefault();\n\t\t\t\tthis.#keyTo(event, next);\n\t\t\t\tthis.#claim.reveal('keys');\n\t\t\t\tthis.#renderHold();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tcontrol.addEventListener(\n\t\t\t'keyup',\n\t\t\t(event) => {\n\t\t\t\t// macOS sends no `keyup` for a key let go while Cmd is down\n\t\t\t\tconst isMeta = event.key === 'Meta';\n\n\t\t\t\tif (isMeta || event.key === this.#keyScrub?.key) this.#endKeyScrub();\n\t\t\t\tif (isMeta && this.#dragging()) return;\n\t\t\t\tif (isMeta || this.mapping().keyTarget(event.key, this.#value) !== undefined) {\n\t\t\t\t\tthis.#springBack();\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tcontrol.addEventListener(\n\t\t\t'blur',\n\t\t\t() => {\n\t\t\t\tthis.#endKeyScrub();\n\t\t\t\tthis.#concealKeyReveal();\n\t\t\t\tthis.#springBack();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t}\n\n\t#commit(next: number, direction: -1 | 0 | 1 = 0): void {\n\t\tconst landed = Number.isFinite(next) ? (this.#land?.(next, direction) ?? next) : next;\n\n\t\tif (this.input(landed)) this.dispatchEvent(new Event('change', { bubbles: true }));\n\t}\n\n\t#concealKeyReveal(): void {\n\t\tif (this.#claim.conceal('keys')) this.#renderHold();\n\t}\n\n\t#dragging(): undefined | ValueDrag {\n\t\treturn this.#pointerDrag?.current();\n\t}\n\n\t#dragTo(drag: ValueDrag, event: PointerEvent): void {\n\t\tconst isOutside = drag.outside?.(event) === true;\n\t\tconst wasEngaged = drag.state.isEngaged;\n\t\tconst mapping = this.mapping();\n\t\tconst { state, value } = stepDrag(mapping, drag.state, {\n\t\t\tisFine: event.shiftKey,\n\t\t\tisOutside,\n\t\t\tposition: drag.position(event),\n\t\t});\n\n\t\tdrag.state = this.#withinLimit(mapping, state);\n\t\tif (value === undefined) return;\n\n\t\tif (!wasEngaged) this.#reveal(drag);\n\t\tthis.input(isOutside ? drag.fromValue : value);\n\t\tif (isOutside === drag.isOutside) return;\n\n\t\tdrag.isOutside = isOutside;\n\t\tthis.#renderDragReveal(drag);\n\t}\n\n\t#endHolds(): void {\n\t\tthis.#entry?.close(false);\n\t\tthis.#pointerDrag?.end();\n\t\tthis.#endKeyScrub();\n\t}\n\n\t#endKeyScrub(): void {\n\t\tconst scrub = this.#keyScrub;\n\t\tif (!scrub) return;\n\n\t\tthis.#keyScrub = undefined;\n\t\tthis.#renderHold();\n\t\tif (this.#value !== scrub.fromValue) this.dispatchEvent(new Event('change', { bubbles: true }));\n\t}\n\n\t#isHeld(): boolean {\n\t\treturn this.#dragging() !== undefined || this.#keyScrub !== undefined;\n\t}\n\n\t#keyTarget(key: string): number | undefined {\n\t\tif (resetKeys.has(key)) return this.default;\n\n\t\treturn this.mapping().keyTarget(key, this.#value, this.keyStep);\n\t}\n\n\t#keyTo(event: KeyboardEvent, next: number): void {\n\t\tif (event.repeat && this.scrubsKeyRepeat()) {\n\t\t\tthis.#scrubKey(event.key, next);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#endKeyScrub();\n\t\tthis.#commit(next, next > this.#value ? 1 : -1);\n\t}\n\n\t#releaseDrag(drag: ValueDrag): void {\n\t\tclearTimeout(drag.revealTimer);\n\t\tthis.#claim.conceal('drag');\n\t\tthis.#renderHold();\n\t\tif (this.#value !== drag.fromValue) this.dispatchEvent(new Event('change', { bubbles: true }));\n\t\tthis.#springBack();\n\t}\n\n\t#renderAria(control: HTMLElement, orientation?: 'horizontal' | 'vertical'): void {\n\t\tthis.writeFormValue(String(this.#value), String(this.#value));\n\t\tif (this.#entry?.isOpen) {\n\t\t\tfor (const name of roleAttributes) control.removeAttribute(name);\n\t\t\tthis.forwardNaming(control, false);\n\t\t\tthis.#renderReadout();\n\t\t\treturn;\n\t\t}\n\n\t\tconst [low, high] = this.mapping().bounds;\n\n\t\twriteAttribute(control, 'role', this.controlRole());\n\t\twriteAttribute(control, 'aria-valuemin', String(low));\n\t\twriteAttribute(control, 'aria-valuemax', String(high));\n\t\twriteAttribute(control, 'aria-valuenow', String(this.#value));\n\t\tif (orientation) writeAttribute(control, 'aria-orientation', orientation);\n\t\twriteAttribute(\n\t\t\tcontrol,\n\t\t\t'aria-valuetext',\n\t\t\t(this.#formatSpokenValue ?? this.#formatValue)?.(this.#value),\n\t\t);\n\t\tthis.forwardNaming(control, true);\n\t\tthis.#renderDisabled(control);\n\t\tthis.#renderReadout();\n\t}\n\n\t#renderControl(): void {\n\t\tthis.draw();\n\t\tthis.#renderScale();\n\t\tthis.toggleState(\n\t\t\t'at-origin',\n\t\t\t!this.isWrapping() && this.#value === this.mapping().snap(this.originValue()),\n\t\t);\n\t\tthis.#renderAria(this.focusTarget(), this.controlOrientation());\n\t}\n\n\t#renderDisabled(control: HTMLElement): void {\n\t\tconst isDisabled = this.isDisabled();\n\n\t\twriteAttribute(control, 'aria-disabled', isDisabled ? 'true' : undefined);\n\t\twriteAttribute(control, 'tabindex', isDisabled ? undefined : '0');\n\t}\n\n\t#renderDragReveal(drag: ValueDrag): void {\n\t\tif (drag.isRevealed && !drag.isOutside) this.#claim.reveal('drag');\n\t\telse this.#claim.conceal('drag');\n\t\tthis.#renderHold();\n\t}\n\n\t#renderHold(): void {\n\t\tthis.#renderReadout();\n\t\tthis.holdChanged();\n\t}\n\n\t#renderReadout(): void {\n\t\tconst readout = this.#readout;\n\t\tif (!readout) return;\n\n\t\tconst { isOpen, value } = this.#claim.shown(this.#value, this.readout);\n\n\t\treadout.bubble.show({\n\t\t\tanchor: readout.anchor,\n\t\t\tisOpen,\n\t\t\ttext: value === undefined ? undefined : this.#textFor(value),\n\t\t});\n\t}\n\n\t#renderScale(): void {\n\t\tconst marks = this.#scaleMarks?.children ?? [];\n\t\tconst mapping = this.mapping();\n\n\t\tfor (const mark of marks) {\n\t\t\tif (!(mark instanceof HTMLElement || mark instanceof SVGElement)) continue;\n\n\t\t\tconst at = String(mapping.proportionOf(scaleValue(mark)));\n\n\t\t\tif (mark.style.getPropertyValue('--_sonic-scale-at') !== at) {\n\t\t\t\tmark.style.setProperty('--_sonic-scale-at', at);\n\t\t\t}\n\t\t}\n\t}\n\n\t#reset(): void {\n\t\tthis.#commit(this.default ?? NaN);\n\t}\n\n\t#reveal(drag: ValueDrag): void {\n\t\tif (drag.isRevealed || this.#dragging() !== drag) return;\n\n\t\tdrag.isRevealed = true;\n\t\tthis.#renderDragReveal(drag);\n\t}\n\n\t#scrubKey(key: string, next: number): void {\n\t\tif (this.#keyScrub?.key !== key) {\n\t\t\tthis.#endKeyScrub();\n\t\t\tthis.#keyScrub = { fromValue: this.#value, key };\n\t\t}\n\t\tthis.input(next);\n\t}\n\n\t#springBack(): void {\n\t\tconst target = this.springTarget();\n\t\tif (target === undefined) return;\n\n\t\t// Set before the commit so a `change` listener reading styles sees the glide\n\t\tif (this.mapping().snap(target) !== this.#value) this.toggleState('springing', true);\n\t\tthis.#commit(target);\n\t}\n\n\t#startDrag(control: HTMLElement, axis: ValueAxis, event: PointerEvent): DragState {\n\t\tconst mapping = this.mapping();\n\t\tconst detent = this.detent;\n\t\tconst start = {\n\t\t\tfrom: this.#value,\n\t\t\tposition: axis.position(event),\n\t\t\tproportion: axis.fromProportion ?? mapping.proportionOf(this.#value),\n\t\t\tthresholdPx: dragThresholdPx(event.pointerType),\n\t\t\ttravelPx: axis.travelPx,\n\t\t};\n\t\tif (detent === undefined) return startDrag(mapping, start);\n\n\t\tconst zonePx = readPxProperty(getComputedStyle(control), '--_sonic-detent-zone', detentZonePx);\n\n\t\treturn startDrag(mapping, {\n\t\t\t...start,\n\t\t\tdetent: { value: detent, zone: zonePx / axis.travelPx },\n\t\t});\n\t}\n\n\t#textFor(value: number): string {\n\t\treturn this.#formatValue?.(value) ?? String(value);\n\t}\n\n\t// A hover holds no focus, so the key is heard on the document (WCAG 1.4.13)\n\t#watchEscape(isHovered: boolean): void {\n\t\tif (!isHovered) {\n\t\t\tthis.#escapeWatch?.abort();\n\t\t\tthis.#escapeWatch = undefined;\n\t\t\treturn;\n\t\t}\n\t\tif (this.#escapeWatch) return;\n\n\t\tconst watch = new AbortController();\n\n\t\tthis.#escapeWatch = watch;\n\t\tthis.ownerDocument.addEventListener(\n\t\t\t'keydown',\n\t\t\t(event) => {\n\t\t\t\tif (event.key === 'Escape' && this.#claim.dismiss()) this.#renderHold();\n\t\t\t},\n\t\t\t{ signal: watch.signal },\n\t\t);\n\t}\n\n\t#withinLimit(mapping: ValueMapping, state: DragState): DragState {\n\t\tconst limit = this.#limit;\n\t\tif (!limit || mapping.isWrapping) return state;\n\n\t\tconst [low, high] = limit;\n\n\t\treturn {\n\t\t\t...state,\n\t\t\trawProportion: clamp(\n\t\t\t\tstate.rawProportion,\n\t\t\t\tmapping.proportionOf(low),\n\t\t\t\tmapping.proportionOf(high),\n\t\t\t),\n\t\t};\n\t}\n\n\t#write(next: number): void {\n\t\tif (!Number.isFinite(next)) return;\n\n\t\tconst clamped = this.mapping().snap(next);\n\n\t\tthis.#asked = clamped;\n\t\tif (clamped === this.#value) return;\n\n\t\tthis.#value = clamped;\n\t\tthis.render();\n\t}\n\n\t#writeModulationProportion(control: HTMLElement, prefix: 'dial' | 'slider'): void {\n\t\tconst modulationValue = this.isWrapping() ? undefined : this.#modulationValue;\n\t\tconst isModulated = modulationValue !== undefined;\n\n\t\tif (isModulated !== this.#isModulated) {\n\t\t\tthis.#isModulated = isModulated;\n\t\t\tthis.toggleState('modulated', isModulated);\n\t\t}\n\t\tif (modulationValue === undefined) {\n\t\t\tcontrol.style.removeProperty(`--_sonic-${prefix}-modulation-value`);\n\t\t\treturn;\n\t\t}\n\n\t\tcontrol.style.setProperty(\n\t\t\t`--_sonic-${prefix}-modulation-value`,\n\t\t\tString(this.mapping().proportionOf(modulationValue)),\n\t\t);\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"value-element.js","names":[],"sources":["../../../src/elements/value-element.ts"],"sourcesContent":["import type { DragState } from '#lib/drag-step.ts';\nimport type { PointerDrag } from '#lib/pointer-drag.ts';\nimport type { ValueMapping } from '#lib/value-mapping.ts';\n\nimport { SonicFormElement } from '#elements/form-element.ts';\nimport { ReadoutClaim, revealMs } from '#elements/readout-claim.ts';\nimport { Readout } from '#elements/readout.ts';\nimport { ValueEntry } from '#elements/value-entry.ts';\nimport { dragThresholdPx, startDrag, stepDrag } from '#lib/drag-step.ts';\nimport { focusByPointer } from '#lib/focus-by-pointer.ts';\nimport { clamp, toNumber } from '#lib/math.ts';\nimport { isMenuPress, isResetPress } from '#lib/modifier-press.ts';\nimport { parseNumberList } from '#lib/number-list.ts';\nimport { bindDrag } from '#lib/pointer-drag.ts';\nimport { readPxProperty } from '#lib/read-px-property.ts';\nimport { requireChild } from '#lib/render.ts';\nimport { resetKeys, valueMapping } from '#lib/value-mapping.ts';\nimport { writeAttribute } from '#lib/write-attribute.ts';\n\nexport interface ValueAxis {\n\tfromProportion?: number;\n\tisKeptOnCancel?: boolean;\n\toutside?: (event: PointerEvent) => boolean;\n\tposition: (event: PointerEvent) => number;\n\ttravelPx: number;\n}\n\ninterface ValueDrag extends ValueAxis {\n\tfromValue: number;\n\tisOutside: boolean;\n\tisRevealed: boolean;\n\trevealTimer: ReturnType<typeof setTimeout> | undefined;\n\tstate: DragState;\n}\n\ninterface KeyScrub {\n\tfromValue: number;\n\tkey: string;\n}\n\nconst detentZonePx = 8;\nconst fallbackTravelPx = 160;\n\nlet instanceCount = 0;\n\nconst proportionAttributes = new Set(['max', 'midpoint', 'min', 'notched', 'positions', 'taper']);\n\nconst roleAttributes = [\n\t'aria-disabled',\n\t'aria-orientation',\n\t'aria-valuemax',\n\t'aria-valuemin',\n\t'aria-valuenow',\n\t'aria-valuetext',\n\t'role',\n\t'tabindex',\n];\n\ntype ValueLanding = (target: number, direction: -1 | 0 | 1) => number;\n\nexport interface ValueLink {\n\tinput: (next: number, isMover?: boolean) => boolean;\n\tisDisabled: () => boolean;\n\tisHeld: () => boolean;\n\tland: (resolve: undefined | ValueLanding) => void;\n\tlimit: (bounds: [number, number] | undefined) => void;\n\tmapping: () => ValueMapping;\n\tvalue: () => number;\n\twatch: (listener: () => void) => () => void;\n}\n\n// Filled from inside the class, so it reaches protected members and nothing lands on the element's public type\nlet link: (element: SonicValueElement) => ValueLink;\n\nexport function linkValue(element: SonicValueElement): ValueLink {\n\treturn link(element);\n}\n\nexport abstract class SonicValueElement extends SonicFormElement {\n\tstatic override readonly observedAttributes = [\n\t\t...SonicFormElement.observedAttributes,\n\t\t'detent',\n\t\t'max',\n\t\t'midpoint',\n\t\t'min',\n\t\t'notched',\n\t\t'origin',\n\t\t'readout',\n\t\t'step',\n\t\t'tabindex',\n\t\t'taper',\n\t\t'value',\n\t\t'positions',\n\t];\n\n\tstatic {\n\t\tlink = (element) => ({\n\t\t\tinput: (next, isMover = false) => (isMover || !element.#isHeld()) && element.input(next),\n\t\t\tisDisabled: () => element.isDisabled(),\n\t\t\tisHeld: () => element.#isHeld(),\n\t\t\tland: (resolve) => {\n\t\t\t\telement.#land = resolve;\n\t\t\t},\n\t\t\tlimit: (bounds) => {\n\t\t\t\telement.#limit = bounds;\n\t\t\t},\n\t\t\tmapping: () => element.mapping(),\n\t\t\tvalue: () => element.#value,\n\t\t\twatch: (listener) => {\n\t\t\t\telement.#watchers.add(listener);\n\n\t\t\t\treturn () => {\n\t\t\t\t\telement.#watchers.delete(listener);\n\t\t\t\t};\n\t\t\t},\n\t\t});\n\t}\n\n\tget default(): number | undefined {\n\t\treturn this.optionalNumberAttribute('default');\n\t}\n\n\tset default(value: number | undefined) {\n\t\tthis.reflect('default', value);\n\t}\n\n\tget detent(): number | undefined {\n\t\treturn this.optionalNumberAttribute('detent');\n\t}\n\n\tset detent(value: number | undefined) {\n\t\tthis.reflect('detent', value);\n\t}\n\n\tget dimmed(): boolean {\n\t\treturn this.hasAttribute('dimmed');\n\t}\n\n\tset dimmed(isDimmed: boolean) {\n\t\tthis.reflect('dimmed', isDimmed);\n\t}\n\n\tget doublePress(): 'entry' | 'reset' {\n\t\treturn this.getAttribute('double-press') === 'reset' ? 'reset' : 'entry';\n\t}\n\n\tset doublePress(gesture: 'entry' | 'reset' | undefined) {\n\t\tthis.reflect('double-press', gesture);\n\t}\n\n\tget formatSpokenValue(): ((value: number) => string) | undefined {\n\t\treturn this.#formatSpokenValue;\n\t}\n\n\tset formatSpokenValue(format: ((value: number) => string) | undefined) {\n\t\tthis.#formatSpokenValue = format;\n\t\tthis.render();\n\t}\n\n\tget formatValue(): ((value: number) => string) | undefined {\n\t\treturn this.#formatValue;\n\t}\n\n\tset formatValue(format: ((value: number) => string) | undefined) {\n\t\tthis.#formatValue = format;\n\t\tthis.render();\n\t}\n\n\tget keyStep(): number | undefined {\n\t\treturn this.optionalNumberAttribute('key-step');\n\t}\n\n\tset keyStep(value: number | undefined) {\n\t\tthis.reflect('key-step', value);\n\t}\n\n\tget max(): number {\n\t\treturn this.numberAttribute('max', 100);\n\t}\n\n\tset max(value: number | undefined) {\n\t\tthis.reflect('max', value);\n\t}\n\n\tget midpoint(): number | undefined {\n\t\treturn this.optionalNumberAttribute('midpoint');\n\t}\n\n\tset midpoint(value: number | undefined) {\n\t\tthis.reflect('midpoint', value);\n\t}\n\n\tget min(): number {\n\t\treturn this.numberAttribute('min', 0);\n\t}\n\n\tset min(value: number | undefined) {\n\t\tthis.reflect('min', value);\n\t}\n\n\tget notched(): boolean {\n\t\treturn this.hasAttribute('notched');\n\t}\n\n\tset notched(isNotched: boolean) {\n\t\tthis.reflect('notched', isNotched);\n\t}\n\n\tget origin(): number | undefined {\n\t\treturn this.optionalNumberAttribute('origin');\n\t}\n\n\tset origin(value: number | undefined) {\n\t\tthis.reflect('origin', value);\n\t}\n\n\tget parseValue(): ((text: string) => number) | undefined {\n\t\treturn this.#parseValue;\n\t}\n\n\tset parseValue(parse: ((text: string) => number) | undefined) {\n\t\tthis.#parseValue = parse;\n\t}\n\n\tget positions(): Array<number> | undefined {\n\t\treturn parseNumberList(this.getAttribute('positions'));\n\t}\n\n\tset positions(positions: Array<number> | undefined) {\n\t\tthis.reflect('positions', positions?.join(' '));\n\t}\n\n\tget readout(): boolean {\n\t\treturn this.hasAttribute('readout');\n\t}\n\n\tset readout(isShown: boolean) {\n\t\tthis.reflect('readout', isShown);\n\t}\n\n\tget step(): number {\n\t\treturn this.numberAttribute('step', 1);\n\t}\n\n\tset step(value: number | undefined) {\n\t\tthis.reflect('step', value);\n\t}\n\n\tget taper(): 'linear' | 'log' {\n\t\treturn this.getAttribute('taper') === 'log' ? 'log' : 'linear';\n\t}\n\n\tset taper(curve: 'linear' | 'log' | undefined) {\n\t\tthis.reflect('taper', curve);\n\t}\n\n\tget value(): number {\n\t\treturn this.#value;\n\t}\n\n\tset value(next: null | number | undefined) {\n\t\t// A framework removes a prop by setting the property to `undefined`\n\t\tif (next === undefined || next === null) {\n\t\t\tthis.formResetCallback();\n\t\t\treturn;\n\t\t}\n\n\t\tconst value = toNumber(next);\n\n\t\tif (this.#isHeld()) {\n\t\t\tthis.heldWrite(value);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#write(value);\n\t\tif (Number.isFinite(value)) this.#asked = value;\n\t}\n\n\tget valueText(): string {\n\t\treturn this.#textFor(this.#value);\n\t}\n\n\t#asked: number | undefined;\n\n\treadonly #claim = new ReadoutClaim(() => {\n\t\tthis.#renderHold();\n\t});\n\n\t#entry: undefined | ValueEntry;\n\n\t#formatSpokenValue: ((value: number) => string) | undefined;\n\n\t#formatValue: ((value: number) => string) | undefined;\n\n\treadonly #instance = String((instanceCount += 1));\n\n\t#isModulated = false;\n\n\t#keyScrub: KeyScrub | undefined;\n\n\t#land: undefined | ValueLanding;\n\n\t#limit: [number, number] | undefined;\n\n\t// Every attribute it reads is observed; a subclass adding an input to `isWrapping()` has to observe it\n\t#mapping: undefined | ValueMapping;\n\n\t#modulationValue: number | undefined;\n\n\t#parseValue: ((text: string) => number) | undefined;\n\n\t#pointerDrag: PointerDrag<ValueDrag> | undefined;\n\n\t#positions: Array<number> | undefined;\n\n\t#readout: undefined | { anchor: HTMLElement; bubble: Readout };\n\n\t#value = 0;\n\n\treadonly #watchers = new Set<() => void>();\n\n\tattributeChangedCallback(name: string): void {\n\t\tthis.#mapping = undefined;\n\t\tthis.#positions = parseNumberList(this.getAttribute('positions'));\n\t\tif (name === 'value') {\n\t\t\tif (this.#isHeld()) {\n\t\t\t\tthis.heldWrite(this.numberAttribute('value', this.min));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.#asked = undefined;\n\t\t}\n\t\tif (name === 'disabled' && this.isDisabled()) this.#endHolds();\n\n\t\tthis.#value = this.mapping().snap(this.#asked ?? this.numberAttribute('value', this.min));\n\t\tif (proportionAttributes.has(name) && this.isBound()) this.proportionsChanged();\n\t\tthis.render();\n\t}\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties(\n\t\t\t'default',\n\t\t\t'dimmed',\n\t\t\t'doublePress',\n\t\t\t'max',\n\t\t\t'midpoint',\n\t\t\t'min',\n\t\t\t'notched',\n\t\t\t'origin',\n\t\t\t'readout',\n\t\t\t'step',\n\t\t\t'taper',\n\t\t\t'positions',\n\t\t\t'detent',\n\t\t\t'formatValue',\n\t\t\t'formatSpokenValue',\n\t\t\t'keyStep',\n\t\t\t'parseValue',\n\t\t\t'value',\n\t\t);\n\t\tsuper.connectedCallback();\n\t}\n\n\tprotected bindGestures(\n\t\tcontrol: HTMLElement,\n\t\tsignal: AbortSignal,\n\t\tgrab: (event: PointerEvent) => undefined | ValueAxis,\n\t): void {\n\t\tconst entry = this.#bindEntry(control, signal);\n\n\t\tthis.#pointerDrag = bindDrag<ValueDrag>(\n\t\t\tcontrol,\n\t\t\t{\n\t\t\t\tcancel: (drag) => {\n\t\t\t\t\tif (drag.isKeptOnCancel !== true) this.input(drag.fromValue);\n\t\t\t\t},\n\t\t\t\tgrab: (event) => {\n\t\t\t\t\tif (isMenuPress(event) || this.isDisabled() || entry.isOpen) return;\n\n\t\t\t\t\tthis.toggleState('springing', false);\n\t\t\t\t\t// A click listener above makes WebKit send a tap's compatibility mousedown, which blurs the entry a double tap just opened\n\t\t\t\t\tif (event.pointerType === 'touch') event.preventDefault();\n\t\t\t\t\tfocusByPointer(control);\n\t\t\t\t\tif (isResetPress(event)) {\n\t\t\t\t\t\tthis.#reset();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst fromValue = this.#value;\n\t\t\t\t\tconst axis = grab(event);\n\t\t\t\t\tif (!axis) return;\n\n\t\t\t\t\tconst drag: ValueDrag = {\n\t\t\t\t\t\t...axis,\n\t\t\t\t\t\tfromValue,\n\t\t\t\t\t\tisOutside: false,\n\t\t\t\t\t\tisRevealed: false,\n\t\t\t\t\t\trevealTimer: undefined,\n\t\t\t\t\t\tstate: this.#startDrag(control, axis, event),\n\t\t\t\t\t};\n\n\t\t\t\t\tdrag.revealTimer = setTimeout(() => {\n\t\t\t\t\t\tthis.#reveal(drag);\n\t\t\t\t\t}, revealMs);\n\n\t\t\t\t\treturn drag;\n\t\t\t\t},\n\t\t\t\tlift: (drag, event) => {\n\t\t\t\t\tconst tap = drag.state.isEngaged ? undefined : this.tapTarget();\n\n\t\t\t\t\tif (tap !== undefined) {\n\t\t\t\t\t\tentry.forgetPress();\n\t\t\t\t\t\tthis.#commit(tap);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (!entry.press(event) || this.springTarget() !== undefined) return;\n\n\t\t\t\t\tif (this.doublePress === 'reset') this.#reset();\n\t\t\t\t\telse entry.open();\n\t\t\t\t},\n\t\t\t\tmove: (drag, event) => {\n\t\t\t\t\tthis.#dragTo(drag, event);\n\t\t\t\t},\n\t\t\t\trelease: (drag) => {\n\t\t\t\t\tthis.#releaseDrag(drag);\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\tcontrol.addEventListener(\n\t\t\t'pointercancel',\n\t\t\t() => {\n\t\t\t\tentry.forgetPress();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tthis.#bindKeys(control, entry, signal);\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tthis.#endKeyScrub();\n\t\t\t\tthis.#concealKeyReveal();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\tprotected controlOrientation(): 'horizontal' | 'vertical' | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected controlRole(): 'slider' | 'spinbutton' {\n\t\treturn 'slider';\n\t}\n\n\tprotected abstract draw(): void;\n\n\tprotected abstract override focusTarget(): HTMLElement;\n\n\tprotected heldFrom(): number | undefined {\n\t\treturn this.#dragging()?.fromValue ?? this.#keyScrub?.fromValue;\n\t}\n\n\tprotected heldWrite(_next: number): void {\n\t\t// Dropped unless a subclass draws where playback carries on\n\t}\n\n\tprotected holdChanged(): void {\n\t\t// Only a subclass draws a hold\n\t}\n\n\tprotected input(next: number): boolean {\n\t\tconst previous = this.#value;\n\n\t\tthis.#write(this.#limit ? clamp(next, ...this.#limit) : next);\n\t\tif (this.#value === previous) return false;\n\n\t\tthis.dispatchEvent(new Event('input', { bubbles: true, composed: true }));\n\n\t\treturn true;\n\t}\n\n\tprotected isEditing(): boolean {\n\t\treturn this.#entry?.isOpen === true;\n\t}\n\n\tprotected isRevealed(): boolean {\n\t\treturn this.#claim.isRevealed;\n\t}\n\n\tprotected isWrapping(): boolean {\n\t\treturn false;\n\t}\n\n\tprotected mapping(): ValueMapping {\n\t\tif (this.#mapping) return this.#mapping;\n\n\t\tconst { detent, midpoint } = this;\n\n\t\tthis.#mapping = valueMapping({\n\t\t\t...(detent === undefined ? {} : { detent }),\n\t\t\t...(this.#positions ? { positions: this.#positions } : {}),\n\t\t\tmax: this.max,\n\t\t\t...(midpoint === undefined ? {} : { midpoint }),\n\t\t\tisNotched: this.notched,\n\t\t\tisWrapping: this.isWrapping(),\n\t\t\tmin: this.min,\n\t\t\tstep: this.step,\n\t\t\ttaper: this.taper,\n\t\t});\n\n\t\treturn this.#mapping;\n\t}\n\n\tprotected originValue(): number {\n\t\treturn this.origin ?? this.mapping().bounds[0];\n\t}\n\n\tprotected previewValue(): number | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected proportionsChanged(): void {\n\t\t// Runs when every proportion moves, never per input\n\t}\n\n\tprotected readModulationValue(): number | undefined {\n\t\treturn this.#modulationValue;\n\t}\n\n\tprotected readoutValue(): number {\n\t\treturn this.#shown().value ?? this.#value;\n\t}\n\n\tprotected render(): void {\n\t\tif (this.isBound()) this.#renderControl();\n\t\tfor (const listener of this.#watchers) listener();\n\t}\n\n\tprotected renderReadout(): void {\n\t\tconst readout = this.#readout;\n\t\tif (!readout) return;\n\n\t\tconst { isOpen, value } = this.#shown();\n\n\t\treadout.bubble.show({\n\t\t\tanchor: readout.anchor,\n\t\t\tisOpen,\n\t\t\ttext: value === undefined ? undefined : this.#textFor(value),\n\t\t});\n\t}\n\n\tprotected restoreState(state: string): void {\n\t\tthis.value = Number(state);\n\t}\n\n\tprotected scrubsKeyRepeat(): boolean {\n\t\treturn false;\n\t}\n\n\tprotected springTarget(): number | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected tapTarget(): number | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected travelPx(control: HTMLElement, property: `--_sonic-${string}`): number {\n\t\treturn Math.max(1, readPxProperty(getComputedStyle(control), property, fallbackTravelPx));\n\t}\n\n\tprotected writeModulationValue(\n\t\tcontrol: HTMLElement,\n\t\tprefix: 'dial' | 'slider',\n\t\tnext: null | number | undefined,\n\t): void {\n\t\tconst value = next === undefined || next === null ? undefined : toNumber(next);\n\t\tif (value !== undefined && !Number.isFinite(value)) return;\n\n\t\tthis.#modulationValue = value;\n\t\tif (this.isBound()) this.#writeModulationProportion(control, prefix);\n\t}\n\n\tprotected writeProportions(\n\t\tcontrol: HTMLElement,\n\t\tprefix: 'dial' | 'slider',\n\t\tmodulation: number,\n\t): void {\n\t\tconst { style } = control;\n\t\tconst mapping = this.mapping();\n\t\tconst value = mapping.proportionOf(this.#value);\n\t\tconst reach = mapping.proportionOf(this.#value + modulation);\n\t\tconst { positionCount } = mapping;\n\n\t\tstyle.setProperty(`--_sonic-${prefix}-value`, String(value));\n\t\tstyle.setProperty(\n\t\t\t`--_sonic-${prefix}-origin`,\n\t\t\tString(mapping.proportionOf(this.originValue())),\n\t\t);\n\t\tstyle.setProperty(`--_sonic-${prefix}-modulation-from`, String(Math.min(value, reach)));\n\t\tstyle.setProperty(`--_sonic-${prefix}-modulation-to`, String(Math.max(value, reach)));\n\t\tif (positionCount === undefined) style.removeProperty(`--_sonic-${prefix}-position-count`);\n\t\telse style.setProperty(`--_sonic-${prefix}-position-count`, String(positionCount));\n\t\tthis.#writeModulationProportion(control, prefix);\n\t}\n\n\t#bindEntry(control: HTMLElement, signal: AbortSignal): ValueEntry {\n\t\tconst input = requireChild(control, 'input', HTMLInputElement);\n\t\tconst bubble = control.querySelector<HTMLElement>('[popover]');\n\n\t\t// Chrome's issues panel flags a form field with no id or name; a `name` would submit it\n\t\tinput.id = `sonic-entry-${this.#instance}`;\n\t\tif (bubble) this.#readout = { anchor: control, bubble: new Readout(bubble) };\n\n\t\tconst entry = new ValueEntry(input, {\n\t\t\tcommit: (text) => {\n\t\t\t\t// eslint-disable-next-line unicorn/prefer-number-coercion -- `Number('')` is 0; an emptied field should leave the value alone\n\t\t\t\tthis.#commit((this.#parseValue ?? Number.parseFloat)(text));\n\t\t\t},\n\t\t\t// `Number.parseFloat` reads \"5 kHz\" as 5\n\t\t\ttext: () => (this.#parseValue ? this.valueText : String(this.#value)),\n\t\t\ttoggle: (isOpen) => {\n\t\t\t\tif (isOpen) this.forwardNaming(input, true);\n\t\t\t\tthis.toggleState('editing', isOpen);\n\t\t\t\tthis.render();\n\t\t\t},\n\t\t});\n\n\t\tthis.#entry = entry;\n\t\tentry.bind(control, signal);\n\n\t\treturn entry;\n\t}\n\n\t#bindKeys(control: HTMLElement, entry: ValueEntry, signal: AbortSignal): void {\n\t\tcontrol.addEventListener(\n\t\t\t'keydown',\n\t\t\t(event) => {\n\t\t\t\tif (this.isDisabled() || event.defaultPrevented || event.target !== control) return;\n\n\t\t\t\tthis.toggleState('springing', false);\n\t\t\t\tif (event.key === 'Enter') {\n\t\t\t\t\tif (this.springTarget() !== undefined) return;\n\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tentry.open();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst next = this.#keyTarget(event.key);\n\t\t\t\tif (next === undefined) return;\n\n\t\t\t\tevent.preventDefault();\n\t\t\t\tthis.#keyTo(event, next);\n\t\t\t\tthis.#claim.reveal('keys');\n\t\t\t\tthis.#renderHold();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tcontrol.addEventListener(\n\t\t\t'keyup',\n\t\t\t(event) => {\n\t\t\t\t// macOS sends no `keyup` for a key let go while Cmd is down\n\t\t\t\tconst isMeta = event.key === 'Meta';\n\n\t\t\t\tif (isMeta || event.key === this.#keyScrub?.key) this.#endKeyScrub();\n\t\t\t\tif (isMeta && this.#dragging()) return;\n\t\t\t\tif (isMeta || this.mapping().keyTarget(event.key, this.#value) !== undefined) {\n\t\t\t\t\tthis.#springBack();\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tcontrol.addEventListener(\n\t\t\t'blur',\n\t\t\t() => {\n\t\t\t\tthis.#endKeyScrub();\n\t\t\t\tthis.#concealKeyReveal();\n\t\t\t\tthis.#springBack();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t}\n\n\t#commit(next: number, direction: -1 | 0 | 1 = 0): void {\n\t\tconst landed = Number.isFinite(next) ? (this.#land?.(next, direction) ?? next) : next;\n\n\t\tif (this.input(landed)) this.dispatchEvent(new Event('change', { bubbles: true }));\n\t}\n\n\t#concealKeyReveal(): void {\n\t\tif (this.#claim.conceal('keys')) this.#renderHold();\n\t}\n\n\t#dragging(): undefined | ValueDrag {\n\t\treturn this.#pointerDrag?.current();\n\t}\n\n\t#dragTo(drag: ValueDrag, event: PointerEvent): void {\n\t\tconst isOutside = drag.outside?.(event) === true;\n\t\tconst wasEngaged = drag.state.isEngaged;\n\t\tconst mapping = this.mapping();\n\t\tconst { state, value } = stepDrag(mapping, drag.state, {\n\t\t\tisFine: event.shiftKey,\n\t\t\tisOutside,\n\t\t\tposition: drag.position(event),\n\t\t});\n\n\t\tdrag.state = this.#withinLimit(mapping, state);\n\t\tif (value === undefined) return;\n\n\t\tif (!wasEngaged) this.#reveal(drag);\n\t\tthis.input(isOutside ? drag.fromValue : value);\n\t\tif (isOutside === drag.isOutside) return;\n\n\t\tdrag.isOutside = isOutside;\n\t\tthis.#renderDragReveal(drag);\n\t}\n\n\t#endHolds(): void {\n\t\tthis.#entry?.close(false);\n\t\tthis.#pointerDrag?.end();\n\t\tthis.#endKeyScrub();\n\t}\n\n\t#endKeyScrub(): void {\n\t\tconst scrub = this.#keyScrub;\n\t\tif (!scrub) return;\n\n\t\tthis.#keyScrub = undefined;\n\t\tthis.#renderHold();\n\t\tif (this.#value !== scrub.fromValue) this.dispatchEvent(new Event('change', { bubbles: true }));\n\t}\n\n\t#isHeld(): boolean {\n\t\treturn this.#dragging() !== undefined || this.#keyScrub !== undefined;\n\t}\n\n\t#keyTarget(key: string): number | undefined {\n\t\tif (resetKeys.has(key)) return this.default;\n\n\t\treturn this.mapping().keyTarget(key, this.#value, this.keyStep);\n\t}\n\n\t#keyTo(event: KeyboardEvent, next: number): void {\n\t\tif (event.repeat && this.scrubsKeyRepeat()) {\n\t\t\tthis.#scrubKey(event.key, next);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#endKeyScrub();\n\t\tthis.#commit(next, next > this.#value ? 1 : -1);\n\t}\n\n\t#releaseDrag(drag: ValueDrag): void {\n\t\tclearTimeout(drag.revealTimer);\n\t\tthis.#claim.conceal('drag');\n\t\tthis.#renderHold();\n\t\tif (this.#value !== drag.fromValue) this.dispatchEvent(new Event('change', { bubbles: true }));\n\t\tthis.#springBack();\n\t}\n\n\t#renderAria(control: HTMLElement, orientation?: 'horizontal' | 'vertical'): void {\n\t\tthis.writeFormValue(String(this.#value), String(this.#value));\n\t\tif (this.#entry?.isOpen) {\n\t\t\tfor (const name of roleAttributes) control.removeAttribute(name);\n\t\t\tthis.forwardNaming(control, false);\n\t\t\tthis.renderReadout();\n\t\t\treturn;\n\t\t}\n\n\t\tconst [low, high] = this.mapping().bounds;\n\n\t\twriteAttribute(control, 'role', this.controlRole());\n\t\twriteAttribute(control, 'aria-valuemin', String(low));\n\t\twriteAttribute(control, 'aria-valuemax', String(high));\n\t\twriteAttribute(control, 'aria-valuenow', String(this.#value));\n\t\tif (orientation) writeAttribute(control, 'aria-orientation', orientation);\n\t\twriteAttribute(\n\t\t\tcontrol,\n\t\t\t'aria-valuetext',\n\t\t\t(this.#formatSpokenValue ?? this.#formatValue)?.(this.#value),\n\t\t);\n\t\tthis.forwardNaming(control, true);\n\t\tthis.#renderDisabled(control);\n\t\tthis.renderReadout();\n\t}\n\n\t#renderControl(): void {\n\t\tthis.draw();\n\t\tthis.toggleState(\n\t\t\t'at-origin',\n\t\t\t!this.isWrapping() && this.#value === this.mapping().snap(this.originValue()),\n\t\t);\n\t\tthis.#renderAria(this.focusTarget(), this.controlOrientation());\n\t}\n\n\t#renderDisabled(control: HTMLElement): void {\n\t\tconst isDisabled = this.isDisabled();\n\n\t\twriteAttribute(control, 'aria-disabled', isDisabled ? 'true' : undefined);\n\t\t// The host is `display: contents`, so its tab stop is the control's\n\t\tconst stop = this.getAttribute('tabindex') === '-1' ? '-1' : '0';\n\n\t\twriteAttribute(control, 'tabindex', isDisabled ? undefined : stop);\n\t}\n\n\t#renderDragReveal(drag: ValueDrag): void {\n\t\tif (drag.isRevealed && !drag.isOutside) this.#claim.reveal('drag');\n\t\telse this.#claim.conceal('drag');\n\t\tthis.#renderHold();\n\t}\n\n\t#renderHold(): void {\n\t\tthis.renderReadout();\n\t\tthis.holdChanged();\n\t}\n\n\t#reset(): void {\n\t\tthis.#commit(this.default ?? NaN);\n\t}\n\n\t#reveal(drag: ValueDrag): void {\n\t\tif (drag.isRevealed || this.#dragging() !== drag) return;\n\n\t\tdrag.isRevealed = true;\n\t\tthis.#renderDragReveal(drag);\n\t}\n\n\t#scrubKey(key: string, next: number): void {\n\t\tif (this.#keyScrub?.key !== key) {\n\t\t\tthis.#endKeyScrub();\n\t\t\tthis.#keyScrub = { fromValue: this.#value, key };\n\t\t}\n\t\tthis.input(next);\n\t}\n\n\t#shown(): { isOpen: boolean; value: number | undefined } {\n\t\tif (this.isEditing()) return { isOpen: true, value: undefined };\n\n\t\tconst isRevealed = this.#claim.isRevealed;\n\t\tconst preview = isRevealed ? undefined : this.previewValue();\n\n\t\treturn {\n\t\t\tisOpen: (isRevealed || preview !== undefined) && this.readout,\n\t\t\tvalue: preview ?? this.#value,\n\t\t};\n\t}\n\n\t#springBack(): void {\n\t\tconst target = this.springTarget();\n\t\tif (target === undefined) return;\n\n\t\t// Set before the commit so a `change` listener reading styles sees the glide\n\t\tif (this.mapping().snap(target) !== this.#value) this.toggleState('springing', true);\n\t\tthis.#commit(target);\n\t}\n\n\t#startDrag(control: HTMLElement, axis: ValueAxis, event: PointerEvent): DragState {\n\t\tconst mapping = this.mapping();\n\t\tconst detent = this.detent;\n\t\tconst start = {\n\t\t\tfrom: this.#value,\n\t\t\tposition: axis.position(event),\n\t\t\tproportion: axis.fromProportion ?? mapping.proportionOf(this.#value),\n\t\t\tthresholdPx: dragThresholdPx(event.pointerType),\n\t\t\ttravelPx: axis.travelPx,\n\t\t};\n\t\tif (detent === undefined) return startDrag(mapping, start);\n\n\t\tconst zonePx = readPxProperty(getComputedStyle(control), '--_sonic-detent-zone', detentZonePx);\n\n\t\treturn startDrag(mapping, {\n\t\t\t...start,\n\t\t\tdetent: { value: detent, zone: zonePx / axis.travelPx },\n\t\t});\n\t}\n\n\t#textFor(value: number): string {\n\t\treturn this.#formatValue?.(value) ?? String(value);\n\t}\n\n\t#withinLimit(mapping: ValueMapping, state: DragState): DragState {\n\t\tconst limit = this.#limit;\n\t\tif (!limit || mapping.isWrapping) return state;\n\n\t\tconst [low, high] = limit;\n\n\t\treturn {\n\t\t\t...state,\n\t\t\trawProportion: clamp(\n\t\t\t\tstate.rawProportion,\n\t\t\t\tmapping.proportionOf(low),\n\t\t\t\tmapping.proportionOf(high),\n\t\t\t),\n\t\t};\n\t}\n\n\t#write(next: number): void {\n\t\tif (!Number.isFinite(next)) return;\n\n\t\tconst clamped = this.mapping().snap(next);\n\n\t\tthis.#asked = clamped;\n\t\tif (clamped === this.#value) return;\n\n\t\tthis.#value = clamped;\n\t\tthis.render();\n\t}\n\n\t#writeModulationProportion(control: HTMLElement, prefix: 'dial' | 'slider'): void {\n\t\tconst modulationValue = this.isWrapping() ? undefined : this.#modulationValue;\n\t\tconst isModulated = modulationValue !== undefined;\n\n\t\tif (isModulated !== this.#isModulated) {\n\t\t\tthis.#isModulated = isModulated;\n\t\t\tthis.toggleState('modulated', isModulated);\n\t\t}\n\t\tif (modulationValue === undefined) {\n\t\t\tcontrol.style.removeProperty(`--_sonic-${prefix}-modulation-value`);\n\t\t\treturn;\n\t\t}\n\n\t\tcontrol.style.setProperty(\n\t\t\t`--_sonic-${prefix}-modulation-value`,\n\t\t\tString(this.mapping().proportionOf(modulationValue)),\n\t\t);\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAwCA,MAAM,eAAe;AACrB,MAAM,mBAAmB;AAEzB,IAAI,gBAAgB;AAEpB,MAAM,uCAAuB,IAAI,IAAI;CAAC;CAAO;CAAY;CAAO;CAAW;CAAa;AAAO,CAAC;AAEhG,MAAM,iBAAiB;CACtB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;AAgBA,IAAI;AAEJ,SAAgB,UAAU,SAAuC;CAChE,OAAO,KAAK,OAAO;AACpB;AAEA,IAAsB,oBAAtB,cAAgD,iBAAiB;CAChE,OAAyB,qBAAqB;EAC7C,GAAG,iBAAiB;EACpB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACD;CAEA;EACC,QAAQ,aAAa;GACpB,QAAQ,MAAM,UAAU,WAAW,WAAW,CAAC,QAAQ,QAAQ,MAAM,QAAQ,MAAM,IAAI;GACvF,kBAAkB,QAAQ,WAAW;GACrC,cAAc,QAAQ,QAAQ;GAC9B,OAAO,YAAY;IAClB,QAAQ,QAAQ;GACjB;GACA,QAAQ,WAAW;IAClB,QAAQ,SAAS;GAClB;GACA,eAAe,QAAQ,QAAQ;GAC/B,aAAa,QAAQ;GACrB,QAAQ,aAAa;IACpB,QAAQ,UAAU,IAAI,QAAQ;IAE9B,aAAa;KACZ,QAAQ,UAAU,OAAO,QAAQ;IAClC;GACD;EACD;CACD;CAEA,IAAI,UAA8B;EACjC,OAAO,KAAK,wBAAwB,SAAS;CAC9C;CAEA,IAAI,QAAQ,OAA2B;EACtC,KAAK,QAAQ,WAAW,KAAK;CAC9B;CAEA,IAAI,SAA6B;EAChC,OAAO,KAAK,wBAAwB,QAAQ;CAC7C;CAEA,IAAI,OAAO,OAA2B;EACrC,KAAK,QAAQ,UAAU,KAAK;CAC7B;CAEA,IAAI,SAAkB;EACrB,OAAO,KAAK,aAAa,QAAQ;CAClC;CAEA,IAAI,OAAO,UAAmB;EAC7B,KAAK,QAAQ,UAAU,QAAQ;CAChC;CAEA,IAAI,cAAiC;EACpC,OAAO,KAAK,aAAa,cAAc,MAAM,UAAU,UAAU;CAClE;CAEA,IAAI,YAAY,SAAwC;EACvD,KAAK,QAAQ,gBAAgB,OAAO;CACrC;CAEA,IAAI,oBAA6D;EAChE,OAAO,KAAK;CACb;CAEA,IAAI,kBAAkB,QAAiD;EACtE,KAAK,qBAAqB;EAC1B,KAAK,OAAO;CACb;CAEA,IAAI,cAAuD;EAC1D,OAAO,KAAK;CACb;CAEA,IAAI,YAAY,QAAiD;EAChE,KAAK,eAAe;EACpB,KAAK,OAAO;CACb;CAEA,IAAI,UAA8B;EACjC,OAAO,KAAK,wBAAwB,UAAU;CAC/C;CAEA,IAAI,QAAQ,OAA2B;EACtC,KAAK,QAAQ,YAAY,KAAK;CAC/B;CAEA,IAAI,MAAc;EACjB,OAAO,KAAK,gBAAgB,OAAO,GAAG;CACvC;CAEA,IAAI,IAAI,OAA2B;EAClC,KAAK,QAAQ,OAAO,KAAK;CAC1B;CAEA,IAAI,WAA+B;EAClC,OAAO,KAAK,wBAAwB,UAAU;CAC/C;CAEA,IAAI,SAAS,OAA2B;EACvC,KAAK,QAAQ,YAAY,KAAK;CAC/B;CAEA,IAAI,MAAc;EACjB,OAAO,KAAK,gBAAgB,OAAO,CAAC;CACrC;CAEA,IAAI,IAAI,OAA2B;EAClC,KAAK,QAAQ,OAAO,KAAK;CAC1B;CAEA,IAAI,UAAmB;EACtB,OAAO,KAAK,aAAa,SAAS;CACnC;CAEA,IAAI,QAAQ,WAAoB;EAC/B,KAAK,QAAQ,WAAW,SAAS;CAClC;CAEA,IAAI,SAA6B;EAChC,OAAO,KAAK,wBAAwB,QAAQ;CAC7C;CAEA,IAAI,OAAO,OAA2B;EACrC,KAAK,QAAQ,UAAU,KAAK;CAC7B;CAEA,IAAI,aAAqD;EACxD,OAAO,KAAK;CACb;CAEA,IAAI,WAAW,OAA+C;EAC7D,KAAK,cAAc;CACpB;CAEA,IAAI,YAAuC;EAC1C,OAAO,gBAAgB,KAAK,aAAa,WAAW,CAAC;CACtD;CAEA,IAAI,UAAU,WAAsC;EACnD,KAAK,QAAQ,aAAa,WAAW,KAAK,GAAG,CAAC;CAC/C;CAEA,IAAI,UAAmB;EACtB,OAAO,KAAK,aAAa,SAAS;CACnC;CAEA,IAAI,QAAQ,SAAkB;EAC7B,KAAK,QAAQ,WAAW,OAAO;CAChC;CAEA,IAAI,OAAe;EAClB,OAAO,KAAK,gBAAgB,QAAQ,CAAC;CACtC;CAEA,IAAI,KAAK,OAA2B;EACnC,KAAK,QAAQ,QAAQ,KAAK;CAC3B;CAEA,IAAI,QAA0B;EAC7B,OAAO,KAAK,aAAa,OAAO,MAAM,QAAQ,QAAQ;CACvD;CAEA,IAAI,MAAM,OAAqC;EAC9C,KAAK,QAAQ,SAAS,KAAK;CAC5B;CAEA,IAAI,QAAgB;EACnB,OAAO,KAAK;CACb;CAEA,IAAI,MAAM,MAAiC;EAE1C,IAAI,SAAS,UAAa,SAAS,MAAM;GACxC,KAAK,kBAAkB;GACvB;EACD;EAEA,MAAM,QAAQ,SAAS,IAAI;EAE3B,IAAI,KAAK,QAAQ,GAAG;GACnB,KAAK,UAAU,KAAK;GACpB;EACD;EAEA,KAAK,OAAO,KAAK;EACjB,IAAI,OAAO,SAAS,KAAK,GAAG,KAAK,SAAS;CAC3C;CAEA,IAAI,YAAoB;EACvB,OAAO,KAAK,SAAS,KAAK,MAAM;CACjC;CAEA;CAEA,AAAS,SAAS,IAAI,mBAAmB;EACxC,KAAK,YAAY;CAClB,CAAC;CAED;CAEA;CAEA;CAEA,AAAS,YAAY,OAAQ,iBAAiB,CAAE;CAEhD,eAAe;CAEf;CAEA;CAEA;CAGA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA,SAAS;CAET,AAAS,4BAAY,IAAI,IAAgB;CAEzC,yBAAyB,MAAoB;EAC5C,KAAK,WAAW;EAChB,KAAK,aAAa,gBAAgB,KAAK,aAAa,WAAW,CAAC;EAChE,IAAI,SAAS,SAAS;GACrB,IAAI,KAAK,QAAQ,GAAG;IACnB,KAAK,UAAU,KAAK,gBAAgB,SAAS,KAAK,GAAG,CAAC;IACtD;GACD;GAEA,KAAK,SAAS;EACf;EACA,IAAI,SAAS,cAAc,KAAK,WAAW,GAAG,KAAK,UAAU;EAE7D,KAAK,SAAS,KAAK,QAAQ,CAAC,CAAC,KAAK,KAAK,UAAU,KAAK,gBAAgB,SAAS,KAAK,GAAG,CAAC;EACxF,IAAI,qBAAqB,IAAI,IAAI,KAAK,KAAK,QAAQ,GAAG,KAAK,mBAAmB;EAC9E,KAAK,OAAO;CACb;CAEA,AAAS,oBAA0B;EAClC,KAAK,kBACJ,WACA,UACA,eACA,OACA,YACA,OACA,WACA,UACA,WACA,QACA,SACA,aACA,UACA,eACA,qBACA,WACA,cACA,OACD;EACA,MAAM,kBAAkB;CACzB;CAEA,AAAU,aACT,SACA,QACA,MACO;EACP,MAAM,QAAQ,KAAK,WAAW,SAAS,MAAM;EAE7C,KAAK,eAAe,SACnB,SACA;GACC,SAAS,SAAS;IACjB,IAAI,KAAK,mBAAmB,MAAM,KAAK,MAAM,KAAK,SAAS;GAC5D;GACA,OAAO,UAAU;IAChB,IAAI,YAAY,KAAK,KAAK,KAAK,WAAW,KAAK,MAAM,QAAQ;IAE7D,KAAK,YAAY,aAAa,KAAK;IAEnC,IAAI,MAAM,gBAAgB,SAAS,MAAM,eAAe;IACxD,eAAe,OAAO;IACtB,IAAI,aAAa,KAAK,GAAG;KACxB,KAAK,OAAO;KACZ;IACD;IAEA,MAAM,YAAY,KAAK;IACvB,MAAM,OAAO,KAAK,KAAK;IACvB,IAAI,CAAC,MAAM;IAEX,MAAM,OAAkB;KACvB,GAAG;KACH;KACA,WAAW;KACX,YAAY;KACZ,aAAa;KACb,OAAO,KAAK,WAAW,SAAS,MAAM,KAAK;IAC5C;IAEA,KAAK,cAAc,iBAAiB;KACnC,KAAK,QAAQ,IAAI;IAClB,MAAW;IAEX,OAAO;GACR;GACA,OAAO,MAAM,UAAU;IACtB,MAAM,MAAM,KAAK,MAAM,YAAY,SAAY,KAAK,UAAU;IAE9D,IAAI,QAAQ,QAAW;KACtB,MAAM,YAAY;KAClB,KAAK,QAAQ,GAAG;KAChB;IACD;IACA,IAAI,CAAC,MAAM,MAAM,KAAK,KAAK,KAAK,aAAa,MAAM,QAAW;IAE9D,IAAI,KAAK,gBAAgB,SAAS,KAAK,OAAO;SACzC,MAAM,KAAK;GACjB;GACA,OAAO,MAAM,UAAU;IACtB,KAAK,QAAQ,MAAM,KAAK;GACzB;GACA,UAAU,SAAS;IAClB,KAAK,aAAa,IAAI;GACvB;GACA,SAAS,eAAe;IACvB,KAAK,YAAY,YAAY,UAAU;GACxC;EACD,GACA,MACD;EACA,QAAQ,iBACP,uBACM;GACL,MAAM,YAAY;EACnB,GACA,EAAE,OAAO,CACV;EACA,KAAK,UAAU,SAAS,OAAO,MAAM;EACrC,OAAO,iBACN,eACM;GACL,KAAK,aAAa;GAClB,KAAK,kBAAkB;EACxB,GACA,EAAE,MAAM,KAAK,CACd;CACD;CAEA,AAAU,qBAA4D,CAEtE;CAEA,AAAU,cAAuC;EAChD,OAAO;CACR;CAMA,AAAU,WAA+B;EACxC,OAAO,KAAK,UAAU,CAAC,EAAE,aAAa,KAAK,WAAW;CACvD;CAEA,AAAU,UAAU,OAAqB,CAEzC;CAEA,AAAU,cAAoB,CAE9B;CAEA,AAAU,MAAM,MAAuB;EACtC,MAAM,WAAW,KAAK;EAEtB,KAAK,OAAO,KAAK,SAAS,MAAM,MAAM,GAAG,KAAK,MAAM,IAAI,IAAI;EAC5D,IAAI,KAAK,WAAW,UAAU,OAAO;EAErC,KAAK,cAAc,IAAI,MAAM,SAAS;GAAE,SAAS;GAAM,UAAU;EAAK,CAAC,CAAC;EAExE,OAAO;CACR;CAEA,AAAU,YAAqB;EAC9B,OAAO,KAAK,QAAQ,WAAW;CAChC;CAEA,AAAU,aAAsB;EAC/B,OAAO,KAAK,OAAO;CACpB;CAEA,AAAU,aAAsB;EAC/B,OAAO;CACR;CAEA,AAAU,UAAwB;EACjC,IAAI,KAAK,UAAU,OAAO,KAAK;EAE/B,MAAM,EAAE,QAAQ,aAAa;EAE7B,KAAK,WAAW,aAAa;GAC5B,GAAI,WAAW,SAAY,CAAC,IAAI,EAAE,OAAO;GACzC,GAAI,KAAK,aAAa,EAAE,WAAW,KAAK,WAAW,IAAI,CAAC;GACxD,KAAK,KAAK;GACV,GAAI,aAAa,SAAY,CAAC,IAAI,EAAE,SAAS;GAC7C,WAAW,KAAK;GAChB,YAAY,KAAK,WAAW;GAC5B,KAAK,KAAK;GACV,MAAM,KAAK;GACX,OAAO,KAAK;EACb,CAAC;EAED,OAAO,KAAK;CACb;CAEA,AAAU,cAAsB;EAC/B,OAAO,KAAK,UAAU,KAAK,QAAQ,CAAC,CAAC,OAAO;CAC7C;CAEA,AAAU,eAAmC,CAE7C;CAEA,AAAU,qBAA2B,CAErC;CAEA,AAAU,sBAA0C;EACnD,OAAO,KAAK;CACb;CAEA,AAAU,eAAuB;EAChC,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS,KAAK;CACpC;CAEA,AAAU,SAAe;EACxB,IAAI,KAAK,QAAQ,GAAG,KAAK,eAAe;EACxC,KAAK,MAAM,YAAY,KAAK,WAAW,SAAS;CACjD;CAEA,AAAU,gBAAsB;EAC/B,MAAM,UAAU,KAAK;EACrB,IAAI,CAAC,SAAS;EAEd,MAAM,EAAE,QAAQ,UAAU,KAAK,OAAO;EAEtC,QAAQ,OAAO,KAAK;GACnB,QAAQ,QAAQ;GAChB;GACA,MAAM,UAAU,SAAY,SAAY,KAAK,SAAS,KAAK;EAC5D,CAAC;CACF;CAEA,AAAU,aAAa,OAAqB;EAC3C,KAAK,QAAQ,OAAO,KAAK;CAC1B;CAEA,AAAU,kBAA2B;EACpC,OAAO;CACR;CAEA,AAAU,eAAmC,CAE7C;CAEA,AAAU,YAAgC,CAE1C;CAEA,AAAU,SAAS,SAAsB,UAAwC;EAChF,OAAO,KAAK,IAAI,GAAG,eAAe,iBAAiB,OAAO,GAAG,UAAU,gBAAgB,CAAC;CACzF;CAEA,AAAU,qBACT,SACA,QACA,MACO;EACP,MAAM,QAAQ,SAAS,UAAa,SAAS,OAAO,SAAY,SAAS,IAAI;EAC7E,IAAI,UAAU,UAAa,CAAC,OAAO,SAAS,KAAK,GAAG;EAEpD,KAAK,mBAAmB;EACxB,IAAI,KAAK,QAAQ,GAAG,KAAK,2BAA2B,SAAS,MAAM;CACpE;CAEA,AAAU,iBACT,SACA,QACA,YACO;EACP,MAAM,EAAE,UAAU;EAClB,MAAM,UAAU,KAAK,QAAQ;EAC7B,MAAM,QAAQ,QAAQ,aAAa,KAAK,MAAM;EAC9C,MAAM,QAAQ,QAAQ,aAAa,KAAK,SAAS,UAAU;EAC3D,MAAM,EAAE,kBAAkB;EAE1B,MAAM,YAAY,YAAY,OAAO,SAAS,OAAO,KAAK,CAAC;EAC3D,MAAM,YACL,YAAY,OAAO,UACnB,OAAO,QAAQ,aAAa,KAAK,YAAY,CAAC,CAAC,CAChD;EACA,MAAM,YAAY,YAAY,OAAO,mBAAmB,OAAO,KAAK,IAAI,OAAO,KAAK,CAAC,CAAC;EACtF,MAAM,YAAY,YAAY,OAAO,iBAAiB,OAAO,KAAK,IAAI,OAAO,KAAK,CAAC,CAAC;EACpF,IAAI,kBAAkB,QAAW,MAAM,eAAe,YAAY,OAAO,gBAAgB;OACpF,MAAM,YAAY,YAAY,OAAO,kBAAkB,OAAO,aAAa,CAAC;EACjF,KAAK,2BAA2B,SAAS,MAAM;CAChD;CAEA,WAAW,SAAsB,QAAiC;EACjE,MAAM,QAAQ,aAAa,SAAS,SAAS,gBAAgB;EAC7D,MAAM,SAAS,QAAQ,cAA2B,WAAW;EAG7D,MAAM,KAAK,eAAe,KAAK;EAC/B,IAAI,QAAQ,KAAK,WAAW;GAAE,QAAQ;GAAS,QAAQ,IAAI,QAAQ,MAAM;EAAE;EAE3E,MAAM,QAAQ,IAAI,WAAW,OAAO;GACnC,SAAS,SAAS;IAEjB,KAAK,SAAS,KAAK,eAAe,OAAO,WAAU,CAAE,IAAI,CAAC;GAC3D;GAEA,YAAa,KAAK,cAAc,KAAK,YAAY,OAAO,KAAK,MAAM;GACnE,SAAS,WAAW;IACnB,IAAI,QAAQ,KAAK,cAAc,OAAO,IAAI;IAC1C,KAAK,YAAY,WAAW,MAAM;IAClC,KAAK,OAAO;GACb;EACD,CAAC;EAED,KAAK,SAAS;EACd,MAAM,KAAK,SAAS,MAAM;EAE1B,OAAO;CACR;CAEA,UAAU,SAAsB,OAAmB,QAA2B;EAC7E,QAAQ,iBACP,YACC,UAAU;GACV,IAAI,KAAK,WAAW,KAAK,MAAM,oBAAoB,MAAM,WAAW,SAAS;GAE7E,KAAK,YAAY,aAAa,KAAK;GACnC,IAAI,MAAM,QAAQ,SAAS;IAC1B,IAAI,KAAK,aAAa,MAAM,QAAW;IAEvC,MAAM,eAAe;IACrB,MAAM,KAAK;IACX;GACD;GAEA,MAAM,OAAO,KAAK,WAAW,MAAM,GAAG;GACtC,IAAI,SAAS,QAAW;GAExB,MAAM,eAAe;GACrB,KAAK,OAAO,OAAO,IAAI;GACvB,KAAK,OAAO,OAAO,MAAM;GACzB,KAAK,YAAY;EAClB,GACA,EAAE,OAAO,CACV;EACA,QAAQ,iBACP,UACC,UAAU;GAEV,MAAM,SAAS,MAAM,QAAQ;GAE7B,IAAI,UAAU,MAAM,QAAQ,KAAK,WAAW,KAAK,KAAK,aAAa;GACnE,IAAI,UAAU,KAAK,UAAU,GAAG;GAChC,IAAI,UAAU,KAAK,QAAQ,CAAC,CAAC,UAAU,MAAM,KAAK,KAAK,MAAM,MAAM,QAClE,KAAK,YAAY;EAEnB,GACA,EAAE,OAAO,CACV;EACA,QAAQ,iBACP,cACM;GACL,KAAK,aAAa;GAClB,KAAK,kBAAkB;GACvB,KAAK,YAAY;EAClB,GACA,EAAE,OAAO,CACV;CACD;CAEA,QAAQ,MAAc,YAAwB,GAAS;EACtD,MAAM,SAAS,OAAO,SAAS,IAAI,IAAK,KAAK,QAAQ,MAAM,SAAS,KAAK,OAAQ;EAEjF,IAAI,KAAK,MAAM,MAAM,GAAG,KAAK,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;CAClF;CAEA,oBAA0B;EACzB,IAAI,KAAK,OAAO,QAAQ,MAAM,GAAG,KAAK,YAAY;CACnD;CAEA,YAAmC;EAClC,OAAO,KAAK,cAAc,QAAQ;CACnC;CAEA,QAAQ,MAAiB,OAA2B;EACnD,MAAM,YAAY,KAAK,UAAU,KAAK,MAAM;EAC5C,MAAM,aAAa,KAAK,MAAM;EAC9B,MAAM,UAAU,KAAK,QAAQ;EAC7B,MAAM,EAAE,OAAO,UAAU,SAAS,SAAS,KAAK,OAAO;GACtD,QAAQ,MAAM;GACd;GACA,UAAU,KAAK,SAAS,KAAK;EAC9B,CAAC;EAED,KAAK,QAAQ,KAAK,aAAa,SAAS,KAAK;EAC7C,IAAI,UAAU,QAAW;EAEzB,IAAI,CAAC,YAAY,KAAK,QAAQ,IAAI;EAClC,KAAK,MAAM,YAAY,KAAK,YAAY,KAAK;EAC7C,IAAI,cAAc,KAAK,WAAW;EAElC,KAAK,YAAY;EACjB,KAAK,kBAAkB,IAAI;CAC5B;CAEA,YAAkB;EACjB,KAAK,QAAQ,MAAM,KAAK;EACxB,KAAK,cAAc,IAAI;EACvB,KAAK,aAAa;CACnB;CAEA,eAAqB;EACpB,MAAM,QAAQ,KAAK;EACnB,IAAI,CAAC,OAAO;EAEZ,KAAK,YAAY;EACjB,KAAK,YAAY;EACjB,IAAI,KAAK,WAAW,MAAM,WAAW,KAAK,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;CAC/F;CAEA,UAAmB;EAClB,OAAO,KAAK,UAAU,MAAM,UAAa,KAAK,cAAc;CAC7D;CAEA,WAAW,KAAiC;EAC3C,IAAI,UAAU,IAAI,GAAG,GAAG,OAAO,KAAK;EAEpC,OAAO,KAAK,QAAQ,CAAC,CAAC,UAAU,KAAK,KAAK,QAAQ,KAAK,OAAO;CAC/D;CAEA,OAAO,OAAsB,MAAoB;EAChD,IAAI,MAAM,UAAU,KAAK,gBAAgB,GAAG;GAC3C,KAAK,UAAU,MAAM,KAAK,IAAI;GAC9B;EACD;EAEA,KAAK,aAAa;EAClB,KAAK,QAAQ,MAAM,OAAO,KAAK,SAAS,IAAI,EAAE;CAC/C;CAEA,aAAa,MAAuB;EACnC,aAAa,KAAK,WAAW;EAC7B,KAAK,OAAO,QAAQ,MAAM;EAC1B,KAAK,YAAY;EACjB,IAAI,KAAK,WAAW,KAAK,WAAW,KAAK,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;EAC7F,KAAK,YAAY;CAClB;CAEA,YAAY,SAAsB,aAA+C;EAChF,KAAK,eAAe,OAAO,KAAK,MAAM,GAAG,OAAO,KAAK,MAAM,CAAC;EAC5D,IAAI,KAAK,QAAQ,QAAQ;GACxB,KAAK,MAAM,QAAQ,gBAAgB,QAAQ,gBAAgB,IAAI;GAC/D,KAAK,cAAc,SAAS,KAAK;GACjC,KAAK,cAAc;GACnB;EACD;EAEA,MAAM,CAAC,KAAK,QAAQ,KAAK,QAAQ,CAAC,CAAC;EAEnC,eAAe,SAAS,QAAQ,KAAK,YAAY,CAAC;EAClD,eAAe,SAAS,iBAAiB,OAAO,GAAG,CAAC;EACpD,eAAe,SAAS,iBAAiB,OAAO,IAAI,CAAC;EACrD,eAAe,SAAS,iBAAiB,OAAO,KAAK,MAAM,CAAC;EAC5D,IAAI,aAAa,eAAe,SAAS,oBAAoB,WAAW;EACxE,eACC,SACA,mBACC,KAAK,sBAAsB,KAAK,aAAY,GAAI,KAAK,MAAM,CAC7D;EACA,KAAK,cAAc,SAAS,IAAI;EAChC,KAAK,gBAAgB,OAAO;EAC5B,KAAK,cAAc;CACpB;CAEA,iBAAuB;EACtB,KAAK,KAAK;EACV,KAAK,YACJ,aACA,CAAC,KAAK,WAAW,KAAK,KAAK,WAAW,KAAK,QAAQ,CAAC,CAAC,KAAK,KAAK,YAAY,CAAC,CAC7E;EACA,KAAK,YAAY,KAAK,YAAY,GAAG,KAAK,mBAAmB,CAAC;CAC/D;CAEA,gBAAgB,SAA4B;EAC3C,MAAM,aAAa,KAAK,WAAW;EAEnC,eAAe,SAAS,iBAAiB,aAAa,SAAS,MAAS;EAExE,MAAM,OAAO,KAAK,aAAa,UAAU,MAAM,OAAO,OAAO;EAE7D,eAAe,SAAS,YAAY,aAAa,SAAY,IAAI;CAClE;CAEA,kBAAkB,MAAuB;EACxC,IAAI,KAAK,cAAc,CAAC,KAAK,WAAW,KAAK,OAAO,OAAO,MAAM;OAC5D,KAAK,OAAO,QAAQ,MAAM;EAC/B,KAAK,YAAY;CAClB;CAEA,cAAoB;EACnB,KAAK,cAAc;EACnB,KAAK,YAAY;CAClB;CAEA,SAAe;EACd,KAAK,QAAQ,KAAK,WAAW,GAAG;CACjC;CAEA,QAAQ,MAAuB;EAC9B,IAAI,KAAK,cAAc,KAAK,UAAU,MAAM,MAAM;EAElD,KAAK,aAAa;EAClB,KAAK,kBAAkB,IAAI;CAC5B;CAEA,UAAU,KAAa,MAAoB;EAC1C,IAAI,KAAK,WAAW,QAAQ,KAAK;GAChC,KAAK,aAAa;GAClB,KAAK,YAAY;IAAE,WAAW,KAAK;IAAQ;GAAI;EAChD;EACA,KAAK,MAAM,IAAI;CAChB;CAEA,SAAyD;EACxD,IAAI,KAAK,UAAU,GAAG,OAAO;GAAE,QAAQ;GAAM,OAAO;EAAU;EAE9D,MAAM,aAAa,KAAK,OAAO;EAC/B,MAAM,UAAU,aAAa,SAAY,KAAK,aAAa;EAE3D,OAAO;GACN,SAAS,cAAc,YAAY,WAAc,KAAK;GACtD,OAAO,WAAW,KAAK;EACxB;CACD;CAEA,cAAoB;EACnB,MAAM,SAAS,KAAK,aAAa;EACjC,IAAI,WAAW,QAAW;EAG1B,IAAI,KAAK,QAAQ,CAAC,CAAC,KAAK,MAAM,MAAM,KAAK,QAAQ,KAAK,YAAY,aAAa,IAAI;EACnF,KAAK,QAAQ,MAAM;CACpB;CAEA,WAAW,SAAsB,MAAiB,OAAgC;EACjF,MAAM,UAAU,KAAK,QAAQ;EAC7B,MAAM,SAAS,KAAK;EACpB,MAAM,QAAQ;GACb,MAAM,KAAK;GACX,UAAU,KAAK,SAAS,KAAK;GAC7B,YAAY,KAAK,kBAAkB,QAAQ,aAAa,KAAK,MAAM;GACnE,aAAa,gBAAgB,MAAM,WAAW;GAC9C,UAAU,KAAK;EAChB;EACA,IAAI,WAAW,QAAW,OAAO,UAAU,SAAS,KAAK;EAEzD,MAAM,SAAS,eAAe,iBAAiB,OAAO,GAAG,wBAAwB,YAAY;EAE7F,OAAO,UAAU,SAAS;GACzB,GAAG;GACH,QAAQ;IAAE,OAAO;IAAQ,MAAM,SAAS,KAAK;GAAS;EACvD,CAAC;CACF;CAEA,SAAS,OAAuB;EAC/B,OAAO,KAAK,eAAe,KAAK,KAAK,OAAO,KAAK;CAClD;CAEA,aAAa,SAAuB,OAA6B;EAChE,MAAM,QAAQ,KAAK;EACnB,IAAI,CAAC,SAAS,QAAQ,YAAY,OAAO;EAEzC,MAAM,CAAC,KAAK,QAAQ;EAEpB,OAAO;GACN,GAAG;GACH,eAAe,MACd,MAAM,eACN,QAAQ,aAAa,GAAG,GACxB,QAAQ,aAAa,IAAI,CAC1B;EACD;CACD;CAEA,OAAO,MAAoB;EAC1B,IAAI,CAAC,OAAO,SAAS,IAAI,GAAG;EAE5B,MAAM,UAAU,KAAK,QAAQ,CAAC,CAAC,KAAK,IAAI;EAExC,KAAK,SAAS;EACd,IAAI,YAAY,KAAK,QAAQ;EAE7B,KAAK,SAAS;EACd,KAAK,OAAO;CACb;CAEA,2BAA2B,SAAsB,QAAiC;EACjF,MAAM,kBAAkB,KAAK,WAAW,IAAI,SAAY,KAAK;EAC7D,MAAM,cAAc,oBAAoB;EAExC,IAAI,gBAAgB,KAAK,cAAc;GACtC,KAAK,eAAe;GACpB,KAAK,YAAY,aAAa,WAAW;EAC1C;EACA,IAAI,oBAAoB,QAAW;GAClC,QAAQ,MAAM,eAAe,YAAY,OAAO,kBAAkB;GAClE;EACD;EAEA,QAAQ,MAAM,YACb,YAAY,OAAO,oBACnB,OAAO,KAAK,QAAQ,CAAC,CAAC,aAAa,eAAe,CAAC,CACpD;CACD;AACD"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TimeRegions } from "../lib/time-regions.js";
|
|
1
2
|
import { SurfaceFrame } from "../lib/canvas-surface.js";
|
|
2
3
|
import { SonicWaveElement } from "./wave-element.js";
|
|
3
4
|
//#region src/elements/wavestrip.d.ts
|
|
@@ -21,6 +22,8 @@ declare const lengths: {
|
|
|
21
22
|
};
|
|
22
23
|
export declare class SonicWavestrip extends SonicWaveElement<Colour, Length> {
|
|
23
24
|
#private;
|
|
25
|
+
get buffered(): Array<[number, number]>;
|
|
26
|
+
set buffered(regions: TimeRegions | undefined);
|
|
24
27
|
get cancellable(): boolean;
|
|
25
28
|
set cancellable(isCancellable: boolean);
|
|
26
29
|
get peaks(): ArrayLike<number> | undefined;
|
|
@@ -44,6 +47,7 @@ export declare class SonicWavestrip extends SonicWaveElement<Colour, Length> {
|
|
|
44
47
|
protected draw(): void;
|
|
45
48
|
protected isEmpty(): boolean;
|
|
46
49
|
protected paint(context: CanvasRenderingContext2D, frame: SurfaceFrame<Colour, Length>): void;
|
|
50
|
+
protected previewValue(): number | undefined;
|
|
47
51
|
protected renderMarkers(): void;
|
|
48
52
|
protected scrubsKeyRepeat(): boolean;
|
|
49
53
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { clampProportion } from "../lib/math.js";
|
|
2
2
|
import { requireChild, template } from "../lib/render.js";
|
|
3
3
|
import { readPxProperty } from "../lib/read-px-property.js";
|
|
4
|
+
import { sortedRegions } from "../lib/time-regions.js";
|
|
4
5
|
import { SonicWaveElement } from "./wave-element.js";
|
|
5
6
|
import { createMarkerBand } from "../lib/marker-band.js";
|
|
6
7
|
import { stripBars, stripRegions } from "../lib/strip-scene.js";
|
|
@@ -45,6 +46,13 @@ function fillRegion(context, path, [from, to, style]) {
|
|
|
45
46
|
context.restore();
|
|
46
47
|
}
|
|
47
48
|
var SonicWavestrip = class extends SonicWaveElement {
|
|
49
|
+
get buffered() {
|
|
50
|
+
return this.#buffered.map(([start, end]) => [start, end]);
|
|
51
|
+
}
|
|
52
|
+
set buffered(regions) {
|
|
53
|
+
this.#buffered = sortedRegions(regions);
|
|
54
|
+
this.render();
|
|
55
|
+
}
|
|
48
56
|
get cancellable() {
|
|
49
57
|
return this.hasAttribute("cancellable");
|
|
50
58
|
}
|
|
@@ -65,11 +73,15 @@ var SonicWavestrip = class extends SonicWaveElement {
|
|
|
65
73
|
lengths = lengths;
|
|
66
74
|
sheet = "wavestrip.css";
|
|
67
75
|
#bars;
|
|
76
|
+
#buffered = [];
|
|
77
|
+
#escapeWatch;
|
|
78
|
+
#hover;
|
|
79
|
+
#isHoverDismissed = false;
|
|
68
80
|
#markerBand = createMarkerBand(requireChild(this.control, ".sonic-wavestrip-markers", HTMLDivElement));
|
|
69
81
|
#paintedKey = "";
|
|
70
82
|
#peaks;
|
|
71
83
|
connectedCallback() {
|
|
72
|
-
this.upgradeProperties("cancellable", "peaks");
|
|
84
|
+
this.upgradeProperties("buffered", "cancellable", "peaks");
|
|
73
85
|
super.connectedCallback();
|
|
74
86
|
}
|
|
75
87
|
connect(signal) {
|
|
@@ -79,6 +91,7 @@ var SonicWavestrip = class extends SonicWaveElement {
|
|
|
79
91
|
}
|
|
80
92
|
draw() {
|
|
81
93
|
const surface = this.surface();
|
|
94
|
+
if (this.isEditing() || this.isRevealed()) this.#hover = void 0;
|
|
82
95
|
this.#placeReadout();
|
|
83
96
|
if (surface && this.#stripRegions(surface.size.width).key !== this.#paintedKey) surface.requestFrame();
|
|
84
97
|
}
|
|
@@ -100,6 +113,9 @@ var SonicWavestrip = class extends SonicWaveElement {
|
|
|
100
113
|
look.colours[kind]
|
|
101
114
|
]);
|
|
102
115
|
}
|
|
116
|
+
previewValue() {
|
|
117
|
+
return this.#hover;
|
|
118
|
+
}
|
|
103
119
|
renderMarkers() {
|
|
104
120
|
this.#markerBand.render(this.markerList(), this.markerProportions());
|
|
105
121
|
}
|
|
@@ -131,11 +147,11 @@ var SonicWavestrip = class extends SonicWaveElement {
|
|
|
131
147
|
const axis = this.#axis();
|
|
132
148
|
const at = clampProportion((event.clientX - axis.startPx) / axis.travelPx);
|
|
133
149
|
const mapping = this.mapping();
|
|
134
|
-
this
|
|
150
|
+
this.#hoverAt(this.#markerAt(event, axis) ?? mapping.snap(mapping.valueAt(at)));
|
|
135
151
|
this.#placeReadout();
|
|
136
152
|
}, { signal });
|
|
137
153
|
for (const type of ["pointerdown", "pointerleave"]) strip.addEventListener(type, () => {
|
|
138
|
-
this
|
|
154
|
+
this.#hoverAt(void 0);
|
|
139
155
|
}, { signal });
|
|
140
156
|
}
|
|
141
157
|
#grab(event) {
|
|
@@ -153,6 +169,12 @@ var SonicWavestrip = class extends SonicWaveElement {
|
|
|
153
169
|
outside
|
|
154
170
|
} : grabbed;
|
|
155
171
|
}
|
|
172
|
+
#hoverAt(value) {
|
|
173
|
+
if (value === void 0) this.#isHoverDismissed = false;
|
|
174
|
+
if (!this.#isHoverDismissed && !this.isEditing() && !this.isRevealed()) this.#hover = value;
|
|
175
|
+
this.renderReadout();
|
|
176
|
+
this.#watchEscape(value !== void 0);
|
|
177
|
+
}
|
|
156
178
|
#markerAt(event, { startPx, topPx, travelPx }) {
|
|
157
179
|
const index = this.#markerBand.at({
|
|
158
180
|
x: event.clientX - startPx,
|
|
@@ -174,11 +196,27 @@ var SonicWavestrip = class extends SonicWaveElement {
|
|
|
174
196
|
const { proportionOf } = this.mapping();
|
|
175
197
|
const isScrubbing = this.heldFrom() !== void 0 && this.isRevealed();
|
|
176
198
|
return stripRegions({
|
|
177
|
-
buffered: this
|
|
199
|
+
buffered: this.#buffered.map(([start, end]) => [proportionOf(start), proportionOf(end)]),
|
|
178
200
|
played: proportionOf(this.playback()),
|
|
179
201
|
...isScrubbing ? { scrub: proportionOf(this.value) } : {}
|
|
180
202
|
}, width);
|
|
181
203
|
}
|
|
204
|
+
#watchEscape(isHovered) {
|
|
205
|
+
if (!isHovered) {
|
|
206
|
+
this.#escapeWatch?.abort();
|
|
207
|
+
this.#escapeWatch = void 0;
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (this.#escapeWatch) return;
|
|
211
|
+
const watch = new AbortController();
|
|
212
|
+
this.#escapeWatch = watch;
|
|
213
|
+
this.ownerDocument.addEventListener("keydown", (event) => {
|
|
214
|
+
if (event.key !== "Escape" || this.#hover === void 0) return;
|
|
215
|
+
this.#hover = void 0;
|
|
216
|
+
this.#isHoverDismissed = true;
|
|
217
|
+
this.render();
|
|
218
|
+
}, { signal: watch.signal });
|
|
219
|
+
}
|
|
182
220
|
};
|
|
183
221
|
|
|
184
222
|
//#endregion
|