@xsynaptic/sonic-ui 0.16.0 → 0.18.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 +20 -0
- package/README.md +112 -19
- package/dist/default/dat.js +1 -0
- package/dist/default/elements/button.js +2 -0
- package/dist/default/elements/dial.js +2 -0
- package/dist/default/elements/display-element.js +9 -7
- package/dist/default/elements/envelope.js +31 -72
- package/dist/default/elements/field-gesture.js +81 -0
- package/dist/default/elements/meter.js +4 -0
- 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/slider.js +11 -13
- package/dist/default/elements/split.js +14 -13
- package/dist/default/elements/switch.js +31 -46
- package/dist/default/elements/toggle.js +20 -44
- package/dist/default/elements/value-element.js +65 -91
- package/dist/default/elements/value-gestures.js +22 -22
- package/dist/default/elements/wave-element.js +9 -12
- package/dist/default/elements/waveform.js +64 -249
- package/dist/default/elements/wavestrip.js +10 -5
- package/dist/default/elements/xy.js +67 -112
- package/dist/default/lib/canvas-surface.js +25 -0
- package/dist/default/lib/crossfade.js +1 -0
- package/dist/default/lib/envelope-curve.js +1 -0
- package/dist/default/lib/marker-rider.js +37 -14
- 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/value-model.js +62 -0
- package/dist/default/lib/waveform-scene.js +108 -0
- package/dist/default/lib/zoom-gesture.js +97 -1
- package/dist/dev/dat.d.ts +1 -0
- package/dist/dev/dat.js +1 -0
- package/dist/dev/dat.js.map +1 -1
- package/dist/dev/elements/button.d.ts +2 -0
- package/dist/dev/elements/button.js +2 -0
- package/dist/dev/elements/button.js.map +1 -1
- package/dist/dev/elements/dial.d.ts +2 -0
- package/dist/dev/elements/dial.js +2 -0
- 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 +9 -7
- package/dist/dev/elements/display-element.js.map +1 -1
- package/dist/dev/elements/envelope.js +31 -72
- 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 +4 -0
- package/dist/dev/elements/meter.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/slider.d.ts +4 -2
- package/dist/dev/elements/slider.js +11 -13
- package/dist/dev/elements/slider.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 +31 -46
- package/dist/dev/elements/switch.js.map +1 -1
- package/dist/dev/elements/toggle.js +20 -44
- package/dist/dev/elements/toggle.js.map +1 -1
- package/dist/dev/elements/value-element.d.ts +5 -5
- package/dist/dev/elements/value-element.js +65 -91
- 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 +7 -4
- package/dist/dev/elements/wave-element.js +9 -12
- package/dist/dev/elements/wave-element.js.map +1 -1
- package/dist/dev/elements/waveform.d.ts +23 -22
- package/dist/dev/elements/waveform.js +64 -249
- 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 +67 -112
- package/dist/dev/elements/xy.js.map +1 -1
- package/dist/dev/index.d.ts +3 -2
- 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/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/marker-rider.js +37 -14
- package/dist/dev/lib/marker-rider.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/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 +1 -0
- 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/styles/button.css +16 -6
- package/dist/styles/waveform.css +12 -4
- package/package.json +1 -1
- package/dist/default/lib/asked-value.js +0 -21
- package/dist/default/lib/fill-watch.js +0 -29
- 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,7 +1,8 @@
|
|
|
1
1
|
import { placeChildren, requireChild, template } from "../lib/render.js";
|
|
2
2
|
import { bindDrag } from "../lib/pointer-drag.js";
|
|
3
3
|
import { dragThresholdPx } from "../lib/drag-step.js";
|
|
4
|
-
import {
|
|
4
|
+
import { enabledEnds } from "../lib/positions.js";
|
|
5
|
+
import { isUnder } from "./radio-group.js";
|
|
5
6
|
import { SonicPositionGroupElement } from "./position-group.js";
|
|
6
7
|
import { positionAt, travelFrom } from "../lib/toggle-travel.js";
|
|
7
8
|
|
|
@@ -52,7 +53,7 @@ var SonicToggle = class extends SonicPositionGroupElement {
|
|
|
52
53
|
}
|
|
53
54
|
render() {
|
|
54
55
|
if (!this.isBound()) return;
|
|
55
|
-
this.group.style.setProperty("--_sonic-toggle-count", String(this
|
|
56
|
+
this.group.style.setProperty("--_sonic-toggle-count", String(this.positions().length));
|
|
56
57
|
this.#placeCap(this.#draggedTo ?? this.#restingAt());
|
|
57
58
|
super.render();
|
|
58
59
|
for (const [index, option] of this.options().entries()) option.style.setProperty("--_sonic-toggle-index", String(index));
|
|
@@ -77,7 +78,7 @@ var SonicToggle = class extends SonicPositionGroupElement {
|
|
|
77
78
|
this.#slideTo(positionAt(drag.travel, pointer), event.pointerId);
|
|
78
79
|
},
|
|
79
80
|
release: (drag) => {
|
|
80
|
-
delete
|
|
81
|
+
delete drag.marked.dataset.sonicPressed;
|
|
81
82
|
this.#draggedTo = void 0;
|
|
82
83
|
this.toggleState("dragging", false);
|
|
83
84
|
this.render();
|
|
@@ -85,25 +86,21 @@ var SonicToggle = class extends SonicPositionGroupElement {
|
|
|
85
86
|
}, signal);
|
|
86
87
|
}
|
|
87
88
|
#checkLegends() {}
|
|
88
|
-
#enabledEnds() {
|
|
89
|
-
if (this.isBare()) return [0, 1];
|
|
90
|
-
const options = this.options();
|
|
91
|
-
const isEnabled = (option) => !this.isOptionDisabled(option);
|
|
92
|
-
return [options.findIndex(isEnabled), options.findLastIndex(isEnabled)];
|
|
93
|
-
}
|
|
94
89
|
#fixedLegend() {
|
|
95
90
|
return [...this.children].find((child) => child !== this.group && !super.isMirrored(child));
|
|
96
91
|
}
|
|
97
92
|
#grab(event) {
|
|
98
|
-
const position = this.
|
|
99
|
-
if (this.isDisabled() ||
|
|
93
|
+
const position = this.pressedIndex(event.target);
|
|
94
|
+
if (this.isDisabled() || position < 0) return void 0;
|
|
100
95
|
const isOnCap = isUnder(this.#cap, event.clientX, event.clientY);
|
|
101
96
|
const travel = this.#travel(event, isOnCap);
|
|
102
|
-
if (!travel || this
|
|
103
|
-
(position ?? this.bare
|
|
97
|
+
if (!travel || !isOnCap && this.isOptionDisabled(position)) return void 0;
|
|
98
|
+
const marked = this.options()[position] ?? this.bare;
|
|
99
|
+
marked.toggleAttribute("data-sonic-pressed", true);
|
|
104
100
|
return {
|
|
105
101
|
hasMoved: false,
|
|
106
102
|
isHolding: this.#holdFrom(position, event.pointerId),
|
|
103
|
+
marked,
|
|
107
104
|
position,
|
|
108
105
|
start: this.along(event),
|
|
109
106
|
thresholdPx: dragThresholdPx(event.pointerType),
|
|
@@ -111,57 +108,36 @@ var SonicToggle = class extends SonicPositionGroupElement {
|
|
|
111
108
|
};
|
|
112
109
|
}
|
|
113
110
|
#holdFrom(position, pointerId) {
|
|
114
|
-
const target =
|
|
115
|
-
if (!
|
|
111
|
+
const target = this.pressTarget(position);
|
|
112
|
+
if (!this.isMomentary(target) || this.isOptionDisabled(target)) return false;
|
|
116
113
|
this.hold(target, pointerId);
|
|
117
114
|
return true;
|
|
118
115
|
}
|
|
119
|
-
#isBlocked(position, isOnCap) {
|
|
120
|
-
return !isOnCap && position !== void 0 && this.isOptionDisabled(position);
|
|
121
|
-
}
|
|
122
|
-
#onAt() {
|
|
123
|
-
return this.orientation === "vertical" ? 0 : 1;
|
|
124
|
-
}
|
|
125
116
|
#placeCap(at) {
|
|
126
117
|
this.group.style.setProperty("--_sonic-toggle-at", String(at));
|
|
127
118
|
}
|
|
128
119
|
#press(position) {
|
|
129
|
-
if (!position) {
|
|
130
|
-
this.setChecked(!this.checked);
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
120
|
const target = this.pressTarget(position);
|
|
134
121
|
if (this.isOptionDisabled(target)) return;
|
|
135
122
|
this.select(target);
|
|
136
|
-
this
|
|
137
|
-
}
|
|
138
|
-
#refocus(position) {
|
|
139
|
-
if (this.group.matches(":focus-within")) position.focus();
|
|
123
|
+
this.refocusAt(target);
|
|
140
124
|
}
|
|
141
125
|
#restingAt() {
|
|
142
|
-
|
|
143
|
-
return Math.max(0, this.checkedIndex(this.options()));
|
|
126
|
+
return Math.max(0, this.checkedIndex());
|
|
144
127
|
}
|
|
145
128
|
#slideTo(at, pointerId) {
|
|
146
|
-
const crossed =
|
|
129
|
+
const crossed = Math.round(at);
|
|
147
130
|
this.#draggedTo = at;
|
|
148
131
|
this.#placeCap(at);
|
|
149
|
-
if (this.
|
|
150
|
-
this.setChecked(Math.round(at) === this.#onAt());
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
if (!crossed || optionValue(crossed) === this.value) return;
|
|
132
|
+
if (this.isChecked(crossed)) return;
|
|
154
133
|
this.releaseHold();
|
|
155
|
-
if (this.isOptionDisabled(crossed) ||
|
|
134
|
+
if (this.isOptionDisabled(crossed) || this.isChecked(crossed)) return;
|
|
156
135
|
if (this.isMomentary(crossed)) this.hold(crossed, pointerId);
|
|
157
136
|
else this.select(crossed);
|
|
158
|
-
this
|
|
159
|
-
}
|
|
160
|
-
#stopCount() {
|
|
161
|
-
return this.options().length || 2;
|
|
137
|
+
this.refocusAt(crossed);
|
|
162
138
|
}
|
|
163
139
|
#travel(event, isOnCap) {
|
|
164
|
-
const [first, last] =
|
|
140
|
+
const [first, last] = enabledEnds(this.positions());
|
|
165
141
|
if (first < 0) return void 0;
|
|
166
142
|
const box = this.#well.getBoundingClientRect();
|
|
167
143
|
const [start, length, thickness] = this.orientation === "vertical" ? [
|
|
@@ -175,7 +151,7 @@ var SonicToggle = class extends SonicPositionGroupElement {
|
|
|
175
151
|
];
|
|
176
152
|
return travelFrom({
|
|
177
153
|
at: this.#restingAt(),
|
|
178
|
-
count: this
|
|
154
|
+
count: this.positions().length,
|
|
179
155
|
first,
|
|
180
156
|
isOnCap,
|
|
181
157
|
last,
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { toNumber, trimFloat } from "../lib/math.js";
|
|
2
2
|
import { writeAttribute } from "../lib/write-attribute.js";
|
|
3
3
|
import { SonicFormElement } from "./form-element.js";
|
|
4
4
|
import { Readout } from "./readout.js";
|
|
5
5
|
import { readPxProperty } from "../lib/read-px-property.js";
|
|
6
6
|
import { parseNumberList } from "../lib/number-list.js";
|
|
7
|
-
import { valueMapping } from "../lib/value-mapping.js";
|
|
8
7
|
import { ValueGestures } from "./value-gestures.js";
|
|
9
|
-
import { moveTo, resnap, setAsked } from "../lib/asked-value.js";
|
|
10
8
|
import { bindHoverPreview } from "../lib/hover-preview.js";
|
|
9
|
+
import { createValueModel } from "../lib/value-model.js";
|
|
11
10
|
|
|
12
11
|
//#region src/elements/value-element.ts
|
|
13
12
|
const fallbackTravelPx = 160;
|
|
@@ -56,20 +55,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
56
55
|
input: (next, isMover = false) => (isMover || !element.#isHeld()) && element.input(next),
|
|
57
56
|
isDisabled: () => element.isDisabled(),
|
|
58
57
|
isHeld: () => element.#isHeld(),
|
|
59
|
-
|
|
60
|
-
element.#land = resolve;
|
|
61
|
-
},
|
|
62
|
-
limit: (bounds) => {
|
|
63
|
-
element.#limit = bounds;
|
|
64
|
-
},
|
|
65
|
-
mapping: () => element.mapping(),
|
|
66
|
-
value: () => element.#cell.value,
|
|
67
|
-
watch: (listener) => {
|
|
68
|
-
element.#watchers.add(listener);
|
|
69
|
-
return () => {
|
|
70
|
-
element.#watchers.delete(listener);
|
|
71
|
-
};
|
|
72
|
-
}
|
|
58
|
+
model: element.#model
|
|
73
59
|
});
|
|
74
60
|
}
|
|
75
61
|
get cancelling() {
|
|
@@ -177,6 +163,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
177
163
|
get pointerType() {
|
|
178
164
|
return this.#gestures?.pointerType();
|
|
179
165
|
}
|
|
166
|
+
/** The values a stepped control stops at, spaced evenly along the travel whatever their spacing */
|
|
180
167
|
get positions() {
|
|
181
168
|
return parseNumberList(this.getAttribute("positions"));
|
|
182
169
|
}
|
|
@@ -192,6 +179,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
192
179
|
get revealed() {
|
|
193
180
|
return this.hasState("revealed");
|
|
194
181
|
}
|
|
182
|
+
/** Rounds the value assistive technology hears, in value units; the value itself is untouched */
|
|
195
183
|
get spokenStep() {
|
|
196
184
|
return this.optionalNumberAttribute("spoken-step");
|
|
197
185
|
}
|
|
@@ -211,7 +199,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
211
199
|
this.reflect("taper", curve);
|
|
212
200
|
}
|
|
213
201
|
get value() {
|
|
214
|
-
return this.#
|
|
202
|
+
return this.#model.value;
|
|
215
203
|
}
|
|
216
204
|
set value(next) {
|
|
217
205
|
if (next === void 0 || next === null) {
|
|
@@ -220,18 +208,14 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
220
208
|
}
|
|
221
209
|
const value = toNumber(next);
|
|
222
210
|
if (this.#isHeld()) {
|
|
223
|
-
this
|
|
211
|
+
this.#writeHeld(value);
|
|
224
212
|
return;
|
|
225
213
|
}
|
|
226
|
-
if (
|
|
214
|
+
if (this.#model.write(value)) this.render();
|
|
227
215
|
}
|
|
228
216
|
get valueText() {
|
|
229
|
-
return this.#textFor(this.#
|
|
217
|
+
return this.#textFor(this.#model.value);
|
|
230
218
|
}
|
|
231
|
-
#cell = {
|
|
232
|
-
asked: void 0,
|
|
233
|
-
value: 0
|
|
234
|
-
};
|
|
235
219
|
#formatEntry;
|
|
236
220
|
#formatSpokenValue;
|
|
237
221
|
#formatValue;
|
|
@@ -239,25 +223,16 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
239
223
|
#heldAt;
|
|
240
224
|
#hover;
|
|
241
225
|
#instance = String(instanceCount += 1);
|
|
242
|
-
#
|
|
243
|
-
#limit;
|
|
244
|
-
#mapping;
|
|
226
|
+
#model = createValueModel(() => this.#spec());
|
|
245
227
|
#parseValue;
|
|
246
|
-
#positions;
|
|
247
228
|
#readout;
|
|
248
|
-
#watchers = /* @__PURE__ */ new Set();
|
|
249
229
|
attributeChangedCallback(name) {
|
|
250
|
-
this.#
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if (this.#isHeld()) {
|
|
254
|
-
this.heldWrite(this.numberAttribute("value", this.min));
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
this.#cell.asked = void 0;
|
|
230
|
+
if (name === "value" && this.#isHeld()) {
|
|
231
|
+
this.#writeHeld(this.numberAttribute("value", this.min));
|
|
232
|
+
return;
|
|
258
233
|
}
|
|
259
234
|
if (name === "disabled" && this.isDisabled()) this.#gestures?.end();
|
|
260
|
-
|
|
235
|
+
this.#model.respec(this.numberAttribute("value", this.min), { forgetAsk: name === "value" });
|
|
261
236
|
if (proportionAttributes.has(name) && this.isBound()) this.proportionsChanged();
|
|
262
237
|
this.render();
|
|
263
238
|
}
|
|
@@ -287,26 +262,23 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
287
262
|
this.forwardNaming(target, isNamed);
|
|
288
263
|
},
|
|
289
264
|
hasEntry: () => this.entry !== "none",
|
|
290
|
-
holdChanged: () => {
|
|
291
|
-
this.#renderHold();
|
|
292
|
-
},
|
|
293
265
|
input: (next) => this.input(next),
|
|
294
266
|
isDisabled: () => this.isDisabled(),
|
|
295
267
|
keyStep: () => this.keyStep,
|
|
296
|
-
|
|
297
|
-
limit: () => this.#limit,
|
|
298
|
-
mapping: () => this.mapping(),
|
|
268
|
+
model: this.#model,
|
|
299
269
|
parse: (text) => (this.#parseValue ?? Number.parseFloat)(text),
|
|
300
270
|
render: () => {
|
|
301
271
|
this.render();
|
|
302
272
|
},
|
|
273
|
+
scrubChanged: () => {
|
|
274
|
+
this.#renderHold();
|
|
275
|
+
},
|
|
303
276
|
scrubsKeyRepeat: () => this.scrubsKeyRepeat(),
|
|
304
277
|
springTarget: () => this.springTarget(),
|
|
305
278
|
tapTarget: () => this.tapTarget(),
|
|
306
279
|
toggleState: (state, isOn) => {
|
|
307
280
|
this.toggleState(state, isOn);
|
|
308
|
-
}
|
|
309
|
-
value: () => this.#cell.value
|
|
281
|
+
}
|
|
310
282
|
}, control);
|
|
311
283
|
this.#gestures.bind(signal, grab);
|
|
312
284
|
control.addEventListener("pointerup", (event) => {
|
|
@@ -322,7 +294,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
322
294
|
dismiss: () => {
|
|
323
295
|
this.render();
|
|
324
296
|
},
|
|
325
|
-
isTaken: () => this.#isEditing() || this
|
|
297
|
+
isTaken: () => this.#isEditing() || this.#isRevealed(),
|
|
326
298
|
show: () => {
|
|
327
299
|
if (!this.readout) return;
|
|
328
300
|
this.renderReadout();
|
|
@@ -335,60 +307,32 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
335
307
|
controlRole() {
|
|
336
308
|
return "slider";
|
|
337
309
|
}
|
|
338
|
-
heldFrom() {
|
|
339
|
-
return this.#gestures?.heldFrom();
|
|
340
|
-
}
|
|
341
|
-
heldWrite(next) {
|
|
342
|
-
this.#heldAt = next;
|
|
343
|
-
}
|
|
344
|
-
holdChanged() {}
|
|
345
310
|
input(next) {
|
|
346
|
-
const previous = this.#
|
|
347
|
-
|
|
348
|
-
if (
|
|
349
|
-
if (this.#cell.value === previous) return false;
|
|
311
|
+
const previous = this.#model.value;
|
|
312
|
+
if (this.#model.input(next)) this.render();
|
|
313
|
+
if (this.#model.value === previous) return false;
|
|
350
314
|
this.dispatchEvent(new Event("input", {
|
|
351
315
|
bubbles: true,
|
|
352
316
|
composed: true
|
|
353
317
|
}));
|
|
354
318
|
return true;
|
|
355
319
|
}
|
|
356
|
-
isRevealed() {
|
|
357
|
-
return this.#gestures?.isRevealed() === true;
|
|
358
|
-
}
|
|
359
320
|
isWrapping() {
|
|
360
321
|
return false;
|
|
361
322
|
}
|
|
362
323
|
mapping() {
|
|
363
|
-
|
|
364
|
-
const { detent, midpoint } = this;
|
|
365
|
-
this.#mapping = valueMapping({
|
|
366
|
-
...detent === void 0 ? {} : { detent },
|
|
367
|
-
...this.#positions ? { positions: this.#positions } : {},
|
|
368
|
-
max: this.max,
|
|
369
|
-
...midpoint === void 0 ? {} : { midpoint },
|
|
370
|
-
isNotched: this.notched,
|
|
371
|
-
isWrapping: this.isWrapping(),
|
|
372
|
-
min: this.min,
|
|
373
|
-
step: this.step,
|
|
374
|
-
taper: this.taper
|
|
375
|
-
});
|
|
376
|
-
return this.#mapping;
|
|
324
|
+
return this.#model.mapping();
|
|
377
325
|
}
|
|
378
326
|
originValue() {
|
|
379
327
|
return this.origin ?? this.mapping().bounds[0];
|
|
380
328
|
}
|
|
381
|
-
playback() {
|
|
382
|
-
const from = this.heldFrom();
|
|
383
|
-
return from === void 0 ? this.#cell.value : this.#heldAt ?? from;
|
|
384
|
-
}
|
|
385
329
|
proportionsChanged() {}
|
|
386
330
|
readoutValue() {
|
|
387
|
-
return this.#shown().value ?? this.#
|
|
331
|
+
return this.#shown().value ?? this.#model.value;
|
|
388
332
|
}
|
|
389
333
|
render() {
|
|
390
334
|
if (this.isBound()) this.#renderControl();
|
|
391
|
-
|
|
335
|
+
this.#model.notify();
|
|
392
336
|
}
|
|
393
337
|
renderReadout() {
|
|
394
338
|
const readout = this.#readout;
|
|
@@ -404,16 +348,25 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
404
348
|
restoreState(state) {
|
|
405
349
|
this.value = Number(state);
|
|
406
350
|
}
|
|
351
|
+
scrubChanged() {}
|
|
407
352
|
scrubsKeyRepeat() {
|
|
408
353
|
return false;
|
|
409
354
|
}
|
|
355
|
+
scrubState() {
|
|
356
|
+
const from = this.#gestures?.scrubFrom();
|
|
357
|
+
return {
|
|
358
|
+
from,
|
|
359
|
+
isRevealed: this.#isRevealed(),
|
|
360
|
+
played: from === void 0 ? this.#model.value : this.#heldAt ?? from
|
|
361
|
+
};
|
|
362
|
+
}
|
|
410
363
|
springTarget() {}
|
|
411
364
|
tapTarget() {}
|
|
412
365
|
travelPx(control, property) {
|
|
413
366
|
return Math.max(1, readPxProperty(getComputedStyle(control), property, fallbackTravelPx));
|
|
414
367
|
}
|
|
415
368
|
#entryText() {
|
|
416
|
-
const value = this.#
|
|
369
|
+
const value = this.#model.value;
|
|
417
370
|
if (this.#formatEntry) return this.#formatEntry(value);
|
|
418
371
|
if (!this.#parseValue) return String(value);
|
|
419
372
|
return this.valueText;
|
|
@@ -424,8 +377,11 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
424
377
|
#isHeld() {
|
|
425
378
|
return this.#gestures?.isHeld() === true;
|
|
426
379
|
}
|
|
380
|
+
#isRevealed() {
|
|
381
|
+
return this.#gestures?.isRevealed() === true;
|
|
382
|
+
}
|
|
427
383
|
#renderAria(control, orientation) {
|
|
428
|
-
this.writeFormValue(String(this.#
|
|
384
|
+
this.writeFormValue(String(this.#model.value), String(this.#model.value));
|
|
429
385
|
if (this.#isEditing()) {
|
|
430
386
|
for (const name of roleAttributes) control.removeAttribute(name);
|
|
431
387
|
this.forwardNaming(control, false);
|
|
@@ -444,9 +400,9 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
444
400
|
this.renderReadout();
|
|
445
401
|
}
|
|
446
402
|
#renderControl() {
|
|
447
|
-
if (this.#isEditing() || this
|
|
403
|
+
if (this.#isEditing() || this.#isRevealed()) this.#hover?.clear();
|
|
448
404
|
this.draw();
|
|
449
|
-
this.toggleState("at-origin", !this.isWrapping() && this.#
|
|
405
|
+
this.toggleState("at-origin", !this.isWrapping() && this.#model.value === this.mapping().snap(this.originValue()));
|
|
450
406
|
this.#renderAria(this.focusTarget(), this.controlOrientation());
|
|
451
407
|
}
|
|
452
408
|
#renderDisabled(control) {
|
|
@@ -456,30 +412,48 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
456
412
|
writeAttribute(control, "tabindex", isDisabled ? void 0 : stop);
|
|
457
413
|
}
|
|
458
414
|
#renderHold() {
|
|
459
|
-
if (this
|
|
415
|
+
if (this.#gestures?.scrubFrom() === void 0) this.#heldAt = void 0;
|
|
460
416
|
this.#hover?.restore();
|
|
461
417
|
this.renderReadout();
|
|
462
|
-
this.
|
|
418
|
+
this.scrubChanged();
|
|
463
419
|
}
|
|
464
420
|
#shown() {
|
|
465
421
|
if (this.#isEditing()) return {
|
|
466
422
|
isOpen: true,
|
|
467
423
|
value: void 0
|
|
468
424
|
};
|
|
469
|
-
const isRevealed = this
|
|
425
|
+
const isRevealed = this.#isRevealed();
|
|
470
426
|
const preview = isRevealed ? void 0 : this.#hover?.value();
|
|
471
427
|
return {
|
|
472
428
|
isOpen: (isRevealed || preview !== void 0) && this.readout,
|
|
473
|
-
value: preview ?? this.#
|
|
429
|
+
value: preview ?? this.#model.value
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
#spec() {
|
|
433
|
+
const { detent, midpoint, positions } = this;
|
|
434
|
+
return {
|
|
435
|
+
...detent === void 0 ? {} : { detent },
|
|
436
|
+
...positions ? { positions } : {},
|
|
437
|
+
max: this.max,
|
|
438
|
+
...midpoint === void 0 ? {} : { midpoint },
|
|
439
|
+
isNotched: this.notched,
|
|
440
|
+
isWrapping: this.isWrapping(),
|
|
441
|
+
min: this.min,
|
|
442
|
+
step: this.step,
|
|
443
|
+
taper: this.taper
|
|
474
444
|
};
|
|
475
445
|
}
|
|
476
446
|
#spokenNow() {
|
|
477
447
|
const step = this.spokenStep;
|
|
478
|
-
return step !== void 0 && step > 0 ? trimFloat(Math.round(this.#
|
|
448
|
+
return step !== void 0 && step > 0 ? trimFloat(Math.round(this.#model.value / step) * step) : this.#model.value;
|
|
479
449
|
}
|
|
480
450
|
#textFor(value) {
|
|
481
451
|
return this.#formatValue?.(value) ?? String(value);
|
|
482
452
|
}
|
|
453
|
+
#writeHeld(next) {
|
|
454
|
+
this.#heldAt = next;
|
|
455
|
+
this.scrubChanged();
|
|
456
|
+
}
|
|
483
457
|
};
|
|
484
458
|
|
|
485
459
|
//#endregion
|
|
@@ -14,7 +14,7 @@ const detentZonePx = 8;
|
|
|
14
14
|
var ValueGestures = class {
|
|
15
15
|
#claim = new ReadoutClaim(() => {
|
|
16
16
|
this.#showRevealed();
|
|
17
|
-
this.#host.
|
|
17
|
+
this.#host.scrubChanged();
|
|
18
18
|
});
|
|
19
19
|
#control;
|
|
20
20
|
#entry;
|
|
@@ -53,7 +53,7 @@ var ValueGestures = class {
|
|
|
53
53
|
this.#pointerType = void 0;
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
|
-
const fromValue = host.value
|
|
56
|
+
const fromValue = host.model.value;
|
|
57
57
|
host.toggleState("dragging", true);
|
|
58
58
|
const axis = grab(event);
|
|
59
59
|
if (!axis) {
|
|
@@ -103,9 +103,6 @@ var ValueGestures = class {
|
|
|
103
103
|
this.#pointerDrag?.end();
|
|
104
104
|
this.#endKeyScrub();
|
|
105
105
|
}
|
|
106
|
-
heldFrom() {
|
|
107
|
-
return this.#dragging()?.fromValue ?? this.#keyScrub?.fromValue;
|
|
108
|
-
}
|
|
109
106
|
isEditing() {
|
|
110
107
|
return this.#entry?.isOpen === true;
|
|
111
108
|
}
|
|
@@ -118,6 +115,9 @@ var ValueGestures = class {
|
|
|
118
115
|
pointerType() {
|
|
119
116
|
return this.#pointerType;
|
|
120
117
|
}
|
|
118
|
+
scrubFrom() {
|
|
119
|
+
return this.#dragging()?.fromValue ?? this.#keyScrub?.fromValue;
|
|
120
|
+
}
|
|
121
121
|
#bindEntry(signal) {
|
|
122
122
|
const control = this.#control;
|
|
123
123
|
const host = this.#host;
|
|
@@ -156,13 +156,13 @@ var ValueGestures = class {
|
|
|
156
156
|
this.#claim.reveal("keys");
|
|
157
157
|
this.#showRevealed();
|
|
158
158
|
this.#keyTo(event, next);
|
|
159
|
-
host.
|
|
159
|
+
host.scrubChanged();
|
|
160
160
|
}, { signal });
|
|
161
161
|
control.addEventListener("keyup", (event) => {
|
|
162
162
|
const isMeta = event.key === "Meta";
|
|
163
163
|
if (isMeta || event.key === this.#keyScrub?.key) this.#endKeyScrub();
|
|
164
164
|
if (isMeta && this.#dragging()) return;
|
|
165
|
-
if (isMeta || host.mapping().keyTarget(event.key, host.value
|
|
165
|
+
if (isMeta || host.model.mapping().keyTarget(event.key, host.model.value) !== void 0) this.#springBack();
|
|
166
166
|
}, { signal });
|
|
167
167
|
control.addEventListener("blur", () => {
|
|
168
168
|
this.#endKeyScrub();
|
|
@@ -172,13 +172,13 @@ var ValueGestures = class {
|
|
|
172
172
|
}
|
|
173
173
|
#commit(next, direction = 0) {
|
|
174
174
|
const host = this.#host;
|
|
175
|
-
const landed = Number.isFinite(next) ? host.land(next, direction) : next;
|
|
175
|
+
const landed = Number.isFinite(next) ? host.model.land(next, direction) : next;
|
|
176
176
|
if (host.input(landed)) host.dispatch("change");
|
|
177
177
|
}
|
|
178
178
|
#concealKeyReveal() {
|
|
179
179
|
if (!this.#claim.conceal("keys")) return;
|
|
180
180
|
this.#showRevealed();
|
|
181
|
-
this.#host.
|
|
181
|
+
this.#host.scrubChanged();
|
|
182
182
|
}
|
|
183
183
|
#crossCancelZone(drag, value) {
|
|
184
184
|
const host = this.#host;
|
|
@@ -196,7 +196,7 @@ var ValueGestures = class {
|
|
|
196
196
|
const host = this.#host;
|
|
197
197
|
const isOutside = drag.outside?.(event) === true;
|
|
198
198
|
const wasEngaged = drag.state.isEngaged;
|
|
199
|
-
const mapping = host.mapping();
|
|
199
|
+
const mapping = host.model.mapping();
|
|
200
200
|
const { state, value } = stepDrag(mapping, drag.state, {
|
|
201
201
|
isFine: event.shiftKey,
|
|
202
202
|
isOutside,
|
|
@@ -213,13 +213,13 @@ var ValueGestures = class {
|
|
|
213
213
|
const scrub = this.#keyScrub;
|
|
214
214
|
if (!scrub) return;
|
|
215
215
|
this.#keyScrub = void 0;
|
|
216
|
-
host.
|
|
217
|
-
if (host.value
|
|
216
|
+
host.scrubChanged();
|
|
217
|
+
if (host.model.value !== scrub.fromValue) host.dispatch("change");
|
|
218
218
|
}
|
|
219
219
|
#keyTarget(key) {
|
|
220
220
|
const host = this.#host;
|
|
221
221
|
if (resetKeys.has(key)) return host.default();
|
|
222
|
-
return host.mapping().keyTarget(key, host.value
|
|
222
|
+
return host.model.mapping().keyTarget(key, host.model.value, host.keyStep());
|
|
223
223
|
}
|
|
224
224
|
#keyTo(event, next) {
|
|
225
225
|
const host = this.#host;
|
|
@@ -228,7 +228,7 @@ var ValueGestures = class {
|
|
|
228
228
|
return;
|
|
229
229
|
}
|
|
230
230
|
this.#endKeyScrub();
|
|
231
|
-
this.#commit(next, next > host.value
|
|
231
|
+
this.#commit(next, next > host.model.value ? 1 : -1);
|
|
232
232
|
}
|
|
233
233
|
#lift(drag, event, entry) {
|
|
234
234
|
const host = this.#host;
|
|
@@ -248,16 +248,16 @@ var ValueGestures = class {
|
|
|
248
248
|
clearTimeout(drag.revealTimer);
|
|
249
249
|
this.#claim.conceal("drag");
|
|
250
250
|
host.toggleState("cancelling", false);
|
|
251
|
-
host.
|
|
251
|
+
host.scrubChanged();
|
|
252
252
|
this.#showRevealed();
|
|
253
|
-
if (host.value
|
|
253
|
+
if (host.model.value !== drag.fromValue) host.dispatch("change");
|
|
254
254
|
this.#springBack();
|
|
255
255
|
this.#pointerType = void 0;
|
|
256
256
|
}
|
|
257
257
|
#renderDragReveal(drag) {
|
|
258
258
|
if (drag.isRevealed && !drag.isOutside) this.#claim.reveal("drag");
|
|
259
259
|
else this.#claim.conceal("drag");
|
|
260
|
-
this.#host.
|
|
260
|
+
this.#host.scrubChanged();
|
|
261
261
|
this.#showRevealed();
|
|
262
262
|
}
|
|
263
263
|
#reset() {
|
|
@@ -273,7 +273,7 @@ var ValueGestures = class {
|
|
|
273
273
|
if (this.#keyScrub?.key !== key) {
|
|
274
274
|
this.#endKeyScrub();
|
|
275
275
|
this.#keyScrub = {
|
|
276
|
-
fromValue: host.value
|
|
276
|
+
fromValue: host.model.value,
|
|
277
277
|
key
|
|
278
278
|
};
|
|
279
279
|
}
|
|
@@ -290,14 +290,14 @@ var ValueGestures = class {
|
|
|
290
290
|
const host = this.#host;
|
|
291
291
|
const target = host.springTarget();
|
|
292
292
|
if (target === void 0) return;
|
|
293
|
-
if (host.mapping().snap(target) !== host.value
|
|
293
|
+
if (host.model.mapping().snap(target) !== host.model.value) host.toggleState("springing", true);
|
|
294
294
|
this.#commit(target);
|
|
295
295
|
}
|
|
296
296
|
#startDrag(axis, event) {
|
|
297
297
|
const host = this.#host;
|
|
298
|
-
const mapping = host.mapping();
|
|
298
|
+
const mapping = host.model.mapping();
|
|
299
299
|
const detent = host.detent();
|
|
300
|
-
const value = host.value
|
|
300
|
+
const value = host.model.value;
|
|
301
301
|
const start = {
|
|
302
302
|
from: value,
|
|
303
303
|
position: axis.position(event),
|
|
@@ -316,7 +316,7 @@ var ValueGestures = class {
|
|
|
316
316
|
});
|
|
317
317
|
}
|
|
318
318
|
#withinLimit(mapping, state) {
|
|
319
|
-
const limit = this.#host.limit();
|
|
319
|
+
const limit = this.#host.model.limit();
|
|
320
320
|
if (!limit || mapping.isWrapping) return state;
|
|
321
321
|
const [low, high] = limit;
|
|
322
322
|
return {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { SonicValueElement } from "./value-element.js";
|
|
2
2
|
import { bindSurface } from "../lib/canvas-surface.js";
|
|
3
|
-
import { bindFill } from "../lib/fill-watch.js";
|
|
4
3
|
|
|
5
4
|
//#region src/elements/wave-element.ts
|
|
6
5
|
function markerKey(marker) {
|
|
@@ -34,10 +33,9 @@ var SonicWaveElement = class extends SonicValueElement {
|
|
|
34
33
|
#current;
|
|
35
34
|
#markers = [];
|
|
36
35
|
#surface;
|
|
37
|
-
#syncFill;
|
|
38
36
|
attributeChangedCallback(name) {
|
|
39
37
|
super.attributeChangedCallback(name);
|
|
40
|
-
if (name === "fill") this.#
|
|
38
|
+
if (name === "fill") this.#surface?.setFill(this.fill);
|
|
41
39
|
}
|
|
42
40
|
connectedCallback() {
|
|
43
41
|
this.upgradeProperties("fill", "markers");
|
|
@@ -53,6 +51,10 @@ var SonicWaveElement = class extends SonicValueElement {
|
|
|
53
51
|
this.#surface = bindSurface({
|
|
54
52
|
canvas: this.canvas,
|
|
55
53
|
colours: this.colours,
|
|
54
|
+
fill: {
|
|
55
|
+
control,
|
|
56
|
+
sizeProperty: this.sizeProperty
|
|
57
|
+
},
|
|
56
58
|
lengths: this.lengths,
|
|
57
59
|
paint: (context, frame) => {
|
|
58
60
|
this.paint(context, frame);
|
|
@@ -71,19 +73,11 @@ var SonicWaveElement = class extends SonicValueElement {
|
|
|
71
73
|
"readout",
|
|
72
74
|
"value"
|
|
73
75
|
]);
|
|
74
|
-
this.#
|
|
75
|
-
this.#syncFill(this.fill);
|
|
76
|
+
this.#surface.setFill(this.fill);
|
|
76
77
|
}
|
|
77
78
|
focusTarget() {
|
|
78
79
|
return this.control;
|
|
79
80
|
}
|
|
80
|
-
heldWrite(next) {
|
|
81
|
-
super.heldWrite(next);
|
|
82
|
-
this.render();
|
|
83
|
-
}
|
|
84
|
-
holdChanged() {
|
|
85
|
-
this.render();
|
|
86
|
-
}
|
|
87
81
|
markerList() {
|
|
88
82
|
return this.#markers;
|
|
89
83
|
}
|
|
@@ -101,6 +95,9 @@ var SonicWaveElement = class extends SonicValueElement {
|
|
|
101
95
|
renderEmpty() {
|
|
102
96
|
this.toggleState("empty", this.isEmpty());
|
|
103
97
|
}
|
|
98
|
+
scrubChanged() {
|
|
99
|
+
this.render();
|
|
100
|
+
}
|
|
104
101
|
showCurrentMarker(seconds) {
|
|
105
102
|
const current = this.#markers.findLast((marker) => marker.start <= seconds);
|
|
106
103
|
if (markerKey(current) === markerKey(this.#current)) return;
|