@xsynaptic/sonic-ui 0.25.1 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +1 -1
- package/dist/default/elements/{display-element.js → analyser-element.js} +10 -12
- package/dist/default/elements/button.js +12 -6
- package/dist/default/elements/dial.js +9 -10
- package/dist/default/elements/envelope.js +26 -20
- package/dist/default/elements/field-gesture.js +49 -8
- package/dist/default/elements/meter.js +6 -5
- package/dist/default/elements/number.js +5 -11
- package/dist/default/elements/position-group.js +4 -4
- package/dist/default/elements/radio-group.js +7 -7
- package/dist/default/elements/region-layer.js +3 -1
- package/dist/default/elements/region.js +5 -1
- package/dist/default/elements/segmented.js +7 -4
- package/dist/default/elements/slider.js +12 -10
- package/dist/default/elements/sonic-element.js +10 -13
- package/dist/default/elements/spectrum.js +3 -3
- package/dist/default/elements/switch.js +11 -6
- package/dist/default/elements/toggle.js +16 -10
- package/dist/default/elements/value-element.js +26 -4
- package/dist/default/elements/wave-element.js +11 -9
- package/dist/default/elements/waveform.js +1 -4
- package/dist/default/elements/wavestrip.js +1 -1
- package/dist/default/elements/xy.js +34 -44
- package/dist/default/lib/canvas-surface.js +35 -2
- package/dist/default/lib/key-press.js +2 -2
- package/dist/default/lib/render.js +2 -2
- package/dist/dev/elements/{display-element.d.ts → analyser-element.d.ts} +3 -3
- package/dist/dev/elements/{display-element.js → analyser-element.js} +11 -14
- package/dist/dev/elements/analyser-element.js.map +1 -0
- package/dist/dev/elements/button.d.ts +4 -0
- package/dist/dev/elements/button.js +12 -11
- package/dist/dev/elements/button.js.map +1 -1
- package/dist/dev/elements/dial.d.ts +4 -1
- package/dist/dev/elements/dial.js +9 -14
- package/dist/dev/elements/dial.js.map +1 -1
- package/dist/dev/elements/envelope.d.ts +5 -0
- package/dist/dev/elements/envelope.js +26 -24
- package/dist/dev/elements/envelope.js.map +1 -1
- package/dist/dev/elements/field-gesture.js +49 -8
- package/dist/dev/elements/field-gesture.js.map +1 -1
- package/dist/dev/elements/meter.d.ts +2 -0
- package/dist/dev/elements/meter.js +6 -6
- package/dist/dev/elements/meter.js.map +1 -1
- package/dist/dev/elements/number.d.ts +2 -1
- package/dist/dev/elements/number.js +5 -12
- package/dist/dev/elements/number.js.map +1 -1
- package/dist/dev/elements/position-group.js +4 -4
- package/dist/dev/elements/position-group.js.map +1 -1
- package/dist/dev/elements/radio-group.d.ts +1 -1
- package/dist/dev/elements/radio-group.js +7 -7
- package/dist/dev/elements/radio-group.js.map +1 -1
- package/dist/dev/elements/region-layer.js +3 -1
- package/dist/dev/elements/region-layer.js.map +1 -1
- package/dist/dev/elements/region.d.ts +1 -0
- package/dist/dev/elements/region.js +5 -1
- package/dist/dev/elements/region.js.map +1 -1
- package/dist/dev/elements/segmented.d.ts +4 -2
- package/dist/dev/elements/segmented.js +7 -9
- package/dist/dev/elements/segmented.js.map +1 -1
- package/dist/dev/elements/slider.d.ts +4 -1
- package/dist/dev/elements/slider.js +12 -14
- package/dist/dev/elements/slider.js.map +1 -1
- package/dist/dev/elements/sonic-element.d.ts +6 -7
- package/dist/dev/elements/sonic-element.js +16 -91
- package/dist/dev/elements/sonic-element.js.map +1 -1
- package/dist/dev/elements/spectrum.d.ts +2 -2
- package/dist/dev/elements/spectrum.js +3 -3
- package/dist/dev/elements/spectrum.js.map +1 -1
- package/dist/dev/elements/switch.d.ts +4 -1
- package/dist/dev/elements/switch.js +11 -10
- package/dist/dev/elements/switch.js.map +1 -1
- package/dist/dev/elements/toggle.d.ts +4 -1
- package/dist/dev/elements/toggle.js +16 -15
- package/dist/dev/elements/toggle.js.map +1 -1
- package/dist/dev/elements/value-element.d.ts +4 -3
- package/dist/dev/elements/value-element.js +26 -4
- package/dist/dev/elements/value-element.js.map +1 -1
- package/dist/dev/elements/wave-element.d.ts +2 -1
- package/dist/dev/elements/wave-element.js +11 -13
- package/dist/dev/elements/wave-element.js.map +1 -1
- package/dist/dev/elements/waveform.d.ts +0 -1
- package/dist/dev/elements/waveform.js +1 -4
- package/dist/dev/elements/waveform.js.map +1 -1
- package/dist/dev/elements/wavestrip.js +1 -1
- package/dist/dev/elements/wavestrip.js.map +1 -1
- package/dist/dev/elements/xy.d.ts +4 -0
- package/dist/dev/elements/xy.js +34 -48
- package/dist/dev/elements/xy.js.map +1 -1
- package/dist/dev/index.d.ts +3 -1
- package/dist/dev/lib/canvas-surface.js +35 -2
- package/dist/dev/lib/canvas-surface.js.map +1 -1
- package/dist/dev/lib/check-styles.d.ts +8 -0
- package/dist/dev/lib/check-styles.js +87 -0
- package/dist/dev/lib/check-styles.js.map +1 -0
- package/dist/dev/lib/key-press.js +2 -2
- package/dist/dev/lib/key-press.js.map +1 -1
- package/dist/dev/lib/render.js +2 -2
- package/dist/dev/lib/render.js.map +1 -1
- package/dist/styles/button.css +11 -9
- package/dist/styles/dial.css +6 -6
- package/dist/styles/envelope.css +6 -0
- package/dist/styles/led.css +8 -8
- package/dist/styles/material/cap.css +13 -2
- package/dist/styles/material/pane.css +7 -1
- package/dist/styles/material/readout.css +10 -2
- package/dist/styles/material/reticle.css +2 -2
- package/dist/styles/meter.css +11 -11
- package/dist/styles/number.css +1 -1
- package/dist/styles/region.css +6 -0
- package/dist/styles/segmented.css +3 -3
- package/dist/styles/slider.css +12 -12
- package/dist/styles/switch.css +6 -0
- package/dist/styles/toggle.css +3 -3
- package/dist/styles/waveform.css +7 -1
- package/dist/styles/wavestrip.css +6 -0
- package/dist/styles/xy.css +15 -3
- package/package.json +1 -1
- package/dist/dev/elements/display-element.js.map +0 -1
|
@@ -8,7 +8,6 @@ const namingAttributes = [
|
|
|
8
8
|
"aria-label",
|
|
9
9
|
"aria-labelledby"
|
|
10
10
|
];
|
|
11
|
-
const canMatchStates = CSS.supports("selector(:state(a))");
|
|
12
11
|
const canReferElements = "ariaLabelledByElements" in Element.prototype;
|
|
13
12
|
function writeLabelledBy(target, labels) {
|
|
14
13
|
const current = target.ariaLabelledByElements;
|
|
@@ -26,7 +25,6 @@ var SonicElement = class SonicElement extends HTMLElement {
|
|
|
26
25
|
}
|
|
27
26
|
internals = "attachInternals" in HTMLElement.prototype ? this.attachInternals() : void 0;
|
|
28
27
|
#connection;
|
|
29
|
-
#customStates = canMatchStates ? this.internals?.states : void 0;
|
|
30
28
|
#states = /* @__PURE__ */ new Set();
|
|
31
29
|
static #labelId(label) {
|
|
32
30
|
if (label.id === "") {
|
|
@@ -50,6 +48,7 @@ var SonicElement = class SonicElement extends HTMLElement {
|
|
|
50
48
|
this.#connection = void 0;
|
|
51
49
|
throw error;
|
|
52
50
|
}
|
|
51
|
+
const { boxProbe: box, control, sheet } = this;
|
|
53
52
|
}
|
|
54
53
|
connectedMoveCallback() {}
|
|
55
54
|
disconnectedCallback() {
|
|
@@ -69,7 +68,6 @@ var SonicElement = class SonicElement extends HTMLElement {
|
|
|
69
68
|
}
|
|
70
69
|
if (!this.isDisabled() && !this.#focused()) target.focus(options);
|
|
71
70
|
}
|
|
72
|
-
checkStyles(control, sheet, box) {}
|
|
73
71
|
focusTarget() {}
|
|
74
72
|
forwardNaming(target, isNamed) {
|
|
75
73
|
const labels = isNamed ? this.namingLabels() : [];
|
|
@@ -89,7 +87,9 @@ var SonicElement = class SonicElement extends HTMLElement {
|
|
|
89
87
|
isDisabled() {
|
|
90
88
|
return this.disabled || this.matches(":disabled");
|
|
91
89
|
}
|
|
92
|
-
keepControl(
|
|
90
|
+
keepControl(signal) {
|
|
91
|
+
const control = this.control;
|
|
92
|
+
if (!control) return;
|
|
93
93
|
const keep = () => {
|
|
94
94
|
appendOnce(this, control);
|
|
95
95
|
};
|
|
@@ -118,14 +118,13 @@ var SonicElement = class SonicElement extends HTMLElement {
|
|
|
118
118
|
}
|
|
119
119
|
this.setAttribute(name, value === true ? "" : value.toString());
|
|
120
120
|
}
|
|
121
|
+
stateTarget() {
|
|
122
|
+
return this.control;
|
|
123
|
+
}
|
|
121
124
|
toggleState(state, isOn) {
|
|
122
|
-
if (isOn)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
this.#states.delete(state);
|
|
128
|
-
this.#customStates?.delete(state);
|
|
125
|
+
if (isOn) this.#states.add(state);
|
|
126
|
+
else this.#states.delete(state);
|
|
127
|
+
this.stateTarget()?.toggleAttribute(`data-sonic-${state}`, isOn);
|
|
129
128
|
}
|
|
130
129
|
upgradeProperties(...names) {
|
|
131
130
|
for (const name of names) {
|
|
@@ -138,8 +137,6 @@ var SonicElement = class SonicElement extends HTMLElement {
|
|
|
138
137
|
usesChild(_child) {
|
|
139
138
|
return false;
|
|
140
139
|
}
|
|
141
|
-
#checkBox(control, checked, box) {}
|
|
142
|
-
#checkHost(checked) {}
|
|
143
140
|
#focused() {
|
|
144
141
|
const root = this.getRootNode();
|
|
145
142
|
const active = root instanceof ShadowRoot ? root.activeElement : this.ownerDocument.activeElement;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { requireChild, template } from "../lib/render.js";
|
|
2
|
-
import {
|
|
2
|
+
import { SonicAnalyserElement } from "./analyser-element.js";
|
|
3
3
|
import { columnEdges, columnLevels, gridColumns, gridRows, levelRows, loudestBin, zoneRows } from "../lib/spectrum-columns.js";
|
|
4
4
|
import { areSettled, createLevels, receiveLevels, stepLevels } from "../lib/spectrum-levels.js";
|
|
5
5
|
|
|
@@ -71,9 +71,9 @@ function paintHolds(context, { look, rowOf }, { bars, holds }) {
|
|
|
71
71
|
context.fillStyle = look.colours.lit;
|
|
72
72
|
context.fill();
|
|
73
73
|
}
|
|
74
|
-
var SonicSpectrum = class extends
|
|
74
|
+
var SonicSpectrum = class extends SonicAnalyserElement {
|
|
75
75
|
static observedAttributes = [
|
|
76
|
-
...
|
|
76
|
+
...SonicAnalyserElement.observedAttributes,
|
|
77
77
|
"frequency-max",
|
|
78
78
|
"frequency-min",
|
|
79
79
|
"grid",
|
|
@@ -20,20 +20,25 @@ const renderBare = template(`<button class="sonic-switch-position" role="switch"
|
|
|
20
20
|
const pressCenterZone = .08;
|
|
21
21
|
var SonicSwitch = class extends SonicPositionGroupElement {
|
|
22
22
|
bare = renderBare();
|
|
23
|
+
boxProbe = {
|
|
24
|
+
property: "padding-top",
|
|
25
|
+
selector: ".sonic-switch-label"
|
|
26
|
+
};
|
|
27
|
+
control = renderSwitch();
|
|
23
28
|
defaultOrientation = "vertical";
|
|
24
|
-
|
|
25
|
-
#bat = requireChild(this.
|
|
29
|
+
sheet = "switch.css";
|
|
30
|
+
#bat = requireChild(this.control, ".sonic-switch-bat", HTMLSpanElement);
|
|
26
31
|
#isClickSwallowed = false;
|
|
27
32
|
claimPress(index, event) {
|
|
28
33
|
if (this.#isOnBat(event)) return true;
|
|
29
34
|
const target = this.pressTarget(index);
|
|
30
35
|
if (this.isOptionDisabled(target) || !this.isMomentary(target)) return false;
|
|
31
|
-
capturePointer(this.
|
|
36
|
+
capturePointer(this.control, event.pointerId);
|
|
32
37
|
this.hold(target, event.pointerId);
|
|
33
38
|
return true;
|
|
34
39
|
}
|
|
35
40
|
connect(signal) {
|
|
36
|
-
const group = this.
|
|
41
|
+
const group = this.control;
|
|
37
42
|
super.connect(signal);
|
|
38
43
|
this.bare.addEventListener("click", (event) => {
|
|
39
44
|
const isSwallowed = this.#isClickSwallowed && event instanceof PointerEvent && event.pointerType !== "";
|
|
@@ -70,7 +75,7 @@ var SonicSwitch = class extends SonicPositionGroupElement {
|
|
|
70
75
|
lift: (press, event) => {
|
|
71
76
|
this.#isClickSwallowed = true;
|
|
72
77
|
if (press.hasMoved || this.isDisabled()) return;
|
|
73
|
-
if (!isUnder(this.
|
|
78
|
+
if (!isUnder(this.control, event.clientX, event.clientY)) return;
|
|
74
79
|
this.#pressBat(event);
|
|
75
80
|
},
|
|
76
81
|
move: (press, event) => {
|
|
@@ -101,7 +106,7 @@ var SonicSwitch = class extends SonicPositionGroupElement {
|
|
|
101
106
|
#renderThrow(index) {
|
|
102
107
|
const count = this.positions().length;
|
|
103
108
|
const at = index < 0 || count < 2 ? 0 : 2 * index / (count - 1) - 1;
|
|
104
|
-
this.
|
|
109
|
+
this.control.style.setProperty("--_sonic-switch-at", String(at));
|
|
105
110
|
}
|
|
106
111
|
#sideStep(from, event) {
|
|
107
112
|
const box = this.#bat.getBoundingClientRect();
|
|
@@ -22,12 +22,18 @@ const renderBare = template(`<button class="sonic-toggle-position" role="switch"
|
|
|
22
22
|
const pressTolerance = 2;
|
|
23
23
|
var SonicToggle = class extends SonicPositionGroupElement {
|
|
24
24
|
bare = renderBare();
|
|
25
|
+
boxProbe = {
|
|
26
|
+
property: "margin-top",
|
|
27
|
+
ratio: "--_sonic-toggle-gap-ratio",
|
|
28
|
+
selector: ".sonic-toggle-cap"
|
|
29
|
+
};
|
|
30
|
+
control = renderToggle();
|
|
25
31
|
defaultOrientation = "horizontal";
|
|
26
|
-
|
|
27
|
-
#cap = requireChild(this.
|
|
32
|
+
sheet = "toggle.css";
|
|
33
|
+
#cap = requireChild(this.control, ".sonic-toggle-cap", HTMLSpanElement);
|
|
28
34
|
#draggedTo;
|
|
29
35
|
#hasWarnedOfLegends = false;
|
|
30
|
-
#well = requireChild(this.
|
|
36
|
+
#well = requireChild(this.control, ".sonic-toggle-well", HTMLSpanElement);
|
|
31
37
|
claimPress() {
|
|
32
38
|
return true;
|
|
33
39
|
}
|
|
@@ -49,7 +55,7 @@ var SonicToggle = class extends SonicPositionGroupElement {
|
|
|
49
55
|
}
|
|
50
56
|
render() {
|
|
51
57
|
if (!this.isBound()) return;
|
|
52
|
-
this.
|
|
58
|
+
this.control.style.setProperty("--_sonic-toggle-count", String(this.positions().length));
|
|
53
59
|
this.#placeCap(this.#draggedTo ?? this.#restingAt());
|
|
54
60
|
super.render();
|
|
55
61
|
for (const [index, option] of this.options().entries()) option.style.setProperty("--_sonic-toggle-index", String(index));
|
|
@@ -58,11 +64,11 @@ var SonicToggle = class extends SonicPositionGroupElement {
|
|
|
58
64
|
return renderPosition();
|
|
59
65
|
}
|
|
60
66
|
#bindCap(signal) {
|
|
61
|
-
bindDrag(this.
|
|
67
|
+
bindDrag(this.control, {
|
|
62
68
|
grab: (event) => this.#grab(event),
|
|
63
69
|
lift: (drag, event) => {
|
|
64
70
|
if (!drag.isPress || drag.isHolding || this.isDisabled()) return;
|
|
65
|
-
if (!isUnder(this.
|
|
71
|
+
if (!isUnder(this.control, event.clientX, event.clientY)) return;
|
|
66
72
|
this.#press(drag.position);
|
|
67
73
|
},
|
|
68
74
|
move: (drag, event) => {
|
|
@@ -76,7 +82,7 @@ var SonicToggle = class extends SonicPositionGroupElement {
|
|
|
76
82
|
if (this.#slideTo(positionAt(drag.travel, pointer), event.pointerId)) drag.isPress = false;
|
|
77
83
|
},
|
|
78
84
|
release: (drag) => {
|
|
79
|
-
delete drag.marked.dataset.
|
|
85
|
+
delete drag.marked.dataset.sonicActive;
|
|
80
86
|
this.#draggedTo = void 0;
|
|
81
87
|
this.toggleState("dragging", false);
|
|
82
88
|
this.render();
|
|
@@ -85,7 +91,7 @@ var SonicToggle = class extends SonicPositionGroupElement {
|
|
|
85
91
|
}
|
|
86
92
|
#checkLegends() {}
|
|
87
93
|
#fixedLegend() {
|
|
88
|
-
return [...this.children].find((child) => child !== this.
|
|
94
|
+
return [...this.children].find((child) => child !== this.control && !super.isMirrored(child));
|
|
89
95
|
}
|
|
90
96
|
#grab(event) {
|
|
91
97
|
const position = this.pressedIndex(event.target);
|
|
@@ -94,7 +100,7 @@ var SonicToggle = class extends SonicPositionGroupElement {
|
|
|
94
100
|
const travel = this.#travel(event, isOnCap);
|
|
95
101
|
if (!travel || !isOnCap && this.isOptionDisabled(position)) return void 0;
|
|
96
102
|
const marked = this.options()[position] ?? this.bare;
|
|
97
|
-
marked.toggleAttribute("data-sonic-
|
|
103
|
+
marked.toggleAttribute("data-sonic-active", true);
|
|
98
104
|
return {
|
|
99
105
|
hasMoved: false,
|
|
100
106
|
isHolding: this.#holdFrom(position, event.pointerId),
|
|
@@ -113,7 +119,7 @@ var SonicToggle = class extends SonicPositionGroupElement {
|
|
|
113
119
|
return true;
|
|
114
120
|
}
|
|
115
121
|
#placeCap(at) {
|
|
116
|
-
this.
|
|
122
|
+
this.control.style.setProperty("--_sonic-toggle-at", String(at));
|
|
117
123
|
}
|
|
118
124
|
#press(position) {
|
|
119
125
|
const target = this.pressTarget(position);
|
|
@@ -233,6 +233,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
233
233
|
#model = createValueModel(() => this.#spec());
|
|
234
234
|
#parseValue;
|
|
235
235
|
#readout;
|
|
236
|
+
#said;
|
|
236
237
|
attributeChangedCallback(name) {
|
|
237
238
|
if (name === "value" && this.#isHeld()) {
|
|
238
239
|
this.#writeHeld(this.numberAttribute("value", this.min));
|
|
@@ -250,7 +251,8 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
250
251
|
abandonHold() {
|
|
251
252
|
this.#gestures?.abandon();
|
|
252
253
|
}
|
|
253
|
-
bindGestures(
|
|
254
|
+
bindGestures(signal, grab) {
|
|
255
|
+
const control = this.control;
|
|
254
256
|
const bubble = control.querySelector("[popover]");
|
|
255
257
|
if (bubble) this.#readout = {
|
|
256
258
|
anchor: control,
|
|
@@ -315,6 +317,9 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
315
317
|
controlRole() {
|
|
316
318
|
return "slider";
|
|
317
319
|
}
|
|
320
|
+
focusTarget() {
|
|
321
|
+
return this.control;
|
|
322
|
+
}
|
|
318
323
|
input(next) {
|
|
319
324
|
const previous = this.#model.value;
|
|
320
325
|
if (this.#model.input(next)) this.render();
|
|
@@ -373,8 +378,12 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
373
378
|
}
|
|
374
379
|
springTarget() {}
|
|
375
380
|
tapTarget() {}
|
|
376
|
-
|
|
377
|
-
|
|
381
|
+
upwardAxis(travelProperty) {
|
|
382
|
+
const styles = getComputedStyle(this.control);
|
|
383
|
+
return {
|
|
384
|
+
position: (event) => -event.clientY,
|
|
385
|
+
travelPx: Math.max(1, readPxProperty(styles, travelProperty, fallbackTravelPx))
|
|
386
|
+
};
|
|
378
387
|
}
|
|
379
388
|
#entryText() {
|
|
380
389
|
const value = this.#model.value;
|
|
@@ -405,7 +414,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
405
414
|
writeAttribute(control, "aria-valuemax", String(high));
|
|
406
415
|
writeAttribute(control, "aria-valuenow", String(this.#spokenNow()));
|
|
407
416
|
if (orientation) writeAttribute(control, "aria-orientation", orientation);
|
|
408
|
-
writeAttribute(control, "aria-valuetext", this
|
|
417
|
+
writeAttribute(control, "aria-valuetext", this.#spokenValueText());
|
|
409
418
|
this.forwardNaming(control, true);
|
|
410
419
|
this.#renderDisabled(control);
|
|
411
420
|
this.renderReadout();
|
|
@@ -458,6 +467,19 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
458
467
|
const step = this.spokenStep;
|
|
459
468
|
return step !== void 0 && step > 0 ? trimFloat(Math.round(this.#model.value / step) * step) : this.#model.value;
|
|
460
469
|
}
|
|
470
|
+
#spokenValueText() {
|
|
471
|
+
const format = this.#formatSpokenValue ?? this.#formatValue ?? this.notation.speak;
|
|
472
|
+
const value = this.#spokenNow();
|
|
473
|
+
const said = this.#said;
|
|
474
|
+
if (said && said.format === format && said.value === value) return said.text;
|
|
475
|
+
const text = format?.(value);
|
|
476
|
+
this.#said = {
|
|
477
|
+
format,
|
|
478
|
+
text,
|
|
479
|
+
value
|
|
480
|
+
};
|
|
481
|
+
return text;
|
|
482
|
+
}
|
|
461
483
|
#textFor(value) {
|
|
462
484
|
return (this.#formatValue ?? this.notation.format)(value);
|
|
463
485
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SonicValueElement } from "./value-element.js";
|
|
2
|
-
import {
|
|
2
|
+
import { bindControlSurface } from "../lib/canvas-surface.js";
|
|
3
3
|
import { formatClock, parseClock } from "../lib/clock.js";
|
|
4
4
|
import { spokenDuration } from "../lib/spoken-duration.js";
|
|
5
5
|
|
|
@@ -32,6 +32,10 @@ var SonicWaveElement = class extends SonicValueElement {
|
|
|
32
32
|
this.renderMarkers();
|
|
33
33
|
this.render();
|
|
34
34
|
}
|
|
35
|
+
boxProbe = {
|
|
36
|
+
property: "margin-bottom",
|
|
37
|
+
selector: "[popover]"
|
|
38
|
+
};
|
|
35
39
|
notation = {
|
|
36
40
|
format: formatClock,
|
|
37
41
|
parse: parseClock,
|
|
@@ -65,15 +69,13 @@ var SonicWaveElement = class extends SonicValueElement {
|
|
|
65
69
|
}
|
|
66
70
|
connect(signal) {
|
|
67
71
|
const control = this.control;
|
|
68
|
-
this.keepControl(
|
|
72
|
+
this.keepControl(signal);
|
|
69
73
|
this.renderEmpty();
|
|
70
|
-
this.#surface =
|
|
74
|
+
this.#surface = bindControlSurface({
|
|
71
75
|
canvas: this.canvas,
|
|
72
76
|
colours: this.colours,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
sizeProperty: this.sizeProperty
|
|
76
|
-
},
|
|
77
|
+
control,
|
|
78
|
+
fill: this.fill,
|
|
77
79
|
lengths: this.lengths,
|
|
78
80
|
numbers: this.numbers,
|
|
79
81
|
paint: (context, frame) => {
|
|
@@ -82,10 +84,10 @@ var SonicWaveElement = class extends SonicValueElement {
|
|
|
82
84
|
resize: () => {
|
|
83
85
|
this.renderMarkers();
|
|
84
86
|
},
|
|
85
|
-
signal
|
|
87
|
+
signal,
|
|
88
|
+
sizeProperty: this.sizeProperty
|
|
86
89
|
});
|
|
87
90
|
this.render();
|
|
88
|
-
this.#surface.setFill(this.fill);
|
|
89
91
|
}
|
|
90
92
|
markerList() {
|
|
91
93
|
return this.#markers;
|
|
@@ -231,7 +231,7 @@ var SonicWaveform = class extends SonicWaveElement {
|
|
|
231
231
|
}
|
|
232
232
|
};
|
|
233
233
|
this.#zoomGesture = bindZoom(this.control, zoomTarget, signal);
|
|
234
|
-
this.bindGestures(
|
|
234
|
+
this.bindGestures(signal, () => this.#grab());
|
|
235
235
|
bindZoomKeys(this.control, zoomTarget, signal);
|
|
236
236
|
if (!("fonts" in document)) return;
|
|
237
237
|
document.fonts.addEventListener("loadingdone", () => {
|
|
@@ -243,9 +243,6 @@ var SonicWaveform = class extends SonicWaveElement {
|
|
|
243
243
|
surface?.requestFrame();
|
|
244
244
|
if (surface?.isVisible === false || !this.#drawn) this.showCurrentMarker(this.#sourceSeconds());
|
|
245
245
|
}
|
|
246
|
-
focusTarget() {
|
|
247
|
-
return this.control;
|
|
248
|
-
}
|
|
249
246
|
isEmpty() {
|
|
250
247
|
return !this.#peaks || this.#peaks.samples.length === 0;
|
|
251
248
|
}
|
|
@@ -157,7 +157,7 @@ var SonicWavestrip = class extends SonicWaveElement {
|
|
|
157
157
|
},
|
|
158
158
|
valueAt: (event) => this.#markerStartAt(event, this.#axis()) ?? this.mapping().snap(this.valueFromPoint(event.clientX, event.clientY))
|
|
159
159
|
});
|
|
160
|
-
this.bindGestures(
|
|
160
|
+
this.bindGestures(signal, (event) => this.#grab(event));
|
|
161
161
|
}
|
|
162
162
|
draw() {
|
|
163
163
|
const surface = this.surface();
|
|
@@ -3,10 +3,7 @@ import { writeAttribute } from "../lib/write-attribute.js";
|
|
|
3
3
|
import { SonicFormElement } from "./form-element.js";
|
|
4
4
|
import { requireChild, template } from "../lib/render.js";
|
|
5
5
|
import { Readout } from "./readout.js";
|
|
6
|
-
import { ReadoutClaim } from "./readout-claim.js";
|
|
7
|
-
import { createDoublePress } from "../lib/double-press.js";
|
|
8
6
|
import { focusByPointer } from "../lib/focus-by-pointer.js";
|
|
9
|
-
import { isMenuPress, isResetPress } from "../lib/modifier-press.js";
|
|
10
7
|
import { resetKeys } from "../lib/value-mapping.js";
|
|
11
8
|
import { createValueModel } from "../lib/value-model.js";
|
|
12
9
|
import { pointerPosition } from "../lib/field.js";
|
|
@@ -203,26 +200,26 @@ var SonicXy = class extends SonicFormElement {
|
|
|
203
200
|
set yTaper(curve) {
|
|
204
201
|
this.reflect("y-taper", curve);
|
|
205
202
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
boxProbe = {
|
|
204
|
+
property: "margin-bottom",
|
|
205
|
+
selector: "[popover]"
|
|
206
|
+
};
|
|
207
|
+
control = renderXy();
|
|
208
|
+
sheet = "xy.css";
|
|
209
209
|
#currentAxis = "x";
|
|
210
|
-
#
|
|
211
|
-
#xy = renderXy();
|
|
212
|
-
#field = requireChild(this.#xy, ".sonic-xy-field", HTMLDivElement);
|
|
210
|
+
#field = requireChild(this.control, ".sonic-xy-field", HTMLDivElement);
|
|
213
211
|
#formatValue;
|
|
214
212
|
#gesture;
|
|
215
|
-
#isRevealed = false;
|
|
216
213
|
#models = {
|
|
217
214
|
x: createValueModel(() => this.#spec("x")),
|
|
218
215
|
y: createValueModel(() => this.#spec("y"))
|
|
219
216
|
};
|
|
220
217
|
#parts = {
|
|
221
|
-
x: requireChild(this
|
|
222
|
-
y: requireChild(this
|
|
218
|
+
x: requireChild(this.control, "[data-sonic-axis=\"x\"]", HTMLDivElement),
|
|
219
|
+
y: requireChild(this.control, "[data-sonic-axis=\"y\"]", HTMLDivElement)
|
|
223
220
|
};
|
|
224
|
-
#puck = requireChild(this
|
|
225
|
-
#readout = new Readout(requireChild(this
|
|
221
|
+
#puck = requireChild(this.control, ".sonic-xy-puck", HTMLDivElement);
|
|
222
|
+
#readout = new Readout(requireChild(this.control, ".sonic-xy-readout", HTMLDivElement));
|
|
226
223
|
attributeChangedCallback(name) {
|
|
227
224
|
if ((name === "x" || name === "y") && this.#gesture?.current()) return;
|
|
228
225
|
if (name === "disabled" && this.isDisabled()) this.#gesture?.end();
|
|
@@ -237,8 +234,8 @@ var SonicXy = class extends SonicFormElement {
|
|
|
237
234
|
this.#respec(...axes);
|
|
238
235
|
}
|
|
239
236
|
connect(signal) {
|
|
240
|
-
const xy = this
|
|
241
|
-
this.keepControl(
|
|
237
|
+
const xy = this.control;
|
|
238
|
+
this.keepControl(signal);
|
|
242
239
|
this.render();
|
|
243
240
|
this.#bindPointer(xy, signal);
|
|
244
241
|
this.#bindKeys(xy, signal);
|
|
@@ -248,7 +245,7 @@ var SonicXy = class extends SonicFormElement {
|
|
|
248
245
|
}
|
|
249
246
|
render() {
|
|
250
247
|
if (!this.isBound()) return;
|
|
251
|
-
const { style } = this
|
|
248
|
+
const { style } = this.control;
|
|
252
249
|
for (const axis of axes) {
|
|
253
250
|
const model = this.#models[axis];
|
|
254
251
|
const mapping = model.mapping();
|
|
@@ -275,49 +272,47 @@ var SonicXy = class extends SonicFormElement {
|
|
|
275
272
|
const move = keyMoves.get(event.key);
|
|
276
273
|
if (!move && !(resetKeys.has(event.key) && this.#hasDefault())) return;
|
|
277
274
|
event.preventDefault();
|
|
278
|
-
this.#
|
|
279
|
-
this.#renderReadout();
|
|
275
|
+
this.#gesture?.revealKeys();
|
|
280
276
|
if (move) this.#keyTo(...move);
|
|
281
277
|
else this.#reset();
|
|
282
278
|
}, { signal });
|
|
283
279
|
xy.addEventListener("focusout", (event) => {
|
|
284
280
|
if (event.relatedTarget instanceof Node && xy.contains(event.relatedTarget)) return;
|
|
285
|
-
|
|
281
|
+
this.#gesture?.concealKeys();
|
|
286
282
|
}, { signal });
|
|
287
283
|
signal.addEventListener("abort", () => {
|
|
288
|
-
|
|
284
|
+
this.#gesture?.concealKeys();
|
|
289
285
|
}, { once: true });
|
|
290
286
|
}
|
|
291
287
|
#bindPointer(xy, signal) {
|
|
292
288
|
xy.addEventListener("mousedown", (event) => {
|
|
293
289
|
event.preventDefault();
|
|
294
290
|
}, { signal });
|
|
295
|
-
xy.addEventListener("pointercancel", () => {
|
|
296
|
-
this.#doublePress.forget();
|
|
297
|
-
}, { signal });
|
|
298
291
|
this.#gesture = bindFieldGesture(xy, {
|
|
299
|
-
|
|
292
|
+
element: this,
|
|
300
293
|
grab: (event) => {
|
|
301
|
-
if (this.isDisabled()
|
|
294
|
+
if (this.isDisabled()) return;
|
|
302
295
|
focusByPointer(this.focusTarget());
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
return this.#grab(event);
|
|
306
|
-
}
|
|
307
|
-
this.#reset();
|
|
296
|
+
this.toggleState("dragging", true);
|
|
297
|
+
return this.#grab(event);
|
|
308
298
|
},
|
|
309
299
|
input: (_hold, next) => {
|
|
310
|
-
|
|
311
|
-
},
|
|
312
|
-
lift: (_hold, event) => {
|
|
313
|
-
if (!this.#doublePress.press(event) || this.doublePress !== "reset") return;
|
|
314
|
-
this.#reset();
|
|
300
|
+
this.#input(next);
|
|
315
301
|
},
|
|
316
302
|
release: (_hold, moved) => {
|
|
317
303
|
if (moved.length > 0) this.dispatchEvent(new Event("change", { bubbles: true }));
|
|
318
304
|
},
|
|
319
|
-
|
|
320
|
-
this
|
|
305
|
+
renderReadout: () => {
|
|
306
|
+
this.#renderReadout();
|
|
307
|
+
},
|
|
308
|
+
reset: () => {
|
|
309
|
+
if (this.isDisabled()) return;
|
|
310
|
+
focusByPointer(this.focusTarget());
|
|
311
|
+
this.#reset();
|
|
312
|
+
},
|
|
313
|
+
resetsOnDoublePress: () => this.doublePress === "reset",
|
|
314
|
+
toggle: (state, isOn) => {
|
|
315
|
+
this.toggleState(state, isOn);
|
|
321
316
|
}
|
|
322
317
|
}, signal);
|
|
323
318
|
}
|
|
@@ -408,16 +403,11 @@ var SonicXy = class extends SonicFormElement {
|
|
|
408
403
|
this.writeFormFields([["x", x], ["y", y]], `${String(x)},${String(y)}`);
|
|
409
404
|
}
|
|
410
405
|
#renderReadout() {
|
|
411
|
-
const { isRevealed } = this.#claim;
|
|
412
406
|
this.#readout.show({
|
|
413
407
|
anchor: this.#puck,
|
|
414
|
-
isOpen: isRevealed && this.readout,
|
|
408
|
+
isOpen: this.#gesture?.isRevealed() === true && this.readout,
|
|
415
409
|
text: this.#valueText("x")
|
|
416
410
|
});
|
|
417
|
-
if (isRevealed === this.#isRevealed) return;
|
|
418
|
-
this.#isRevealed = isRevealed;
|
|
419
|
-
this.toggleState("revealed", isRevealed);
|
|
420
|
-
this.dispatchEvent(new Event("sonic-reveal", { bubbles: true }));
|
|
421
411
|
}
|
|
422
412
|
#reset() {
|
|
423
413
|
this.#commit({
|
|
@@ -10,6 +10,17 @@ function deviceBox(entry, css) {
|
|
|
10
10
|
if (!device || Math.abs(device.inlineSize - css.inlineSize * dpr) > 1) return void 0;
|
|
11
11
|
return Math.abs(device.blockSize - css.blockSize * dpr) > 1 ? void 0 : device;
|
|
12
12
|
}
|
|
13
|
+
function canTakeColour(context, colour) {
|
|
14
|
+
const kept = context.fillStyle;
|
|
15
|
+
const isKept = (sentinel) => {
|
|
16
|
+
context.fillStyle = sentinel;
|
|
17
|
+
context.fillStyle = colour;
|
|
18
|
+
return context.fillStyle === sentinel;
|
|
19
|
+
};
|
|
20
|
+
const isRefused = isKept("#000000") && isKept("#ffffff");
|
|
21
|
+
context.fillStyle = kept;
|
|
22
|
+
return !isRefused;
|
|
23
|
+
}
|
|
13
24
|
function readEach(properties, read) {
|
|
14
25
|
return Object.fromEntries(Object.entries(properties).flatMap(([name, property]) => property === void 0 ? [] : [[name, read(property)]]));
|
|
15
26
|
}
|
|
@@ -181,7 +192,7 @@ var CanvasSurface = class {
|
|
|
181
192
|
const { canvas, colours, lengths = {}, numbers = {} } = this.#options;
|
|
182
193
|
const styles = getComputedStyle(canvas);
|
|
183
194
|
return {
|
|
184
|
-
colours: readEach(colours, (property) => styles.getPropertyValue(property).trim().replaceAll("currentcolor", () => styles.color)),
|
|
195
|
+
colours: readEach(colours, (property) => this.#resolve(styles.getPropertyValue(property).trim().replaceAll("currentcolor", () => styles.color))),
|
|
185
196
|
isReducedMotion: this.#reducedMotion.matches,
|
|
186
197
|
lengths: readEach(lengths, (property) => readPxProperty(styles, property, 0)),
|
|
187
198
|
numbers: readEach(numbers, (property) => readPxProperty(styles, property, 0))
|
|
@@ -209,6 +220,16 @@ var CanvasSurface = class {
|
|
|
209
220
|
if (previous.width === 0 || previous.height === 0) this.rebuild();
|
|
210
221
|
else this.invalidate();
|
|
211
222
|
}
|
|
223
|
+
#resolve(colour) {
|
|
224
|
+
const context = this.#context;
|
|
225
|
+
if (!context || canTakeColour(context, colour)) return colour;
|
|
226
|
+
const probe = document.createElement("span");
|
|
227
|
+
probe.style.color = colour;
|
|
228
|
+
this.#options.canvas.append(probe);
|
|
229
|
+
const resolved = getComputedStyle(probe).color;
|
|
230
|
+
probe.remove();
|
|
231
|
+
return resolved;
|
|
232
|
+
}
|
|
212
233
|
#schedule() {
|
|
213
234
|
if (this.#options.signal.aborted || this.#frame !== void 0 || !this.#isVisible) return;
|
|
214
235
|
this.#frame = requestAnimationFrame((frameMs) => {
|
|
@@ -233,6 +254,18 @@ var CanvasSurface = class {
|
|
|
233
254
|
function bindSurface(options) {
|
|
234
255
|
return new CanvasSurface(options);
|
|
235
256
|
}
|
|
257
|
+
function bindControlSurface(options) {
|
|
258
|
+
const { control, fill, sizeProperty, ...surfaceOptions } = options;
|
|
259
|
+
const surface = bindSurface({
|
|
260
|
+
...surfaceOptions,
|
|
261
|
+
fill: {
|
|
262
|
+
control,
|
|
263
|
+
sizeProperty
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
surface.setFill(fill);
|
|
267
|
+
return surface;
|
|
268
|
+
}
|
|
236
269
|
|
|
237
270
|
//#endregion
|
|
238
|
-
export { bindSurface };
|
|
271
|
+
export { bindControlSurface, bindSurface };
|
|
@@ -3,7 +3,7 @@ function bindKeyPress(root, signal) {
|
|
|
3
3
|
let pressed;
|
|
4
4
|
const release = () => {
|
|
5
5
|
if (!pressed) return;
|
|
6
|
-
delete pressed.dataset.
|
|
6
|
+
delete pressed.dataset.sonicActive;
|
|
7
7
|
pressed = void 0;
|
|
8
8
|
};
|
|
9
9
|
root.addEventListener("keydown", (event) => {
|
|
@@ -12,7 +12,7 @@ function bindKeyPress(root, signal) {
|
|
|
12
12
|
if (!(part instanceof HTMLButtonElement) || part.disabled) return;
|
|
13
13
|
release();
|
|
14
14
|
pressed = part;
|
|
15
|
-
part.dataset.
|
|
15
|
+
part.dataset.sonicActive = "";
|
|
16
16
|
}, { signal });
|
|
17
17
|
root.addEventListener("keyup", (event) => {
|
|
18
18
|
if (event.key === " " || event.key === "Meta") release();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region src/lib/render.ts
|
|
2
2
|
function requireChild(root, selector, child) {
|
|
3
3
|
const found = root.querySelector(selector);
|
|
4
|
-
if (!(found instanceof child)) throw new
|
|
4
|
+
if (!(found instanceof child)) throw new TypeError(`A template is missing its ${selector}`);
|
|
5
5
|
return found;
|
|
6
6
|
}
|
|
7
7
|
function template(html, root) {
|
|
@@ -9,7 +9,7 @@ function template(html, root) {
|
|
|
9
9
|
parsed.innerHTML = html;
|
|
10
10
|
return () => {
|
|
11
11
|
const clone = document.importNode(parsed.content, true).firstElementChild;
|
|
12
|
-
if (!(clone instanceof root)) throw new
|
|
12
|
+
if (!(clone instanceof root)) throw new TypeError(`A template's root is not a ${root.name}`);
|
|
13
13
|
return clone;
|
|
14
14
|
};
|
|
15
15
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { SonicElement } from "./sonic-element.js";
|
|
2
2
|
import { Decibels } from "../lib/units.js";
|
|
3
3
|
import { Surface, SurfaceFrame } from "../lib/canvas-surface.js";
|
|
4
|
-
//#region src/elements/
|
|
5
|
-
export declare abstract class
|
|
4
|
+
//#region src/elements/analyser-element.d.ts
|
|
5
|
+
export declare abstract class SonicAnalyserElement<Colour extends string, Numeric extends string = never> extends SonicElement {
|
|
6
6
|
#private;
|
|
7
7
|
static readonly observedAttributes: string[];
|
|
8
8
|
get analyser(): AnalyserNode | undefined;
|
|
@@ -31,4 +31,4 @@ export declare abstract class SonicDisplayElement<Colour extends string, Numeric
|
|
|
31
31
|
protected surface(): Surface | undefined;
|
|
32
32
|
}
|
|
33
33
|
//#endregion
|
|
34
|
-
//# sourceMappingURL=
|
|
34
|
+
//# sourceMappingURL=analyser-element.d.ts.map
|