@xsynaptic/sonic-ui 0.17.0 → 0.19.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 +28 -0
- package/README.md +122 -19
- package/dist/default/elements/button.js +2 -5
- package/dist/default/elements/dial.js +2 -7
- package/dist/default/elements/display-element.js +9 -12
- package/dist/default/elements/envelope.js +31 -78
- package/dist/default/elements/field-gesture.js +81 -0
- package/dist/default/elements/meter.js +4 -1
- package/dist/default/elements/number.js +0 -7
- package/dist/default/elements/position-group.js +42 -26
- package/dist/default/elements/radio-group.js +59 -56
- package/dist/default/elements/scale.js +3 -3
- package/dist/default/elements/segmented.js +0 -5
- package/dist/default/elements/slider.js +11 -20
- package/dist/default/elements/sonic-element.js +3 -1
- package/dist/default/elements/split.js +14 -13
- package/dist/default/elements/switch.js +31 -47
- package/dist/default/elements/toggle.js +20 -49
- package/dist/default/elements/value-element.js +72 -94
- package/dist/default/elements/value-gestures.js +22 -22
- package/dist/default/elements/wave-element.js +16 -20
- package/dist/default/elements/waveform.js +42 -241
- package/dist/default/elements/wavestrip.js +10 -5
- package/dist/default/elements/xy.js +67 -119
- package/dist/default/index.js +2 -1
- package/dist/default/lib/canvas-surface.js +25 -0
- package/dist/default/lib/clock.js +23 -0
- package/dist/default/lib/crossfade.js +1 -0
- package/dist/default/lib/envelope-curve.js +1 -0
- package/dist/default/lib/peaks-request.js +44 -0
- package/dist/default/lib/positions.js +58 -0
- package/dist/default/lib/scrub.js +12 -0
- package/dist/default/lib/spoken-duration.js +30 -0
- package/dist/default/lib/value-model.js +62 -0
- package/dist/default/lib/waveform-buckets.js +7 -1
- package/dist/default/lib/waveform-scene.js +108 -0
- package/dist/default/lib/zoom-gesture.js +97 -1
- package/dist/dev/elements/button.d.ts +2 -0
- package/dist/dev/elements/button.js +14 -5
- package/dist/dev/elements/button.js.map +1 -1
- package/dist/dev/elements/dial.d.ts +2 -0
- package/dist/dev/elements/dial.js +16 -7
- package/dist/dev/elements/dial.js.map +1 -1
- package/dist/dev/elements/display-element.d.ts +5 -3
- package/dist/dev/elements/display-element.js +11 -9
- package/dist/dev/elements/display-element.js.map +1 -1
- package/dist/dev/elements/envelope.js +48 -78
- package/dist/dev/elements/envelope.js.map +1 -1
- package/dist/dev/elements/field-gesture.js +82 -0
- package/dist/dev/elements/field-gesture.js.map +1 -0
- package/dist/dev/elements/meter.d.ts +10 -5
- package/dist/dev/elements/meter.js +5 -1
- package/dist/dev/elements/meter.js.map +1 -1
- package/dist/dev/elements/number.js +13 -7
- package/dist/dev/elements/number.js.map +1 -1
- package/dist/dev/elements/position-group.d.ts +12 -6
- package/dist/dev/elements/position-group.js +42 -26
- package/dist/dev/elements/position-group.js.map +1 -1
- package/dist/dev/elements/radio-group.d.ts +11 -7
- package/dist/dev/elements/radio-group.js +59 -56
- package/dist/dev/elements/radio-group.js.map +1 -1
- package/dist/dev/elements/scale.js +3 -3
- package/dist/dev/elements/scale.js.map +1 -1
- package/dist/dev/elements/segmented.js +12 -5
- package/dist/dev/elements/segmented.js.map +1 -1
- package/dist/dev/elements/slider.d.ts +4 -2
- package/dist/dev/elements/slider.js +25 -20
- package/dist/dev/elements/slider.js.map +1 -1
- package/dist/dev/elements/sonic-element.d.ts +13 -2
- package/dist/dev/elements/sonic-element.js +63 -11
- package/dist/dev/elements/sonic-element.js.map +1 -1
- package/dist/dev/elements/split.d.ts +1 -0
- package/dist/dev/elements/split.js +14 -13
- package/dist/dev/elements/split.js.map +1 -1
- package/dist/dev/elements/switch.d.ts +2 -2
- package/dist/dev/elements/switch.js +38 -47
- package/dist/dev/elements/switch.js.map +1 -1
- package/dist/dev/elements/toggle.js +32 -49
- package/dist/dev/elements/toggle.js.map +1 -1
- package/dist/dev/elements/value-element.d.ts +11 -5
- package/dist/dev/elements/value-element.js +72 -94
- package/dist/dev/elements/value-element.js.map +1 -1
- package/dist/dev/elements/value-gestures.js +22 -22
- package/dist/dev/elements/value-gestures.js.map +1 -1
- package/dist/dev/elements/wave-element.d.ts +8 -5
- package/dist/dev/elements/wave-element.js +30 -20
- package/dist/dev/elements/wave-element.js.map +1 -1
- package/dist/dev/elements/waveform.d.ts +20 -22
- package/dist/dev/elements/waveform.js +42 -241
- package/dist/dev/elements/waveform.js.map +1 -1
- package/dist/dev/elements/wavestrip.d.ts +5 -1
- package/dist/dev/elements/wavestrip.js +10 -5
- package/dist/dev/elements/wavestrip.js.map +1 -1
- package/dist/dev/elements/xy.js +81 -119
- package/dist/dev/elements/xy.js.map +1 -1
- package/dist/dev/index.d.ts +5 -3
- package/dist/dev/index.js +2 -1
- package/dist/dev/lib/canvas-surface.d.ts +1 -0
- package/dist/dev/lib/canvas-surface.js +25 -0
- package/dist/dev/lib/canvas-surface.js.map +1 -1
- package/dist/dev/lib/clock.d.ts +5 -0
- package/dist/dev/lib/clock.js +24 -0
- package/dist/dev/lib/clock.js.map +1 -0
- package/dist/dev/lib/crossfade.d.ts +1 -0
- package/dist/dev/lib/crossfade.js +1 -0
- package/dist/dev/lib/crossfade.js.map +1 -1
- package/dist/dev/lib/envelope-curve.d.ts +1 -0
- package/dist/dev/lib/envelope-curve.js +1 -0
- package/dist/dev/lib/envelope-curve.js.map +1 -1
- package/dist/dev/lib/mirror-children.js.map +1 -1
- package/dist/dev/lib/owned-control.js.map +1 -1
- package/dist/dev/lib/peaks-request.d.ts +5 -0
- package/dist/dev/lib/peaks-request.js +45 -0
- package/dist/dev/lib/peaks-request.js.map +1 -0
- package/dist/dev/lib/positions.d.ts +7 -0
- package/dist/dev/lib/positions.js +59 -0
- package/dist/dev/lib/positions.js.map +1 -0
- package/dist/dev/lib/scrub.d.ts +8 -0
- package/dist/dev/lib/scrub.js +13 -0
- package/dist/dev/lib/scrub.js.map +1 -0
- package/dist/dev/lib/spoken-duration.js +31 -0
- package/dist/dev/lib/spoken-duration.js.map +1 -0
- package/dist/dev/lib/time-regions.d.ts +1 -0
- package/dist/dev/lib/time-regions.js.map +1 -1
- package/dist/dev/lib/units.d.ts +8 -0
- package/dist/dev/lib/value-model.js +63 -0
- package/dist/dev/lib/value-model.js.map +1 -0
- package/dist/dev/lib/waveform-buckets.d.ts +2 -1
- package/dist/dev/lib/waveform-buckets.js +7 -1
- package/dist/dev/lib/waveform-buckets.js.map +1 -1
- package/dist/dev/lib/waveform-scene.d.ts +11 -0
- package/dist/dev/lib/waveform-scene.js +109 -0
- package/dist/dev/lib/waveform-scene.js.map +1 -0
- package/dist/dev/lib/zoom-gesture.js +97 -1
- package/dist/dev/lib/zoom-gesture.js.map +1 -1
- package/dist/skins/amber.css +1 -0
- package/dist/skins/ivory.css +1 -0
- package/dist/skins/lime.css +1 -0
- package/dist/skins/slate.css +1 -0
- package/dist/styles/button.css +45 -11
- package/dist/styles/dial.css +10 -9
- package/dist/styles/envelope.css +10 -4
- package/dist/styles/led.css +5 -1
- package/dist/styles/material/arc.css +3 -2
- package/dist/styles/material/bracket.css +2 -2
- package/dist/styles/material/cap.css +33 -12
- package/dist/styles/material/core.css +4 -0
- package/dist/styles/material/glass.css +1 -1
- package/dist/styles/material/groove.css +4 -3
- package/dist/styles/material/keycap.css +3 -2
- package/dist/styles/material/lens.css +1 -1
- package/dist/styles/material/pane.css +5 -4
- package/dist/styles/material/readout.css +6 -6
- package/dist/styles/material/well.css +2 -2
- package/dist/styles/meter.css +2 -7
- package/dist/styles/number.css +5 -1
- package/dist/styles/panel.css +4 -3
- package/dist/styles/ring.css +1 -1
- package/dist/styles/screen.css +5 -1
- package/dist/styles/segmented.css +17 -4
- package/dist/styles/slider.css +9 -3
- package/dist/styles/spectrum.css +16 -3
- package/dist/styles/switch.css +35 -10
- package/dist/styles/toggle.css +14 -7
- package/dist/styles/waveform.css +17 -5
- package/dist/styles/wavestrip.css +11 -3
- package/dist/styles/xy.css +9 -5
- package/package.json +1 -6
- package/dist/default/dat.js +0 -51
- package/dist/default/lib/asked-value.js +0 -21
- package/dist/default/lib/fill-watch.js +0 -29
- package/dist/dev/dat.d.ts +0 -19
- package/dist/dev/dat.js +0 -52
- package/dist/dev/dat.js.map +0 -1
- package/dist/dev/lib/asked-value.js +0 -22
- package/dist/dev/lib/asked-value.js.map +0 -1
- package/dist/dev/lib/fill-watch.js +0 -30
- package/dist/dev/lib/fill-watch.js.map +0 -1
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { writeAttribute } from "../lib/write-attribute.js";
|
|
2
2
|
import { bindHold } from "../lib/hold.js";
|
|
3
|
+
import { isMomentaryAt, pressTarget, restOf } from "../lib/positions.js";
|
|
3
4
|
import { SonicRadioGroupElement, optionValue } from "./radio-group.js";
|
|
4
5
|
|
|
5
6
|
//#region src/elements/position-group.ts
|
|
7
|
+
const latching = {
|
|
8
|
+
isDisabled: false,
|
|
9
|
+
isMomentary: false
|
|
10
|
+
};
|
|
6
11
|
var SonicPositionGroupElement = class extends SonicRadioGroupElement {
|
|
7
12
|
static observedAttributes = [
|
|
8
13
|
...SonicRadioGroupElement.observedAttributes,
|
|
@@ -56,21 +61,22 @@ var SonicPositionGroupElement = class extends SonicRadioGroupElement {
|
|
|
56
61
|
along(event) {
|
|
57
62
|
return this.orientation === "vertical" ? event.clientY : event.clientX;
|
|
58
63
|
}
|
|
59
|
-
checkedIndex(
|
|
60
|
-
|
|
64
|
+
checkedIndex() {
|
|
65
|
+
if (this.isBare()) return this.checked ? this.onIndex() : 1 - this.onIndex();
|
|
66
|
+
return this.options().findIndex((option) => optionValue(option) === this.value);
|
|
61
67
|
}
|
|
62
|
-
chooseByClick(
|
|
63
|
-
super.chooseByClick(
|
|
64
|
-
if (this.isMomentary(
|
|
68
|
+
chooseByClick(index) {
|
|
69
|
+
super.chooseByClick(index);
|
|
70
|
+
if (this.isMomentary(index)) this.springBack();
|
|
65
71
|
}
|
|
66
|
-
chooseByKey(
|
|
67
|
-
if (!this.isMomentary(
|
|
68
|
-
super.chooseByKey(
|
|
72
|
+
chooseByKey(index, event) {
|
|
73
|
+
if (!this.isMomentary(index)) {
|
|
74
|
+
super.chooseByKey(index, event);
|
|
69
75
|
return;
|
|
70
76
|
}
|
|
71
77
|
if (event.repeat) return;
|
|
72
|
-
this.hold(
|
|
73
|
-
|
|
78
|
+
this.hold(index, event.key);
|
|
79
|
+
this.options()[index]?.focus();
|
|
74
80
|
}
|
|
75
81
|
connect(signal) {
|
|
76
82
|
this.upgradeProperties("defaultChecked", "checked", "orientation");
|
|
@@ -90,23 +96,33 @@ var SonicPositionGroupElement = class extends SonicRadioGroupElement {
|
|
|
90
96
|
focusTarget() {
|
|
91
97
|
return this.isBare() ? this.bare : super.focusTarget();
|
|
92
98
|
}
|
|
93
|
-
hold(
|
|
94
|
-
if (this.#holding?.hold(by) === true) this.select(
|
|
99
|
+
hold(index, by) {
|
|
100
|
+
if (this.#holding?.hold(by) === true) this.select(index);
|
|
95
101
|
}
|
|
96
102
|
isBare() {
|
|
97
103
|
return this.options().length === 0;
|
|
98
104
|
}
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
return
|
|
105
|
+
isChecked(index) {
|
|
106
|
+
const option = this.options()[index];
|
|
107
|
+
return option ? optionValue(option) === this.value : index === this.checkedIndex();
|
|
108
|
+
}
|
|
109
|
+
isMomentary(index) {
|
|
110
|
+
return isMomentaryAt(this.positions(), index);
|
|
102
111
|
}
|
|
103
112
|
isWrapping() {
|
|
104
113
|
return false;
|
|
105
114
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
115
|
+
onIndex() {
|
|
116
|
+
return this.orientation === "vertical" ? 0 : 1;
|
|
117
|
+
}
|
|
118
|
+
positions() {
|
|
119
|
+
return this.isBare() ? [latching, latching] : super.positions();
|
|
120
|
+
}
|
|
121
|
+
pressedIndex(target) {
|
|
122
|
+
return target === this.bare ? 0 : this.indexOf(target);
|
|
123
|
+
}
|
|
124
|
+
pressTarget(index) {
|
|
125
|
+
return pressTarget(this.positions(), this.checkedIndex(), index);
|
|
110
126
|
}
|
|
111
127
|
releaseHold() {
|
|
112
128
|
this.#holding?.release();
|
|
@@ -128,21 +144,21 @@ var SonicPositionGroupElement = class extends SonicRadioGroupElement {
|
|
|
128
144
|
if (this.isBare()) this.checked = state === "true";
|
|
129
145
|
else super.restoreState(state);
|
|
130
146
|
}
|
|
147
|
+
select(index) {
|
|
148
|
+
if (this.isBare()) this.setChecked(index === this.onIndex());
|
|
149
|
+
else super.select(index);
|
|
150
|
+
}
|
|
131
151
|
setChecked(isChecked) {
|
|
132
152
|
if (isChecked === this.checked) return;
|
|
133
153
|
this.checked = isChecked;
|
|
134
154
|
this.dispatchEvent(new Event("change", { bubbles: true }));
|
|
135
155
|
}
|
|
136
156
|
springBack() {
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
const held = options[index];
|
|
140
|
-
if (!held || !this.isMomentary(held)) return;
|
|
141
|
-
const rest = options[index === 0 ? 1 : index - 1];
|
|
142
|
-
if (!rest) return;
|
|
157
|
+
const rest = restOf(this.positions(), this.checkedIndex());
|
|
158
|
+
if (rest === void 0) return;
|
|
143
159
|
const isFocused = this.group.contains(this.ownerDocument.activeElement);
|
|
144
160
|
this.select(rest);
|
|
145
|
-
if (isFocused) rest
|
|
161
|
+
if (isFocused) this.options()[rest]?.focus();
|
|
146
162
|
}
|
|
147
163
|
#renderBare() {
|
|
148
164
|
const group = this.group;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { clamp } from "../lib/math.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";
|
|
@@ -6,14 +5,9 @@ import { bindKeyPress } from "../lib/key-press.js";
|
|
|
6
5
|
import { placeChildren } from "../lib/render.js";
|
|
7
6
|
import { mirrorChildren } from "../lib/mirror-children.js";
|
|
8
7
|
import { bindDrag } from "../lib/pointer-drag.js";
|
|
8
|
+
import { keyTarget, stepFrom } from "../lib/positions.js";
|
|
9
9
|
|
|
10
10
|
//#region src/elements/radio-group.ts
|
|
11
|
-
const keySteps = /* @__PURE__ */ new Map([
|
|
12
|
-
["ArrowDown", 1],
|
|
13
|
-
["ArrowLeft", -1],
|
|
14
|
-
["ArrowRight", 1],
|
|
15
|
-
["ArrowUp", -1]
|
|
16
|
-
]);
|
|
17
11
|
function isInside(box, x, y) {
|
|
18
12
|
return x >= box.left && x < box.right && y >= box.top && y < box.bottom;
|
|
19
13
|
}
|
|
@@ -38,14 +32,14 @@ var SonicRadioGroupElement = class extends SonicFormElement {
|
|
|
38
32
|
if (name === "value") this.#value = this.getAttribute("value") ?? "";
|
|
39
33
|
this.render();
|
|
40
34
|
}
|
|
41
|
-
chooseByClick(
|
|
42
|
-
this.select(
|
|
35
|
+
chooseByClick(index) {
|
|
36
|
+
this.select(index);
|
|
43
37
|
}
|
|
44
|
-
chooseByKey(
|
|
45
|
-
this.select(
|
|
46
|
-
|
|
38
|
+
chooseByKey(index, _event) {
|
|
39
|
+
this.select(index);
|
|
40
|
+
this.options()[index]?.focus();
|
|
47
41
|
}
|
|
48
|
-
claimPress(
|
|
42
|
+
claimPress(_index, _event) {
|
|
49
43
|
return false;
|
|
50
44
|
}
|
|
51
45
|
connect(signal) {
|
|
@@ -61,16 +55,19 @@ var SonicRadioGroupElement = class extends SonicFormElement {
|
|
|
61
55
|
}, signal);
|
|
62
56
|
group.addEventListener("click", (event) => {
|
|
63
57
|
if (event instanceof PointerEvent && event.pointerType !== "") return;
|
|
64
|
-
const
|
|
65
|
-
if (
|
|
58
|
+
const index = this.indexOf(event.target);
|
|
59
|
+
if (index !== -1) this.chooseByClick(index);
|
|
66
60
|
}, { signal });
|
|
67
61
|
this.#bindPress(group, signal);
|
|
68
62
|
bindKeyPress(group, signal);
|
|
69
63
|
group.addEventListener("keydown", (event) => {
|
|
70
64
|
if (event.defaultPrevented) return;
|
|
71
|
-
const
|
|
72
|
-
const next =
|
|
73
|
-
|
|
65
|
+
const index = this.indexOf(event.target);
|
|
66
|
+
const next = index === -1 ? void 0 : keyTarget(this.positions(), index, {
|
|
67
|
+
isWrapping: this.isWrapping(),
|
|
68
|
+
key: event.key
|
|
69
|
+
});
|
|
70
|
+
if (next === void 0) return;
|
|
74
71
|
event.preventDefault();
|
|
75
72
|
this.chooseByKey(next, event);
|
|
76
73
|
}, { signal });
|
|
@@ -78,11 +75,15 @@ var SonicRadioGroupElement = class extends SonicFormElement {
|
|
|
78
75
|
focusTarget() {
|
|
79
76
|
return this.options().find((option) => option.tabIndex === 0);
|
|
80
77
|
}
|
|
78
|
+
indexOf(target) {
|
|
79
|
+
const option = this.optionOf(target);
|
|
80
|
+
return option ? this.options().indexOf(option) : -1;
|
|
81
|
+
}
|
|
81
82
|
isMirrored(child) {
|
|
82
83
|
return child instanceof Element && child.matches("[data-sonic-value]");
|
|
83
84
|
}
|
|
84
|
-
isOptionDisabled(
|
|
85
|
-
return
|
|
85
|
+
isOptionDisabled(index) {
|
|
86
|
+
return this.positions()[index]?.isDisabled !== false;
|
|
86
87
|
}
|
|
87
88
|
isWrapping() {
|
|
88
89
|
return true;
|
|
@@ -98,14 +99,27 @@ var SonicRadioGroupElement = class extends SonicFormElement {
|
|
|
98
99
|
placeCopies(copies) {
|
|
99
100
|
this.#copyOptions(copies);
|
|
100
101
|
}
|
|
101
|
-
|
|
102
|
-
return option
|
|
102
|
+
positions() {
|
|
103
|
+
return this.options().map((option) => {
|
|
104
|
+
const child = option.querySelector("[data-sonic-value]");
|
|
105
|
+
return {
|
|
106
|
+
isDisabled: child?.hasAttribute("data-sonic-disabled") === true,
|
|
107
|
+
isMomentary: child?.hasAttribute("data-sonic-momentary") === true
|
|
108
|
+
};
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
refocusAt(index) {
|
|
112
|
+
if (this.group.matches(":focus-within")) this.options()[index]?.focus();
|
|
113
|
+
}
|
|
114
|
+
releaseTarget(index) {
|
|
115
|
+
return index;
|
|
103
116
|
}
|
|
104
117
|
render() {
|
|
105
118
|
if (!this.isBound()) return;
|
|
106
119
|
const options = this.options();
|
|
120
|
+
const positions = this.positions();
|
|
107
121
|
const checked = options.find((option) => optionValue(option) === this.#value);
|
|
108
|
-
const enabled = this.isDisabled() ? [] : options.filter((
|
|
122
|
+
const enabled = this.isDisabled() ? [] : options.filter((_option, index) => positions[index]?.isDisabled === false);
|
|
109
123
|
const focusable = enabled.find((option) => option === checked) ?? enabled[0];
|
|
110
124
|
for (const option of options) {
|
|
111
125
|
writeAttribute(option, "disabled", enabled.includes(option) ? void 0 : "");
|
|
@@ -118,45 +132,42 @@ var SonicRadioGroupElement = class extends SonicFormElement {
|
|
|
118
132
|
restoreState(state) {
|
|
119
133
|
this.value = state;
|
|
120
134
|
}
|
|
121
|
-
select(
|
|
122
|
-
const
|
|
135
|
+
select(index) {
|
|
136
|
+
const option = this.options()[index];
|
|
137
|
+
const next = option && optionValue(option);
|
|
123
138
|
if (next === void 0 || next === this.#value) return;
|
|
124
139
|
this.value = next;
|
|
125
140
|
this.dispatchEvent(new Event("change", { bubbles: true }));
|
|
126
141
|
}
|
|
127
142
|
stepFrom(from, step) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
index = this.isWrapping() ? (next + options.length) % options.length : clamp(next, 0, options.length - 1);
|
|
133
|
-
const option = options[index];
|
|
134
|
-
if (option && !this.isOptionDisabled(option)) return option;
|
|
135
|
-
}
|
|
143
|
+
return stepFrom(this.positions(), from, {
|
|
144
|
+
isWrapping: this.isWrapping(),
|
|
145
|
+
step
|
|
146
|
+
});
|
|
136
147
|
}
|
|
137
148
|
#bindPress(group, signal) {
|
|
138
149
|
bindDrag(group, {
|
|
139
150
|
grab: (event) => {
|
|
140
|
-
const
|
|
141
|
-
if (
|
|
142
|
-
if (this.claimPress(
|
|
151
|
+
const index = this.indexOf(event.target);
|
|
152
|
+
if (index === -1 || this.isDisabled() || this.isOptionDisabled(index)) return;
|
|
153
|
+
if (this.claimPress(index, event)) return;
|
|
143
154
|
const boxes = this.#optionBoxes();
|
|
144
|
-
this.#markPressed(
|
|
155
|
+
this.#markPressed(index);
|
|
145
156
|
return {
|
|
146
157
|
boxes,
|
|
147
|
-
|
|
158
|
+
index
|
|
148
159
|
};
|
|
149
160
|
},
|
|
150
161
|
lift: (press) => {
|
|
151
|
-
if (
|
|
152
|
-
const
|
|
153
|
-
if (
|
|
154
|
-
this.select(
|
|
155
|
-
|
|
162
|
+
if (press.index === void 0 || this.isDisabled()) return;
|
|
163
|
+
const index = this.releaseTarget(press.index);
|
|
164
|
+
if (index === void 0) return;
|
|
165
|
+
this.select(index);
|
|
166
|
+
this.refocusAt(index);
|
|
156
167
|
},
|
|
157
168
|
move: (press, event) => {
|
|
158
|
-
press.
|
|
159
|
-
this.#markPressed(press.
|
|
169
|
+
press.index = press.boxes.find(([, box]) => isInside(box, event.clientX, event.clientY))?.[0];
|
|
170
|
+
this.#markPressed(press.index);
|
|
160
171
|
},
|
|
161
172
|
release: () => {
|
|
162
173
|
this.#markPressed(void 0);
|
|
@@ -180,20 +191,12 @@ var SonicRadioGroupElement = class extends SonicFormElement {
|
|
|
180
191
|
this.render();
|
|
181
192
|
if (focused) this.#refocus(focused, focusedValue);
|
|
182
193
|
}
|
|
183
|
-
#keyTarget(option, key) {
|
|
184
|
-
const options = this.options();
|
|
185
|
-
const isEnabled = (other) => !this.isOptionDisabled(other);
|
|
186
|
-
if (key === "Home") return options.find((other) => isEnabled(other));
|
|
187
|
-
if (key === "End") return options.findLast((other) => isEnabled(other));
|
|
188
|
-
const step = keySteps.get(key);
|
|
189
|
-
if (step === void 0) return void 0;
|
|
190
|
-
return this.stepFrom(options.indexOf(option), step) ?? option;
|
|
191
|
-
}
|
|
192
194
|
#markPressed(pressed) {
|
|
193
|
-
for (const option of this.options()) option.toggleAttribute("data-sonic-pressed",
|
|
195
|
+
for (const [index, option] of this.options().entries()) option.toggleAttribute("data-sonic-pressed", index === pressed);
|
|
194
196
|
}
|
|
195
197
|
#optionBoxes() {
|
|
196
|
-
|
|
198
|
+
const positions = this.positions();
|
|
199
|
+
return this.options().flatMap((option, index) => positions[index]?.isDisabled === false ? [[index, option.getBoundingClientRect()]] : []);
|
|
197
200
|
}
|
|
198
201
|
#refocus(focused, value) {
|
|
199
202
|
const options = this.options();
|
|
@@ -17,9 +17,9 @@ function scaleMark(original) {
|
|
|
17
17
|
return mark;
|
|
18
18
|
}
|
|
19
19
|
function bindScale(element, { control, marks }, signal) {
|
|
20
|
-
const {
|
|
20
|
+
const { model } = linkValue(element);
|
|
21
21
|
const render = () => {
|
|
22
|
-
const { proportionOf } = mapping();
|
|
22
|
+
const { proportionOf } = model.mapping();
|
|
23
23
|
for (const mark of marks.children) {
|
|
24
24
|
if (!(mark instanceof HTMLElement || mark instanceof SVGElement)) continue;
|
|
25
25
|
const at = String(proportionOf(scaleValue(mark)));
|
|
@@ -36,7 +36,7 @@ function bindScale(element, { control, marks }, signal) {
|
|
|
36
36
|
render();
|
|
37
37
|
}
|
|
38
38
|
}, signal);
|
|
39
|
-
signal.addEventListener("abort", watch(render), { once: true });
|
|
39
|
+
signal.addEventListener("abort", model.watch(render), { once: true });
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
//#endregion
|
|
@@ -12,11 +12,6 @@ var SonicSegmented = class extends SonicRadioGroupElement {
|
|
|
12
12
|
group = renderSegmented();
|
|
13
13
|
connect(signal) {
|
|
14
14
|
super.connect(signal);
|
|
15
|
-
this.checkStyles(this.group, "segmented.css", [
|
|
16
|
-
"well",
|
|
17
|
-
"keycap",
|
|
18
|
-
["cap", ".sonic-segmented-option"]
|
|
19
|
-
]);
|
|
20
15
|
}
|
|
21
16
|
renderOption() {
|
|
22
17
|
return renderOption();
|
|
@@ -3,6 +3,7 @@ import { requireChild, template } from "../lib/render.js";
|
|
|
3
3
|
import { createModulation } from "./modulation.js";
|
|
4
4
|
import { SonicValueElement } from "./value-element.js";
|
|
5
5
|
import { bindScale } from "./scale.js";
|
|
6
|
+
import { scrubRegions } from "../lib/scrub.js";
|
|
6
7
|
import { sortedRegions } from "../lib/time-regions.js";
|
|
7
8
|
|
|
8
9
|
//#region src/elements/slider.ts
|
|
@@ -39,6 +40,7 @@ var SonicSlider = class extends SonicValueElement {
|
|
|
39
40
|
"scrub",
|
|
40
41
|
"spring"
|
|
41
42
|
];
|
|
43
|
+
/** Loaded spans, in the slider's own values */
|
|
42
44
|
get buffered() {
|
|
43
45
|
return this.#buffered.map(([start, end]) => [start, end]);
|
|
44
46
|
}
|
|
@@ -52,12 +54,14 @@ var SonicSlider = class extends SonicValueElement {
|
|
|
52
54
|
set groovePress(gesture) {
|
|
53
55
|
this.reflect("groove-press", gesture);
|
|
54
56
|
}
|
|
57
|
+
/** How far a modulation source can push the value, in value units; signed */
|
|
55
58
|
get modulation() {
|
|
56
59
|
return this.numberAttribute("modulation", 0);
|
|
57
60
|
}
|
|
58
61
|
set modulation(amount) {
|
|
59
62
|
this.reflect("modulation", amount);
|
|
60
63
|
}
|
|
64
|
+
/** Where the value is right now with modulation applied; a property only, cheap to write every frame, fires nothing */
|
|
61
65
|
get modulationValue() {
|
|
62
66
|
return this.#modulation.value();
|
|
63
67
|
}
|
|
@@ -114,13 +118,6 @@ var SonicSlider = class extends SonicValueElement {
|
|
|
114
118
|
}
|
|
115
119
|
});
|
|
116
120
|
this.render();
|
|
117
|
-
this.checkStyles(slider, "slider.css", [
|
|
118
|
-
"cap",
|
|
119
|
-
"readout",
|
|
120
|
-
"value",
|
|
121
|
-
"groove",
|
|
122
|
-
["glass", ".sonic-slider-readout"]
|
|
123
|
-
]);
|
|
124
121
|
this.bindGestures(slider, signal, (event) => {
|
|
125
122
|
const axis = this.#axis(slider, cap);
|
|
126
123
|
if (event.target instanceof Node && cap.contains(event.target)) return axis;
|
|
@@ -146,11 +143,7 @@ var SonicSlider = class extends SonicValueElement {
|
|
|
146
143
|
focusTarget() {
|
|
147
144
|
return this.#slider;
|
|
148
145
|
}
|
|
149
|
-
|
|
150
|
-
super.heldWrite(next);
|
|
151
|
-
if (this.scrub) this.render();
|
|
152
|
-
}
|
|
153
|
-
holdChanged() {
|
|
146
|
+
scrubChanged() {
|
|
154
147
|
if (this.scrub) this.render();
|
|
155
148
|
}
|
|
156
149
|
scrubsKeyRepeat() {
|
|
@@ -199,18 +192,16 @@ var SonicSlider = class extends SonicValueElement {
|
|
|
199
192
|
}
|
|
200
193
|
#renderScrub(slider) {
|
|
201
194
|
const { style } = slider;
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
const scrubbed = proportionOf(this.value);
|
|
206
|
-
if (isHeld) style.setProperty("--_sonic-slider-played", String(played));
|
|
195
|
+
const state = this.scrubState();
|
|
196
|
+
const { played, scrub } = scrubRegions(state, this.value, this.mapping());
|
|
197
|
+
if (this.scrub && state.from !== void 0) style.setProperty("--_sonic-slider-played", String(played));
|
|
207
198
|
else style.removeProperty("--_sonic-slider-played");
|
|
208
|
-
if (
|
|
199
|
+
if (scrub === void 0 || !this.scrub) {
|
|
209
200
|
style.removeProperty("--_sonic-slider-scrub-region");
|
|
210
201
|
return;
|
|
211
202
|
}
|
|
212
|
-
const from = grooveStop(Math.min(played,
|
|
213
|
-
const to = grooveStop(Math.max(played,
|
|
203
|
+
const from = grooveStop(Math.min(played, scrub));
|
|
204
|
+
const to = grooveStop(Math.max(played, scrub));
|
|
214
205
|
style.setProperty("--_sonic-slider-scrub-region", `linear-gradient(var(--_sonic-slider-toward), transparent ${from}, var(--_sonic-slider-scrub) ${from} ${to}, transparent ${to})`);
|
|
215
206
|
}
|
|
216
207
|
};
|
|
@@ -58,7 +58,7 @@ var SonicElement = class extends HTMLElement {
|
|
|
58
58
|
}
|
|
59
59
|
if (!this.isDisabled() && !this.#focused()) target.focus(options);
|
|
60
60
|
}
|
|
61
|
-
checkStyles(control, sheet, material
|
|
61
|
+
checkStyles(control, sheet, { box, material }) {}
|
|
62
62
|
focusTarget() {}
|
|
63
63
|
forwardNaming(target, isNamed) {
|
|
64
64
|
const labels = isNamed ? this.namingLabels() : [];
|
|
@@ -124,6 +124,8 @@ var SonicElement = class extends HTMLElement {
|
|
|
124
124
|
this[name] = value;
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
|
+
#checkBox(control, checked, box) {}
|
|
128
|
+
#checkHost(checked) {}
|
|
127
129
|
#focused() {
|
|
128
130
|
const root = this.getRootNode();
|
|
129
131
|
const active = root instanceof ShadowRoot ? root.activeElement : this.ownerDocument.activeElement;
|
|
@@ -22,7 +22,7 @@ function gridLimits(mapping, [low, high]) {
|
|
|
22
22
|
return [bottom < low - gridSlop ? mapping.keyTarget("ArrowRight", bottom) ?? bottom : bottom, top > high + gridSlop ? mapping.keyTarget("ArrowLeft", top) ?? top : top];
|
|
23
23
|
}
|
|
24
24
|
function modelOf(member, value, isFree) {
|
|
25
|
-
const mapping = member.link.mapping();
|
|
25
|
+
const mapping = member.link.model.mapping();
|
|
26
26
|
const [first, last] = mapping.bounds;
|
|
27
27
|
return {
|
|
28
28
|
isFree,
|
|
@@ -46,6 +46,7 @@ var SonicSplit = class extends SonicElement {
|
|
|
46
46
|
set mode(name) {
|
|
47
47
|
this.reflect("mode", name);
|
|
48
48
|
}
|
|
49
|
+
/** What the members add up to; unset, it is their sum when they connect */
|
|
49
50
|
get total() {
|
|
50
51
|
return this.optionalNumberAttribute("total");
|
|
51
52
|
}
|
|
@@ -105,7 +106,7 @@ var SonicSplit = class extends SonicElement {
|
|
|
105
106
|
}
|
|
106
107
|
#compensate() {
|
|
107
108
|
this.#isQueued = false;
|
|
108
|
-
for (const mover of this.#members) if (mover.link.value
|
|
109
|
+
for (const mover of this.#members) if (mover.link.model.value !== mover.seen) this.#move(mover);
|
|
109
110
|
}
|
|
110
111
|
#find() {
|
|
111
112
|
const found = [];
|
|
@@ -121,18 +122,18 @@ var SonicSplit = class extends SonicElement {
|
|
|
121
122
|
}
|
|
122
123
|
#join(element) {
|
|
123
124
|
const link = linkValue(element);
|
|
124
|
-
const unwatch = link.watch(() => {
|
|
125
|
+
const unwatch = link.model.watch(() => {
|
|
125
126
|
if (this.#isWriting || this.#isQueued) return;
|
|
126
127
|
this.#isQueued = true;
|
|
127
128
|
queueMicrotask(() => {
|
|
128
129
|
if (this.#isQueued) this.#compensate();
|
|
129
130
|
});
|
|
130
131
|
});
|
|
131
|
-
link.
|
|
132
|
+
link.model.setLanding((target, direction) => this.#land(element, target, direction));
|
|
132
133
|
return {
|
|
133
134
|
element,
|
|
134
135
|
link,
|
|
135
|
-
seen: link.value
|
|
136
|
+
seen: link.model.value,
|
|
136
137
|
unwatch
|
|
137
138
|
};
|
|
138
139
|
}
|
|
@@ -155,7 +156,7 @@ var SonicSplit = class extends SonicElement {
|
|
|
155
156
|
for (const [index, member] of this.#members.entries()) {
|
|
156
157
|
const model = this.#model(values, member);
|
|
157
158
|
const value = values[index] ?? member.seen;
|
|
158
|
-
member.link.
|
|
159
|
+
member.link.model.setLimit(isLocked(member) ? [value, value] : gridLimits(member.link.model.mapping(), splitLimits(model, index, this.#total)));
|
|
159
160
|
}
|
|
160
161
|
}
|
|
161
162
|
#model(values, mover) {
|
|
@@ -177,7 +178,7 @@ var SonicSplit = class extends SonicElement {
|
|
|
177
178
|
total: this.#total
|
|
178
179
|
}, {
|
|
179
180
|
index,
|
|
180
|
-
target: mover.link.value
|
|
181
|
+
target: mover.link.model.value
|
|
181
182
|
}), mover);
|
|
182
183
|
this.#limit();
|
|
183
184
|
}
|
|
@@ -187,7 +188,7 @@ var SonicSplit = class extends SonicElement {
|
|
|
187
188
|
const snapshot = this.#snapshot;
|
|
188
189
|
if (snapshot?.mover.element !== event.target) return;
|
|
189
190
|
this.#snapshot = void 0;
|
|
190
|
-
const changed = this.#members.filter((member, index) => member !== snapshot.mover && member.link.value
|
|
191
|
+
const changed = this.#members.filter((member, index) => member !== snapshot.mover && member.link.model.value !== snapshot.values[index]);
|
|
191
192
|
queueMicrotask(() => {
|
|
192
193
|
this.#isWriting = true;
|
|
193
194
|
try {
|
|
@@ -213,8 +214,8 @@ var SonicSplit = class extends SonicElement {
|
|
|
213
214
|
#unbind() {
|
|
214
215
|
for (const { link, unwatch } of this.#members) {
|
|
215
216
|
unwatch();
|
|
216
|
-
link.
|
|
217
|
-
link.
|
|
217
|
+
link.model.setLanding(void 0);
|
|
218
|
+
link.model.setLimit(void 0);
|
|
218
219
|
}
|
|
219
220
|
this.#members = [];
|
|
220
221
|
this.#snapshot = void 0;
|
|
@@ -234,14 +235,14 @@ var SonicSplit = class extends SonicElement {
|
|
|
234
235
|
try {
|
|
235
236
|
for (const [index, member] of this.#members.entries()) {
|
|
236
237
|
const value = values[index];
|
|
237
|
-
if (value === void 0 || value === member.link.value
|
|
238
|
-
member.link.
|
|
238
|
+
if (value === void 0 || value === member.link.model.value) continue;
|
|
239
|
+
member.link.model.setLimit(void 0);
|
|
239
240
|
member.link.input(value, member === mover);
|
|
240
241
|
}
|
|
241
242
|
} finally {
|
|
242
243
|
this.#isWriting = false;
|
|
243
244
|
}
|
|
244
|
-
for (const member of this.#members) member.seen = member.link.value
|
|
245
|
+
for (const member of this.#members) member.seen = member.link.model.value;
|
|
245
246
|
}
|
|
246
247
|
};
|
|
247
248
|
|