@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,9 @@
|
|
|
1
|
-
import { placeChildren, requireChild, template } from "../lib/render.js";
|
|
2
1
|
import { writeAttribute } from "../lib/write-attribute.js";
|
|
3
2
|
import { SonicFormElement } from "./form-element.js";
|
|
4
3
|
import { copyNode } from "../lib/copy-node.js";
|
|
5
4
|
import { bindHold } from "../lib/hold.js";
|
|
5
|
+
import { placeChildren, requireChild, template } from "../lib/render.js";
|
|
6
|
+
import { mirrorChildren } from "../lib/mirror-children.js";
|
|
6
7
|
|
|
7
8
|
//#region src/elements/button.ts
|
|
8
9
|
const renderButton = template(`
|
|
@@ -88,7 +89,7 @@ var SonicButton = class extends SonicFormElement {
|
|
|
88
89
|
const button = this.#button;
|
|
89
90
|
const cap = requireChild(button, ".sonic-button-cap", HTMLSpanElement);
|
|
90
91
|
this.upgradeProperties("armed", "busy", "defaultPressed", "momentary", "softDisabled", "latching", "pressed", "value");
|
|
91
|
-
|
|
92
|
+
mirrorChildren(this, {
|
|
92
93
|
control: button,
|
|
93
94
|
copy: copyNode,
|
|
94
95
|
place: (copies) => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { requireChild, template } from "../lib/render.js";
|
|
2
2
|
import { SonicValueElement } from "./value-element.js";
|
|
3
|
+
import { bindScale } from "./scale.js";
|
|
3
4
|
|
|
4
5
|
//#region src/elements/dial.ts
|
|
5
6
|
const renderDial = template(`
|
|
@@ -54,7 +55,10 @@ var SonicDial = class extends SonicValueElement {
|
|
|
54
55
|
}
|
|
55
56
|
connect(signal) {
|
|
56
57
|
const dial = this.#dial;
|
|
57
|
-
|
|
58
|
+
bindScale(this, {
|
|
59
|
+
control: dial,
|
|
60
|
+
marks: requireChild(dial, ".sonic-dial-scale", HTMLDivElement)
|
|
61
|
+
}, signal);
|
|
58
62
|
this.render();
|
|
59
63
|
this.checkStyles(dial, "dial.css");
|
|
60
64
|
this.bindGestures(dial, signal, () => ({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { requireChild, template } from "../lib/render.js";
|
|
2
1
|
import { writeAttribute } from "../lib/write-attribute.js";
|
|
3
2
|
import { SonicElement } from "./sonic-element.js";
|
|
3
|
+
import { requireChild, template } from "../lib/render.js";
|
|
4
4
|
import { ReadoutClaim } from "./readout-claim.js";
|
|
5
5
|
import { Readout } from "./readout.js";
|
|
6
6
|
import { dragThresholdPx } from "../lib/drag-step.js";
|
|
@@ -44,6 +44,7 @@ function stageParts(envelope, hook, stages) {
|
|
|
44
44
|
}
|
|
45
45
|
const renderEnvelope = template(`
|
|
46
46
|
<div class="sonic-envelope" aria-hidden="true">
|
|
47
|
+
<div class="sonic-envelope-bracket"></div>
|
|
47
48
|
<svg class="sonic-envelope-graph" preserveAspectRatio="none" viewBox="0 0 1 1">
|
|
48
49
|
<path class="sonic-envelope-fill" />
|
|
49
50
|
<rect class="sonic-envelope-fill sonic-envelope-floor" y="1" />
|
|
@@ -127,15 +128,17 @@ var SonicEnvelope = class extends SonicElement {
|
|
|
127
128
|
this.reflect("sustain", id);
|
|
128
129
|
}
|
|
129
130
|
#bindings = /* @__PURE__ */ new Map();
|
|
131
|
+
#envelope = renderEnvelope();
|
|
132
|
+
#bracket = requireChild(this.#envelope, ".sonic-envelope-bracket", HTMLDivElement);
|
|
130
133
|
#claim = new ReadoutClaim(() => {
|
|
131
134
|
this.#renderReadout();
|
|
132
135
|
});
|
|
133
|
-
#envelope = renderEnvelope();
|
|
134
136
|
#curveHandles = stageParts(this.#envelope, "sonic-envelope-curve", curveStages);
|
|
135
137
|
#fill = requireChild(this.#envelope, ".sonic-envelope-fill", SVGElement);
|
|
136
138
|
#floor = requireChild(this.#envelope, ".sonic-envelope-floor", SVGElement);
|
|
137
139
|
#graph = requireChild(this.#envelope, ".sonic-envelope-graph", SVGElement);
|
|
138
140
|
#handles = stageParts(this.#envelope, "sonic-envelope-handle", timeStages);
|
|
141
|
+
#held;
|
|
139
142
|
#isDriving = false;
|
|
140
143
|
#line = requireChild(this.#envelope, ".sonic-envelope-line", SVGElement);
|
|
141
144
|
#pointerDrag;
|
|
@@ -232,8 +235,15 @@ var SonicEnvelope = class extends SonicElement {
|
|
|
232
235
|
at: shape.curveHandles.find((point) => point.stage === stage),
|
|
233
236
|
drives: this.#curveDrives(stage)
|
|
234
237
|
});
|
|
238
|
+
this.#drawBracket();
|
|
235
239
|
this.#renderReadout();
|
|
236
240
|
}
|
|
241
|
+
#drawBracket() {
|
|
242
|
+
const part = this.#held;
|
|
243
|
+
if (!part) return;
|
|
244
|
+
for (const name of ["--_sonic-envelope-x", "--_sonic-envelope-y"]) this.#bracket.style.setProperty(name, part.style.getPropertyValue(name));
|
|
245
|
+
writeAttribute(this.#bracket, "data-sonic-part", part.classList.contains("sonic-envelope-curve") ? "curve" : void 0);
|
|
246
|
+
}
|
|
237
247
|
#drawPoint(part, point) {
|
|
238
248
|
const { at, drives } = point;
|
|
239
249
|
writeAttribute(part, "hidden", at ? void 0 : "");
|
|
@@ -260,6 +270,8 @@ var SonicEnvelope = class extends SonicElement {
|
|
|
260
270
|
if (!pressed || pressed.drives.length === 0) return void 0;
|
|
261
271
|
const { drives, isFlipped, part } = pressed;
|
|
262
272
|
this.#claim.press(true);
|
|
273
|
+
this.#held = part;
|
|
274
|
+
this.#drawBracket();
|
|
263
275
|
const box = this.#graph.getBoundingClientRect();
|
|
264
276
|
const travel = {
|
|
265
277
|
x: Math.max(1, box.width * this.#shape.share),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { toNumber } from "../lib/math.js";
|
|
2
|
-
import { template } from "../lib/render.js";
|
|
3
2
|
import { SonicElement } from "./sonic-element.js";
|
|
3
|
+
import { template } from "../lib/render.js";
|
|
4
4
|
import { parseNumberList } from "../lib/number-list.js";
|
|
5
5
|
import { linearTaper } from "../lib/taper.js";
|
|
6
6
|
import { ballisticsRates, fall, rise, stepNeedle } from "../lib/ballistics.js";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { placeChildren } from "../lib/render.js";
|
|
2
1
|
import { writeAttribute } from "../lib/write-attribute.js";
|
|
3
2
|
import { SonicFormElement } from "./form-element.js";
|
|
4
3
|
import { copyNode } from "../lib/copy-node.js";
|
|
4
|
+
import { placeChildren } from "../lib/render.js";
|
|
5
|
+
import { mirrorChildren } from "../lib/mirror-children.js";
|
|
5
6
|
import { bindDrag } from "../lib/pointer-drag.js";
|
|
6
7
|
|
|
7
8
|
//#region src/elements/radio-group.ts
|
|
@@ -48,7 +49,7 @@ var SonicRadioGroupElement = class extends SonicFormElement {
|
|
|
48
49
|
connect(signal) {
|
|
49
50
|
const group = this.group;
|
|
50
51
|
this.upgradeProperties("value");
|
|
51
|
-
|
|
52
|
+
mirrorChildren(this, {
|
|
52
53
|
control: group,
|
|
53
54
|
copy: copyNode,
|
|
54
55
|
isCopied: (child) => child instanceof Element && child.matches("[data-sonic-value]"),
|
|
@@ -6,10 +6,7 @@ var ReadoutClaim = class {
|
|
|
6
6
|
return this.#isDragging || this.#keyTimer !== void 0;
|
|
7
7
|
}
|
|
8
8
|
#holdTimer;
|
|
9
|
-
#hover;
|
|
10
|
-
#isDismissed = false;
|
|
11
9
|
#isDragging = false;
|
|
12
|
-
#isEditing = false;
|
|
13
10
|
#keyTimer;
|
|
14
11
|
#onLapse;
|
|
15
12
|
constructor(onLapse) {
|
|
@@ -27,21 +24,6 @@ var ReadoutClaim = class {
|
|
|
27
24
|
this.#keyTimer = void 0;
|
|
28
25
|
return wasTimed;
|
|
29
26
|
}
|
|
30
|
-
dismiss() {
|
|
31
|
-
const wasHovered = this.#hover !== void 0;
|
|
32
|
-
this.#hover = void 0;
|
|
33
|
-
this.#isDismissed = wasHovered || this.#isDismissed;
|
|
34
|
-
return wasHovered;
|
|
35
|
-
}
|
|
36
|
-
edit(isOpen) {
|
|
37
|
-
this.#isEditing = isOpen;
|
|
38
|
-
if (isOpen) this.#hover = void 0;
|
|
39
|
-
}
|
|
40
|
-
hover(value) {
|
|
41
|
-
if (value === void 0) this.#isDismissed = false;
|
|
42
|
-
if (this.#isDismissed || this.#isEditing || this.isRevealed) return;
|
|
43
|
-
this.#hover = value;
|
|
44
|
-
}
|
|
45
27
|
press(isDown) {
|
|
46
28
|
this.conceal("drag");
|
|
47
29
|
if (!isDown) {
|
|
@@ -54,7 +36,6 @@ var ReadoutClaim = class {
|
|
|
54
36
|
}, 250);
|
|
55
37
|
}
|
|
56
38
|
reveal(by) {
|
|
57
|
-
this.#hover = void 0;
|
|
58
39
|
if (by === "drag") {
|
|
59
40
|
this.#isDragging = true;
|
|
60
41
|
return;
|
|
@@ -65,16 +46,6 @@ var ReadoutClaim = class {
|
|
|
65
46
|
this.#onLapse();
|
|
66
47
|
}, keyRevealMs);
|
|
67
48
|
}
|
|
68
|
-
shown(current, isReadout) {
|
|
69
|
-
if (this.#isEditing) return {
|
|
70
|
-
isOpen: true,
|
|
71
|
-
value: void 0
|
|
72
|
-
};
|
|
73
|
-
return {
|
|
74
|
-
isOpen: (this.isRevealed || this.#hover !== void 0) && isReadout,
|
|
75
|
-
value: this.#hover ?? current
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
49
|
};
|
|
79
50
|
|
|
80
51
|
//#endregion
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { copyNode } from "../lib/copy-node.js";
|
|
2
|
+
import { placeChildren } from "../lib/render.js";
|
|
3
|
+
import { mirrorChildren } from "../lib/mirror-children.js";
|
|
4
|
+
import { linkValue } from "./value-element.js";
|
|
5
|
+
|
|
6
|
+
//#region src/elements/scale.ts
|
|
7
|
+
function scaleValue(mark) {
|
|
8
|
+
const text = mark.dataset.sonicValue?.trim();
|
|
9
|
+
return text ? Number(text) : NaN;
|
|
10
|
+
}
|
|
11
|
+
function scaleMark(original) {
|
|
12
|
+
const mark = copyNode(original);
|
|
13
|
+
if (!(mark instanceof HTMLElement || mark instanceof SVGElement)) return void 0;
|
|
14
|
+
if (!Number.isFinite(scaleValue(mark))) return void 0;
|
|
15
|
+
const isTick = mark.childElementCount === 0 && mark.textContent.trim() === "";
|
|
16
|
+
mark.classList.add(isTick ? "sonic-scale-tick" : "sonic-scale-label");
|
|
17
|
+
return mark;
|
|
18
|
+
}
|
|
19
|
+
function bindScale(element, { control, marks }, signal) {
|
|
20
|
+
const { mapping, watch } = linkValue(element);
|
|
21
|
+
const render = () => {
|
|
22
|
+
const { proportionOf } = mapping();
|
|
23
|
+
for (const mark of marks.children) {
|
|
24
|
+
if (!(mark instanceof HTMLElement || mark instanceof SVGElement)) continue;
|
|
25
|
+
const at = String(proportionOf(scaleValue(mark)));
|
|
26
|
+
if (mark.style.getPropertyValue("--_sonic-scale-at") !== at) mark.style.setProperty("--_sonic-scale-at", at);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
mirrorChildren(element, {
|
|
30
|
+
control,
|
|
31
|
+
copy: scaleMark,
|
|
32
|
+
isCopied: (child) => child instanceof Element && child.matches("[data-sonic-value]"),
|
|
33
|
+
isPassed: (child) => child instanceof Element && child.matches(".sonic-led"),
|
|
34
|
+
place: (copies) => {
|
|
35
|
+
placeChildren(marks, copies);
|
|
36
|
+
render();
|
|
37
|
+
}
|
|
38
|
+
}, signal);
|
|
39
|
+
signal.addEventListener("abort", watch(render), { once: true });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
export { bindScale };
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { requireChild, template } from "../lib/render.js";
|
|
2
2
|
import { SonicValueElement } from "./value-element.js";
|
|
3
|
+
import { bindScale } from "./scale.js";
|
|
4
|
+
import { sortedRegions } from "../lib/time-regions.js";
|
|
3
5
|
|
|
4
6
|
//#region src/elements/slider.ts
|
|
5
7
|
function grooveStop(proportion) {
|
|
@@ -34,6 +36,13 @@ var SonicSlider = class extends SonicValueElement {
|
|
|
34
36
|
"orientation",
|
|
35
37
|
"spring"
|
|
36
38
|
];
|
|
39
|
+
get buffered() {
|
|
40
|
+
return this.#buffered.map(([start, end]) => [start, end]);
|
|
41
|
+
}
|
|
42
|
+
set buffered(regions) {
|
|
43
|
+
this.#buffered = sortedRegions(regions);
|
|
44
|
+
this.render();
|
|
45
|
+
}
|
|
37
46
|
get groovePress() {
|
|
38
47
|
return this.getAttribute("groove-press") === "none" ? "none" : "jump";
|
|
39
48
|
}
|
|
@@ -64,15 +73,19 @@ var SonicSlider = class extends SonicValueElement {
|
|
|
64
73
|
set spring(isSpring) {
|
|
65
74
|
this.reflect("spring", isSpring);
|
|
66
75
|
}
|
|
76
|
+
#buffered = [];
|
|
67
77
|
#slider = renderSlider();
|
|
68
78
|
connectedCallback() {
|
|
69
|
-
this.upgradeProperties("groovePress", "modulationValue", "modulation", "orientation", "spring");
|
|
79
|
+
this.upgradeProperties("buffered", "groovePress", "modulationValue", "modulation", "orientation", "spring");
|
|
70
80
|
super.connectedCallback();
|
|
71
81
|
}
|
|
72
82
|
connect(signal) {
|
|
73
83
|
const slider = this.#slider;
|
|
74
84
|
const cap = requireChild(slider, ".sonic-slider-cap", HTMLDivElement);
|
|
75
|
-
|
|
85
|
+
bindScale(this, {
|
|
86
|
+
control: slider,
|
|
87
|
+
marks: requireChild(slider, ".sonic-slider-scale", HTMLDivElement)
|
|
88
|
+
}, signal);
|
|
76
89
|
slider.addEventListener("transitionend", (event) => {
|
|
77
90
|
if (event.propertyName === "--_sonic-slider-value") this.toggleState("springing", false);
|
|
78
91
|
}, { signal });
|
|
@@ -113,7 +126,7 @@ var SonicSlider = class extends SonicValueElement {
|
|
|
113
126
|
};
|
|
114
127
|
}
|
|
115
128
|
#renderBuffered(slider) {
|
|
116
|
-
const buffered = this
|
|
129
|
+
const buffered = this.#buffered;
|
|
117
130
|
if (buffered.length === 0) {
|
|
118
131
|
slider.style.removeProperty("--_sonic-slider-buffered-regions");
|
|
119
132
|
return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { toNumber } from "../lib/math.js";
|
|
2
|
-
import {
|
|
2
|
+
import { appendOnce } from "../lib/owned-control.js";
|
|
3
3
|
import { writeAttribute } from "../lib/write-attribute.js";
|
|
4
4
|
|
|
5
5
|
//#region src/elements/sonic-element.ts
|
|
@@ -23,7 +23,6 @@ var SonicElement = class extends HTMLElement {
|
|
|
23
23
|
}
|
|
24
24
|
internals = "attachInternals" in HTMLElement.prototype ? this.attachInternals() : void 0;
|
|
25
25
|
#connection;
|
|
26
|
-
#slots;
|
|
27
26
|
blur() {
|
|
28
27
|
this.#focused()?.blur();
|
|
29
28
|
}
|
|
@@ -77,8 +76,7 @@ var SonicElement = class extends HTMLElement {
|
|
|
77
76
|
}
|
|
78
77
|
keepControl(control, signal) {
|
|
79
78
|
const keep = () => {
|
|
80
|
-
|
|
81
|
-
this.#checkChildren([...this.childNodes].filter((child) => child !== control));
|
|
79
|
+
appendOnce(this, control);
|
|
82
80
|
};
|
|
83
81
|
const observer = new MutationObserver(keep);
|
|
84
82
|
keep();
|
|
@@ -87,50 +85,6 @@ var SonicElement = class extends HTMLElement {
|
|
|
87
85
|
observer.disconnect();
|
|
88
86
|
}, { once: true });
|
|
89
87
|
}
|
|
90
|
-
mirrorChildren({ control, copy, isCopied = () => true, isPassed = () => false, place }, signal) {
|
|
91
|
-
const slots = this.#slots ?? attachSlots(this);
|
|
92
|
-
let copies = /* @__PURE__ */ new Map();
|
|
93
|
-
this.#slots = slots;
|
|
94
|
-
const mirror = (touched) => {
|
|
95
|
-
this.#appendOnce(control);
|
|
96
|
-
const children = [...this.childNodes].filter((child) => child !== control);
|
|
97
|
-
const slotted = children.filter((child) => child instanceof Element || child instanceof Text);
|
|
98
|
-
const kept = copies;
|
|
99
|
-
const originals = children.filter((child) => isCopied(child));
|
|
100
|
-
this.#checkMirrored(originals);
|
|
101
|
-
this.#checkChildren(children.filter((child) => !isCopied(child) && !isPassed(child)));
|
|
102
|
-
copies = new Map(originals.map((original) => [original, touched && !touched.has(original) && kept.has(original) ? kept.get(original) : copy(original)]));
|
|
103
|
-
place([...copies.values()].filter((made) => made !== void 0));
|
|
104
|
-
slots.shown.assign(...slotted.filter((child) => !isCopied(child)), control);
|
|
105
|
-
slots.kept.assign(...slotted.filter((child) => isCopied(child)));
|
|
106
|
-
};
|
|
107
|
-
const watch = () => {
|
|
108
|
-
observer.disconnect();
|
|
109
|
-
observer.observe(this, { childList: true });
|
|
110
|
-
for (const child of this.childNodes) {
|
|
111
|
-
if (child === control) continue;
|
|
112
|
-
observer.observe(child, {
|
|
113
|
-
attributes: true,
|
|
114
|
-
characterData: true,
|
|
115
|
-
childList: true,
|
|
116
|
-
subtree: true
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
const observer = new MutationObserver((records) => {
|
|
121
|
-
const changes = records.filter((record) => this.#isCopiedChange(record, control, isCopied));
|
|
122
|
-
if (changes.length === 0) return;
|
|
123
|
-
if (changes.some((record) => record.target === this)) {
|
|
124
|
-
mirror();
|
|
125
|
-
watch();
|
|
126
|
-
} else mirror(new Set(changes.map((record) => this.#childHolding(record.target))));
|
|
127
|
-
});
|
|
128
|
-
mirror();
|
|
129
|
-
watch();
|
|
130
|
-
signal.addEventListener("abort", () => {
|
|
131
|
-
observer.disconnect();
|
|
132
|
-
}, { once: true });
|
|
133
|
-
}
|
|
134
88
|
namingLabels() {
|
|
135
89
|
return [];
|
|
136
90
|
}
|
|
@@ -161,30 +115,11 @@ var SonicElement = class extends HTMLElement {
|
|
|
161
115
|
this[name] = value;
|
|
162
116
|
}
|
|
163
117
|
}
|
|
164
|
-
#appendOnce(control) {
|
|
165
|
-
const [hook] = control.classList;
|
|
166
|
-
const stale = [...this.children].filter((child) => child !== control && hook !== void 0 && child.classList.contains(hook));
|
|
167
|
-
for (const child of stale) child.remove();
|
|
168
|
-
if (control.parentNode !== this) this.append(control);
|
|
169
|
-
}
|
|
170
|
-
#checkChildren(undocumented) {}
|
|
171
|
-
#checkMirrored(originals) {}
|
|
172
|
-
#childHolding(node) {
|
|
173
|
-
let current = node;
|
|
174
|
-
while (current && current.parentNode !== this) current = current.parentNode;
|
|
175
|
-
return current ?? void 0;
|
|
176
|
-
}
|
|
177
118
|
#focused() {
|
|
178
119
|
const root = this.getRootNode();
|
|
179
120
|
const active = root instanceof ShadowRoot ? root.activeElement : this.ownerDocument.activeElement;
|
|
180
121
|
return active instanceof HTMLElement && this.contains(active) ? active : void 0;
|
|
181
122
|
}
|
|
182
|
-
#isCopiedChange(record, control, isCopied) {
|
|
183
|
-
if (record.target === this) return record.removedNodes.length > 0 || [...record.addedNodes].some((node) => node !== control);
|
|
184
|
-
const child = this.#childHolding(record.target);
|
|
185
|
-
if (child === void 0) return false;
|
|
186
|
-
return isCopied(child) || record.type === "attributes" && record.target === child;
|
|
187
|
-
}
|
|
188
123
|
};
|
|
189
124
|
|
|
190
125
|
//#endregion
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { clamp } from "../lib/math.js";
|
|
2
|
-
import { requireChild, template } from "../lib/render.js";
|
|
3
2
|
import { writeAttribute } from "../lib/write-attribute.js";
|
|
4
3
|
import { bindHold } from "../lib/hold.js";
|
|
4
|
+
import { requireChild, template } from "../lib/render.js";
|
|
5
5
|
import { bindDrag } from "../lib/pointer-drag.js";
|
|
6
6
|
import { SonicRadioGroupElement, isUnder, optionValue } from "./radio-group.js";
|
|
7
7
|
|
|
@@ -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;
|