@xsynaptic/sonic-ui 0.5.0 → 0.6.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/README.md +3 -1
- package/dist/default/dat.js +5 -4
- package/dist/default/define/button.js +1 -1
- package/dist/default/define.js +2 -2
- package/dist/default/elements/button.js +3 -3
- package/dist/default/elements/envelope.js +32 -16
- package/dist/default/elements/meter.js +11 -7
- package/dist/default/elements/number.js +1 -1
- package/dist/default/elements/radio-group.js +43 -45
- package/dist/default/elements/readout.js +1 -1
- package/dist/default/elements/sonic-element.js +56 -29
- package/dist/default/elements/switch.js +32 -38
- package/dist/default/elements/value-element.js +111 -108
- package/dist/default/elements/wave-element.js +5 -2
- package/dist/default/elements/waveform.js +35 -12
- package/dist/default/elements/wavestrip.js +18 -15
- package/dist/default/elements/xy.js +32 -18
- package/dist/default/index.js +2 -2
- package/dist/default/lib/adsr-shape.js +5 -0
- package/dist/default/lib/ballistics.js +2 -2
- package/dist/default/lib/canvas-surface.js +13 -2
- package/dist/default/lib/distribute.js +1 -1
- package/dist/default/lib/drag-step.js +4 -4
- package/dist/default/lib/frame-timeline.js +2 -1
- package/dist/default/lib/marker-band.js +54 -10
- package/dist/default/lib/marker-rider.js +10 -4
- package/dist/default/lib/math.js +6 -1
- package/dist/default/lib/pointer-drag.js +8 -5
- package/dist/default/lib/resample-peaks.js +11 -1
- package/dist/default/lib/write-attribute.js +1 -0
- package/dist/dev/dat.d.ts +2 -2
- package/dist/dev/dat.js +5 -4
- package/dist/dev/dat.js.map +1 -1
- package/dist/dev/define/button.js +1 -1
- package/dist/dev/define.d.ts +4 -4
- package/dist/dev/define.js +2 -2
- package/dist/dev/elements/button.js +3 -3
- package/dist/dev/elements/button.js.map +1 -1
- package/dist/dev/elements/dial.d.ts +1 -1
- package/dist/dev/elements/dial.js.map +1 -1
- package/dist/dev/elements/envelope.js +32 -16
- package/dist/dev/elements/envelope.js.map +1 -1
- package/dist/dev/elements/meter.d.ts +1 -1
- package/dist/dev/elements/meter.js +11 -7
- package/dist/dev/elements/meter.js.map +1 -1
- package/dist/dev/elements/number.js +1 -1
- package/dist/dev/elements/number.js.map +1 -1
- package/dist/dev/elements/radio-group.js +43 -45
- package/dist/dev/elements/radio-group.js.map +1 -1
- package/dist/dev/elements/readout.js +1 -1
- package/dist/dev/elements/readout.js.map +1 -1
- package/dist/dev/elements/slider.d.ts +1 -1
- package/dist/dev/elements/slider.js.map +1 -1
- package/dist/dev/elements/sonic-element.d.ts +4 -2
- package/dist/dev/elements/sonic-element.js +79 -29
- package/dist/dev/elements/sonic-element.js.map +1 -1
- package/dist/dev/elements/switch.js +32 -38
- package/dist/dev/elements/switch.js.map +1 -1
- package/dist/dev/elements/value-element.d.ts +3 -3
- package/dist/dev/elements/value-element.js +111 -108
- package/dist/dev/elements/value-element.js.map +1 -1
- package/dist/dev/elements/wave-element.d.ts +1 -0
- package/dist/dev/elements/wave-element.js +5 -2
- package/dist/dev/elements/wave-element.js.map +1 -1
- package/dist/dev/elements/waveform.d.ts +1 -1
- package/dist/dev/elements/waveform.js +35 -12
- package/dist/dev/elements/waveform.js.map +1 -1
- package/dist/dev/elements/wavestrip.js +18 -15
- package/dist/dev/elements/wavestrip.js.map +1 -1
- package/dist/dev/elements/xy.d.ts +3 -3
- package/dist/dev/elements/xy.js +32 -18
- package/dist/dev/elements/xy.js.map +1 -1
- package/dist/dev/index.d.ts +2 -2
- package/dist/dev/index.js +2 -2
- package/dist/dev/lib/adsr-shape.js +5 -0
- package/dist/dev/lib/adsr-shape.js.map +1 -1
- package/dist/dev/lib/ballistics.js +2 -2
- package/dist/dev/lib/ballistics.js.map +1 -1
- package/dist/dev/lib/canvas-surface.d.ts +1 -0
- package/dist/dev/lib/canvas-surface.js +13 -2
- package/dist/dev/lib/canvas-surface.js.map +1 -1
- package/dist/dev/lib/distribute.js +1 -1
- package/dist/dev/lib/distribute.js.map +1 -1
- package/dist/dev/lib/drag-step.js +4 -4
- package/dist/dev/lib/drag-step.js.map +1 -1
- package/dist/dev/lib/frame-timeline.js +2 -1
- package/dist/dev/lib/frame-timeline.js.map +1 -1
- package/dist/dev/lib/marker-band.js +54 -10
- package/dist/dev/lib/marker-band.js.map +1 -1
- package/dist/dev/lib/marker-rider.js +10 -4
- package/dist/dev/lib/marker-rider.js.map +1 -1
- package/dist/dev/lib/math.js +6 -1
- package/dist/dev/lib/math.js.map +1 -1
- package/dist/dev/lib/pointer-drag.js +8 -5
- package/dist/dev/lib/pointer-drag.js.map +1 -1
- package/dist/dev/lib/resample-peaks.js +11 -1
- package/dist/dev/lib/resample-peaks.js.map +1 -1
- package/dist/dev/lib/write-attribute.js +1 -0
- package/dist/dev/lib/write-attribute.js.map +1 -1
- package/dist/skins/amber.css +8 -0
- package/dist/skins/flat.css +25 -0
- package/dist/skins/ivory.css +1 -0
- package/dist/skins/lime.css +2 -0
- package/dist/skins/slate.css +2 -0
- package/dist/styles/button.css +38 -10
- package/dist/styles/dial.css +24 -16
- package/dist/styles/envelope.css +56 -11
- package/dist/styles/led.css +3 -3
- package/dist/styles/material.css +83 -41
- package/dist/styles/meter.css +8 -4
- package/dist/styles/panel.css +5 -3
- package/dist/styles/segmented.css +27 -5
- package/dist/styles/slider.css +2 -1
- package/dist/styles/switch.css +59 -20
- package/dist/styles/waveform.css +28 -5
- package/dist/styles/wavestrip.css +23 -6
- package/dist/styles/xy.css +61 -24
- package/package.json +2 -5
|
@@ -2,6 +2,7 @@ import { clamp } from "../lib/math.js";
|
|
|
2
2
|
import { requireChild, template } from "../lib/render.js";
|
|
3
3
|
import { writeAttribute } from "../lib/write-attribute.js";
|
|
4
4
|
import { bindHold } from "../lib/hold.js";
|
|
5
|
+
import { bindDrag } from "../lib/pointer-drag.js";
|
|
5
6
|
import { SonicRadioGroupElement, isUnder, optionValue } from "./radio-group.js";
|
|
6
7
|
|
|
7
8
|
//#region src/elements/switch.ts
|
|
@@ -60,7 +61,6 @@ var SonicSwitch = class extends SonicRadioGroupElement {
|
|
|
60
61
|
group = renderSwitch();
|
|
61
62
|
#bare = renderBare();
|
|
62
63
|
#bat = requireChild(this.group, ".sonic-switch-bat", HTMLSpanElement);
|
|
63
|
-
#batPress;
|
|
64
64
|
#checked = false;
|
|
65
65
|
#holding;
|
|
66
66
|
#isClickSwallowed = false;
|
|
@@ -92,7 +92,7 @@ var SonicSwitch = class extends SonicRadioGroupElement {
|
|
|
92
92
|
option.focus();
|
|
93
93
|
}
|
|
94
94
|
claimPress(option, event) {
|
|
95
|
-
if (this.#
|
|
95
|
+
if (this.#isOnBat(event)) return true;
|
|
96
96
|
if (!this.#isMomentary(option)) return false;
|
|
97
97
|
this.group.setPointerCapture(event.pointerId);
|
|
98
98
|
this.#hold(option, event.pointerId);
|
|
@@ -108,9 +108,8 @@ var SonicSwitch = class extends SonicRadioGroupElement {
|
|
|
108
108
|
this.#isClickSwallowed = false;
|
|
109
109
|
if (!isSwallowed) this.#setChecked(!this.checked);
|
|
110
110
|
}, { signal });
|
|
111
|
-
this.#bare.addEventListener("pointerdown", (
|
|
111
|
+
this.#bare.addEventListener("pointerdown", () => {
|
|
112
112
|
this.#isClickSwallowed = false;
|
|
113
|
-
if (event.button === 0 && !this.isDisabled()) this.#grabBat(event);
|
|
114
113
|
}, { signal });
|
|
115
114
|
this.#bindBat(group, signal);
|
|
116
115
|
this.#holding = bindHold(group, {
|
|
@@ -138,12 +137,13 @@ var SonicSwitch = class extends SonicRadioGroupElement {
|
|
|
138
137
|
return option;
|
|
139
138
|
}
|
|
140
139
|
render() {
|
|
140
|
+
if (!this.isBound()) return;
|
|
141
141
|
const group = this.group;
|
|
142
142
|
const options = this.options();
|
|
143
143
|
if (options.length > 0) {
|
|
144
144
|
this.#bare.remove();
|
|
145
145
|
writeAttribute(group, "role", "radiogroup");
|
|
146
|
-
group
|
|
146
|
+
writeAttribute(group, "data-sonic-position-count", String(options.length));
|
|
147
147
|
super.render();
|
|
148
148
|
this.#renderThrow(this.#checkedIndex(options));
|
|
149
149
|
return;
|
|
@@ -153,8 +153,8 @@ var SonicSwitch = class extends SonicRadioGroupElement {
|
|
|
153
153
|
writeAttribute(group, "role", void 0);
|
|
154
154
|
delete group.dataset.sonicPositionCount;
|
|
155
155
|
if (bare.parentElement !== group) group.append(bare);
|
|
156
|
-
bare
|
|
157
|
-
bare
|
|
156
|
+
writeAttribute(bare, "disabled", this.isDisabled() ? "" : void 0);
|
|
157
|
+
writeAttribute(bare, "aria-checked", String(isChecked));
|
|
158
158
|
this.forwardNaming(group, false);
|
|
159
159
|
this.forwardNaming(bare, true);
|
|
160
160
|
const onSide = this.orientation === "horizontal" ? 1 : -1;
|
|
@@ -172,41 +172,32 @@ var SonicSwitch = class extends SonicRadioGroupElement {
|
|
|
172
172
|
return this.orientation === "horizontal" ? event.clientX : event.clientY;
|
|
173
173
|
}
|
|
174
174
|
#bindBat(group, signal) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
press
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
175
|
+
bindDrag(group, {
|
|
176
|
+
grab: (event) => {
|
|
177
|
+
if (!(event.target === this.#bare || this.optionOf(event.target) !== void 0) || this.isDisabled() || !this.#isOnBat(event)) return;
|
|
178
|
+
return {
|
|
179
|
+
hasMoved: false,
|
|
180
|
+
last: this.#along(event),
|
|
181
|
+
width: this.#bat.getBoundingClientRect().width
|
|
182
|
+
};
|
|
183
|
+
},
|
|
184
|
+
lift: (press, event) => {
|
|
185
|
+
if (!press.hasMoved && !this.isDisabled()) this.#pressBat(event);
|
|
186
|
+
this.#isClickSwallowed = true;
|
|
187
|
+
},
|
|
188
|
+
move: (press, event) => {
|
|
189
|
+
if (this.isDisabled()) return;
|
|
190
|
+
const delta = this.#along(event) - press.last;
|
|
191
|
+
if (Math.abs(delta) < press.width / 4) return;
|
|
192
|
+
press.hasMoved = true;
|
|
193
|
+
press.last = this.#along(event);
|
|
194
|
+
this.#throwBy(Math.sign(delta), event.pointerId);
|
|
195
|
+
}
|
|
196
|
+
}, signal);
|
|
196
197
|
}
|
|
197
198
|
#checkedIndex(options) {
|
|
198
199
|
return options.findIndex((option) => optionValue(option) === this.value);
|
|
199
200
|
}
|
|
200
|
-
#grabBat(event) {
|
|
201
|
-
if (!isUnder(this.#bat, event.clientX, event.clientY)) return false;
|
|
202
|
-
this.group.setPointerCapture(event.pointerId);
|
|
203
|
-
this.#batPress = {
|
|
204
|
-
hasMoved: false,
|
|
205
|
-
last: this.#along(event),
|
|
206
|
-
pointerId: event.pointerId
|
|
207
|
-
};
|
|
208
|
-
return true;
|
|
209
|
-
}
|
|
210
201
|
#hasSprungFrom(option) {
|
|
211
202
|
if (!option || !this.#isMomentary(option)) return false;
|
|
212
203
|
this.#holding?.release();
|
|
@@ -222,6 +213,9 @@ var SonicSwitch = class extends SonicRadioGroupElement {
|
|
|
222
213
|
const options = this.options();
|
|
223
214
|
return (option === options[0] || option === options.at(-1)) && options.length > 1 && option.querySelector("[data-sonic-value]")?.hasAttribute("data-sonic-momentary") === true;
|
|
224
215
|
}
|
|
216
|
+
#isOnBat(event) {
|
|
217
|
+
return isUnder(this.#bat, event.clientX, event.clientY);
|
|
218
|
+
}
|
|
225
219
|
#pressBat(event) {
|
|
226
220
|
const options = this.options();
|
|
227
221
|
if (options.length === 0) {
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { clamp } from "../lib/math.js";
|
|
1
|
+
import { clamp, toNumber } from "../lib/math.js";
|
|
2
2
|
import { placeChildren, requireChild } from "../lib/render.js";
|
|
3
3
|
import { writeAttribute } from "../lib/write-attribute.js";
|
|
4
4
|
import { SonicFormElement } from "./form-element.js";
|
|
5
|
+
import { copyNode } from "../lib/copy-node.js";
|
|
5
6
|
import { ReadoutClaim } from "./readout-claim.js";
|
|
6
7
|
import { Readout } from "./readout.js";
|
|
7
8
|
import { ValueEntry } from "./value-entry.js";
|
|
8
|
-
import { copyNode } from "../lib/copy-node.js";
|
|
9
9
|
import { dragThresholdPx, startDrag, stepDrag } from "../lib/drag-step.js";
|
|
10
10
|
import { focusByPointer } from "../lib/focus-by-pointer.js";
|
|
11
11
|
import { isMenuPress, isResetPress } from "../lib/modifier-press.js";
|
|
12
12
|
import { parseNumberList } from "../lib/number-list.js";
|
|
13
|
+
import { bindDrag } from "../lib/pointer-drag.js";
|
|
13
14
|
import { readPxProperty } from "../lib/read-px-property.js";
|
|
14
15
|
import { readRegions } from "../lib/time-regions.js";
|
|
15
16
|
import { resetKeys, valueMapping } from "../lib/value-mapping.js";
|
|
@@ -203,53 +204,57 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
203
204
|
return this.#value;
|
|
204
205
|
}
|
|
205
206
|
set value(next) {
|
|
207
|
+
if (next === void 0 || next === null) {
|
|
208
|
+
this.formResetCallback();
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const value = toNumber(next);
|
|
206
212
|
if (this.#isHeld()) {
|
|
207
|
-
this.heldWrite(
|
|
213
|
+
this.heldWrite(value);
|
|
208
214
|
return;
|
|
209
215
|
}
|
|
210
|
-
this.#write(
|
|
216
|
+
this.#write(value);
|
|
217
|
+
if (Number.isFinite(value)) this.#asked = value;
|
|
211
218
|
}
|
|
212
219
|
get valueText() {
|
|
213
220
|
return this.#textFor(this.#value);
|
|
214
221
|
}
|
|
222
|
+
#asked;
|
|
215
223
|
#buffered = [];
|
|
216
224
|
#claim = new ReadoutClaim(() => {
|
|
217
225
|
this.#renderHold();
|
|
218
226
|
});
|
|
219
|
-
#drag;
|
|
220
227
|
#entry;
|
|
221
228
|
#escapeWatch;
|
|
222
229
|
#formatSpokenValue;
|
|
223
230
|
#formatValue;
|
|
224
231
|
#instance = String(instanceCount += 1);
|
|
225
|
-
#isDirty = false;
|
|
226
232
|
#isModulated = false;
|
|
227
233
|
#keyScrub;
|
|
228
234
|
#land;
|
|
229
235
|
#limit;
|
|
236
|
+
#mapping;
|
|
230
237
|
#modulationValue;
|
|
231
238
|
#parseValue;
|
|
239
|
+
#pointerDrag;
|
|
232
240
|
#positions;
|
|
233
241
|
#readout;
|
|
234
242
|
#scaleMarks;
|
|
235
243
|
#value = 0;
|
|
236
244
|
#watchers = /* @__PURE__ */ new Set();
|
|
237
245
|
attributeChangedCallback(name) {
|
|
246
|
+
this.#mapping = void 0;
|
|
238
247
|
this.#positions = parseNumberList(this.getAttribute("positions"));
|
|
239
248
|
if (name === "value") {
|
|
240
249
|
if (this.#isHeld()) {
|
|
241
250
|
this.heldWrite(this.numberAttribute("value", this.min));
|
|
242
251
|
return;
|
|
243
252
|
}
|
|
244
|
-
this.#
|
|
245
|
-
}
|
|
246
|
-
if (name === "disabled" && this.isDisabled()) {
|
|
247
|
-
this.#entry?.close(false);
|
|
248
|
-
this.#endDrag();
|
|
249
|
-
this.#endKeyScrub();
|
|
253
|
+
this.#asked = void 0;
|
|
250
254
|
}
|
|
251
|
-
|
|
252
|
-
|
|
255
|
+
if (name === "disabled" && this.isDisabled()) this.#endHolds();
|
|
256
|
+
this.#value = this.mapping().snap(this.#asked ?? this.numberAttribute("value", this.min));
|
|
257
|
+
if (proportionAttributes.has(name) && this.isBound()) this.proportionsChanged();
|
|
253
258
|
this.render();
|
|
254
259
|
}
|
|
255
260
|
connectedCallback() {
|
|
@@ -258,66 +263,61 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
258
263
|
}
|
|
259
264
|
bindGestures(control, signal, grab) {
|
|
260
265
|
const entry = this.#bindEntry(control, signal);
|
|
261
|
-
control
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
266
|
+
this.#pointerDrag = bindDrag(control, {
|
|
267
|
+
cancel: (drag) => {
|
|
268
|
+
if (drag.isKeptOnCancel !== true) this.input(drag.fromValue);
|
|
269
|
+
},
|
|
270
|
+
grab: (event) => {
|
|
271
|
+
if (isMenuPress(event) || this.isDisabled() || entry.isOpen) return;
|
|
272
|
+
this.toggleState("springing", false);
|
|
273
|
+
if (event.pointerType === "touch") event.preventDefault();
|
|
274
|
+
focusByPointer(control);
|
|
275
|
+
if (isResetPress(event)) {
|
|
276
|
+
this.#reset();
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const fromValue = this.#value;
|
|
280
|
+
const axis = grab(event);
|
|
281
|
+
if (!axis) return;
|
|
282
|
+
const drag = {
|
|
283
|
+
...axis,
|
|
284
|
+
fromValue,
|
|
285
|
+
isOutside: false,
|
|
286
|
+
isRevealed: false,
|
|
287
|
+
revealTimer: void 0,
|
|
288
|
+
state: this.#startDrag(control, axis, event)
|
|
289
|
+
};
|
|
290
|
+
drag.revealTimer = setTimeout(() => {
|
|
291
|
+
this.#reveal(drag);
|
|
292
|
+
}, 250);
|
|
293
|
+
return drag;
|
|
294
|
+
},
|
|
295
|
+
lift: (drag, event) => {
|
|
296
|
+
const tap = drag.state.isEngaged ? void 0 : this.tapTarget();
|
|
297
|
+
if (tap !== void 0) {
|
|
298
|
+
entry.forgetPress();
|
|
299
|
+
this.#commit(tap);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (!entry.press(event) || this.springTarget() !== void 0) return;
|
|
303
|
+
if (this.doublePress === "reset") this.#reset();
|
|
304
|
+
else entry.open();
|
|
305
|
+
},
|
|
306
|
+
move: (drag, event) => {
|
|
307
|
+
this.#dragTo(drag, event);
|
|
308
|
+
},
|
|
309
|
+
release: (drag) => {
|
|
310
|
+
this.#releaseDrag(drag);
|
|
311
|
+
},
|
|
312
|
+
toggle: (isDragging) => {
|
|
313
|
+
this.toggleState("dragging", isDragging);
|
|
270
314
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
if (!axis) return;
|
|
274
|
-
const drag = {
|
|
275
|
-
...axis,
|
|
276
|
-
fromValue,
|
|
277
|
-
isOutside: false,
|
|
278
|
-
isRevealed: false,
|
|
279
|
-
pointerId: event.pointerId,
|
|
280
|
-
revealTimer: void 0,
|
|
281
|
-
state: this.#startDrag(control, axis, event)
|
|
282
|
-
};
|
|
283
|
-
drag.revealTimer = setTimeout(() => {
|
|
284
|
-
this.#reveal(drag);
|
|
285
|
-
}, 250);
|
|
286
|
-
this.#drag = drag;
|
|
287
|
-
control.setPointerCapture(event.pointerId);
|
|
288
|
-
this.toggleState("dragging", true);
|
|
289
|
-
}, { signal });
|
|
290
|
-
control.addEventListener("pointermove", (event) => {
|
|
291
|
-
const drag = this.#drag;
|
|
292
|
-
if (event.pointerId === drag?.pointerId) this.#dragTo(drag, event);
|
|
293
|
-
}, { signal });
|
|
294
|
-
const endDrag = (event) => {
|
|
295
|
-
if (event.pointerId === this.#drag?.pointerId) this.#endDrag();
|
|
296
|
-
};
|
|
297
|
-
control.addEventListener("pointercancel", (event) => {
|
|
298
|
-
const drag = this.#drag;
|
|
299
|
-
if (event.pointerId === drag?.pointerId && drag.isKeptOnCancel !== true) this.input(drag.fromValue);
|
|
300
|
-
endDrag(event);
|
|
315
|
+
}, signal);
|
|
316
|
+
control.addEventListener("pointercancel", () => {
|
|
301
317
|
entry.forgetPress();
|
|
302
318
|
}, { signal });
|
|
303
|
-
control.addEventListener("lostpointercapture", endDrag, { signal });
|
|
304
|
-
control.addEventListener("pointerup", (event) => {
|
|
305
|
-
const drag = this.#drag;
|
|
306
|
-
if (event.pointerId !== drag?.pointerId) return;
|
|
307
|
-
this.#endDrag();
|
|
308
|
-
const tap = drag.state.isEngaged ? void 0 : this.tapTarget();
|
|
309
|
-
if (tap !== void 0) {
|
|
310
|
-
entry.forgetPress();
|
|
311
|
-
this.#commit(tap);
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
if (!entry.press(event) || this.springTarget() !== void 0) return;
|
|
315
|
-
if (this.doublePress === "reset") this.#reset();
|
|
316
|
-
else entry.open();
|
|
317
|
-
}, { signal });
|
|
318
319
|
this.#bindKeys(control, entry, signal);
|
|
319
320
|
signal.addEventListener("abort", () => {
|
|
320
|
-
this.#endDrag();
|
|
321
321
|
this.#endKeyScrub();
|
|
322
322
|
this.#concealKeyReveal();
|
|
323
323
|
}, { once: true });
|
|
@@ -328,6 +328,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
328
328
|
control,
|
|
329
329
|
copy: scaleMark,
|
|
330
330
|
isCopied: (child) => child instanceof Element && child.matches("[data-sonic-value]"),
|
|
331
|
+
isPassed: (child) => child instanceof Element && child.matches(".sonic-led"),
|
|
331
332
|
place: (copies) => {
|
|
332
333
|
placeChildren(marks, copies);
|
|
333
334
|
this.#renderScale();
|
|
@@ -339,7 +340,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
339
340
|
return "slider";
|
|
340
341
|
}
|
|
341
342
|
heldFrom() {
|
|
342
|
-
return this.#
|
|
343
|
+
return this.#dragging()?.fromValue ?? this.#keyScrub?.fromValue;
|
|
343
344
|
}
|
|
344
345
|
heldWrite(_next) {}
|
|
345
346
|
holdChanged() {}
|
|
@@ -365,8 +366,9 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
365
366
|
return false;
|
|
366
367
|
}
|
|
367
368
|
mapping() {
|
|
369
|
+
if (this.#mapping) return this.#mapping;
|
|
368
370
|
const { detent, midpoint } = this;
|
|
369
|
-
|
|
371
|
+
this.#mapping = valueMapping({
|
|
370
372
|
...detent === void 0 ? {} : { detent },
|
|
371
373
|
...this.#positions ? { positions: this.#positions } : {},
|
|
372
374
|
max: this.max,
|
|
@@ -377,6 +379,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
377
379
|
step: this.step,
|
|
378
380
|
taper: this.taper
|
|
379
381
|
});
|
|
382
|
+
return this.#mapping;
|
|
380
383
|
}
|
|
381
384
|
originValue() {
|
|
382
385
|
return this.origin ?? this.mapping().bounds[0];
|
|
@@ -389,10 +392,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
389
392
|
return this.#claim.shown(this.#value, this.readout).value ?? this.#value;
|
|
390
393
|
}
|
|
391
394
|
render() {
|
|
392
|
-
this.
|
|
393
|
-
this.#renderScale();
|
|
394
|
-
this.toggleState("at-origin", !this.isWrapping() && this.#value === this.mapping().snap(this.originValue()));
|
|
395
|
-
this.#renderAria(this.focusTarget(), this.controlOrientation());
|
|
395
|
+
if (this.isBound()) this.#renderControl();
|
|
396
396
|
for (const listener of this.#watchers) listener();
|
|
397
397
|
}
|
|
398
398
|
restoreState(state) {
|
|
@@ -407,9 +407,10 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
407
407
|
return Math.max(1, readPxProperty(getComputedStyle(control), property, fallbackTravelPx));
|
|
408
408
|
}
|
|
409
409
|
writeModulationValue(control, prefix, next) {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
this.#
|
|
410
|
+
const value = next === void 0 || next === null ? void 0 : toNumber(next);
|
|
411
|
+
if (value !== void 0 && !Number.isFinite(value)) return;
|
|
412
|
+
this.#modulationValue = value;
|
|
413
|
+
if (this.isBound()) this.#writeModulationProportion(control, prefix);
|
|
413
414
|
}
|
|
414
415
|
writeProportions(control, prefix, modulation) {
|
|
415
416
|
const { style } = control;
|
|
@@ -469,7 +470,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
469
470
|
control.addEventListener("keyup", (event) => {
|
|
470
471
|
const isMeta = event.key === "Meta";
|
|
471
472
|
if (isMeta || event.key === this.#keyScrub?.key) this.#endKeyScrub();
|
|
472
|
-
if (isMeta && this.#
|
|
473
|
+
if (isMeta && this.#dragging()) return;
|
|
473
474
|
if (isMeta || this.mapping().keyTarget(event.key, this.#value) !== void 0) this.#springBack();
|
|
474
475
|
}, { signal });
|
|
475
476
|
control.addEventListener("blur", () => {
|
|
@@ -478,10 +479,6 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
478
479
|
this.#springBack();
|
|
479
480
|
}, { signal });
|
|
480
481
|
}
|
|
481
|
-
#canPress(event, entry) {
|
|
482
|
-
if (event.button !== 0 || isMenuPress(event) || this.isDisabled() || entry.isOpen) return false;
|
|
483
|
-
return !this.#drag || this.#drag.pointerId === event.pointerId;
|
|
484
|
-
}
|
|
485
482
|
#commit(next, direction = 0) {
|
|
486
483
|
const landed = Number.isFinite(next) ? this.#land?.(next, direction) ?? next : next;
|
|
487
484
|
if (this.input(landed)) this.dispatchEvent(new Event("change", { bubbles: true }));
|
|
@@ -489,6 +486,9 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
489
486
|
#concealKeyReveal() {
|
|
490
487
|
if (this.#claim.conceal("keys")) this.#renderHold();
|
|
491
488
|
}
|
|
489
|
+
#dragging() {
|
|
490
|
+
return this.#pointerDrag?.current();
|
|
491
|
+
}
|
|
492
492
|
#dragTo(drag, event) {
|
|
493
493
|
const isOutside = drag.outside?.(event) === true;
|
|
494
494
|
const wasEngaged = drag.state.isEngaged;
|
|
@@ -506,16 +506,10 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
506
506
|
drag.isOutside = isOutside;
|
|
507
507
|
this.#renderDragReveal(drag);
|
|
508
508
|
}
|
|
509
|
-
#
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
this.#drag = void 0;
|
|
514
|
-
this.toggleState("dragging", false);
|
|
515
|
-
this.#claim.conceal("drag");
|
|
516
|
-
this.#renderHold();
|
|
517
|
-
if (this.#value !== drag.fromValue) this.dispatchEvent(new Event("change", { bubbles: true }));
|
|
518
|
-
this.#springBack();
|
|
509
|
+
#endHolds() {
|
|
510
|
+
this.#entry?.close(false);
|
|
511
|
+
this.#pointerDrag?.end();
|
|
512
|
+
this.#endKeyScrub();
|
|
519
513
|
}
|
|
520
514
|
#endKeyScrub() {
|
|
521
515
|
const scrub = this.#keyScrub;
|
|
@@ -525,7 +519,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
525
519
|
if (this.#value !== scrub.fromValue) this.dispatchEvent(new Event("change", { bubbles: true }));
|
|
526
520
|
}
|
|
527
521
|
#isHeld() {
|
|
528
|
-
return this.#
|
|
522
|
+
return this.#dragging() !== void 0 || this.#keyScrub !== void 0;
|
|
529
523
|
}
|
|
530
524
|
#keyTarget(key) {
|
|
531
525
|
if (resetKeys.has(key)) return this.default;
|
|
@@ -539,6 +533,13 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
539
533
|
this.#endKeyScrub();
|
|
540
534
|
this.#commit(next, next > this.#value ? 1 : -1);
|
|
541
535
|
}
|
|
536
|
+
#releaseDrag(drag) {
|
|
537
|
+
clearTimeout(drag.revealTimer);
|
|
538
|
+
this.#claim.conceal("drag");
|
|
539
|
+
this.#renderHold();
|
|
540
|
+
if (this.#value !== drag.fromValue) this.dispatchEvent(new Event("change", { bubbles: true }));
|
|
541
|
+
this.#springBack();
|
|
542
|
+
}
|
|
542
543
|
#renderAria(control, orientation) {
|
|
543
544
|
this.writeFormValue(String(this.#value), String(this.#value));
|
|
544
545
|
if (this.#entry?.isOpen) {
|
|
@@ -548,24 +549,26 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
548
549
|
return;
|
|
549
550
|
}
|
|
550
551
|
const [low, high] = this.mapping().bounds;
|
|
551
|
-
control
|
|
552
|
-
control
|
|
553
|
-
control
|
|
554
|
-
control
|
|
555
|
-
if (orientation) control
|
|
552
|
+
writeAttribute(control, "role", this.controlRole());
|
|
553
|
+
writeAttribute(control, "aria-valuemin", String(low));
|
|
554
|
+
writeAttribute(control, "aria-valuemax", String(high));
|
|
555
|
+
writeAttribute(control, "aria-valuenow", String(this.#value));
|
|
556
|
+
if (orientation) writeAttribute(control, "aria-orientation", orientation);
|
|
556
557
|
writeAttribute(control, "aria-valuetext", (this.#formatSpokenValue ?? this.#formatValue)?.(this.#value));
|
|
557
558
|
this.forwardNaming(control, true);
|
|
558
559
|
this.#renderDisabled(control);
|
|
559
560
|
this.#renderReadout();
|
|
560
561
|
}
|
|
562
|
+
#renderControl() {
|
|
563
|
+
this.draw();
|
|
564
|
+
this.#renderScale();
|
|
565
|
+
this.toggleState("at-origin", !this.isWrapping() && this.#value === this.mapping().snap(this.originValue()));
|
|
566
|
+
this.#renderAria(this.focusTarget(), this.controlOrientation());
|
|
567
|
+
}
|
|
561
568
|
#renderDisabled(control) {
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
return;
|
|
566
|
-
}
|
|
567
|
-
control.removeAttribute("aria-disabled");
|
|
568
|
-
control.setAttribute("tabindex", "0");
|
|
569
|
+
const isDisabled = this.isDisabled();
|
|
570
|
+
writeAttribute(control, "aria-disabled", isDisabled ? "true" : void 0);
|
|
571
|
+
writeAttribute(control, "tabindex", isDisabled ? void 0 : "0");
|
|
569
572
|
}
|
|
570
573
|
#renderDragReveal(drag) {
|
|
571
574
|
if (drag.isRevealed && !drag.isOutside) this.#claim.reveal("drag");
|
|
@@ -599,7 +602,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
599
602
|
this.#commit(this.default ?? NaN);
|
|
600
603
|
}
|
|
601
604
|
#reveal(drag) {
|
|
602
|
-
if (drag.isRevealed || this.#
|
|
605
|
+
if (drag.isRevealed || this.#dragging() !== drag) return;
|
|
603
606
|
drag.isRevealed = true;
|
|
604
607
|
this.#renderDragReveal(drag);
|
|
605
608
|
}
|
|
@@ -666,8 +669,8 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
666
669
|
}
|
|
667
670
|
#write(next) {
|
|
668
671
|
if (!Number.isFinite(next)) return;
|
|
669
|
-
this.#isDirty = true;
|
|
670
672
|
const clamped = this.mapping().snap(next);
|
|
673
|
+
this.#asked = clamped;
|
|
671
674
|
if (clamped === this.#value) return;
|
|
672
675
|
this.#value = clamped;
|
|
673
676
|
this.render();
|
|
@@ -8,7 +8,7 @@ var SonicWaveElement = class extends SonicValueElement {
|
|
|
8
8
|
}
|
|
9
9
|
set markers(list) {
|
|
10
10
|
this.#markers = [...list ?? []].filter((marker) => Number.isFinite(marker.start)).map((marker) => ({ ...marker })).toSorted((first, second) => first.start - second.start);
|
|
11
|
-
this.renderMarkers();
|
|
11
|
+
if (this.isBound()) this.renderMarkers();
|
|
12
12
|
}
|
|
13
13
|
#heldAt;
|
|
14
14
|
#markers = [];
|
|
@@ -22,7 +22,7 @@ var SonicWaveElement = class extends SonicValueElement {
|
|
|
22
22
|
}
|
|
23
23
|
connect(signal) {
|
|
24
24
|
const control = this.control;
|
|
25
|
-
this.
|
|
25
|
+
this.keepControl(control, signal);
|
|
26
26
|
this.renderEmpty();
|
|
27
27
|
this.#surface = bindSurface({
|
|
28
28
|
canvas: this.canvas,
|
|
@@ -50,6 +50,9 @@ var SonicWaveElement = class extends SonicValueElement {
|
|
|
50
50
|
if (this.heldFrom() === void 0) this.#heldAt = void 0;
|
|
51
51
|
this.render();
|
|
52
52
|
}
|
|
53
|
+
markerList() {
|
|
54
|
+
return this.#markers;
|
|
55
|
+
}
|
|
53
56
|
markerProportions() {
|
|
54
57
|
const mapping = this.mapping();
|
|
55
58
|
return this.#markers.map(({ end, start }) => {
|
|
@@ -3,6 +3,7 @@ import { requireChild, template } from "../lib/render.js";
|
|
|
3
3
|
import { readRegions } from "../lib/time-regions.js";
|
|
4
4
|
import { SonicWaveElement } from "./wave-element.js";
|
|
5
5
|
import { frameTimeline } from "../lib/frame-timeline.js";
|
|
6
|
+
import { isKind, writeKind } from "../lib/marker-band.js";
|
|
6
7
|
import { createLabelRider } from "../lib/marker-rider.js";
|
|
7
8
|
import { createTrackingClock } from "../lib/tracking-clock.js";
|
|
8
9
|
import { waveformBuckets } from "../lib/waveform-buckets.js";
|
|
@@ -172,6 +173,7 @@ var SonicWaveform = class extends SonicWaveElement {
|
|
|
172
173
|
#drawn;
|
|
173
174
|
#ghost = requireChild(this.control, ".sonic-waveform-ghost", HTMLDivElement);
|
|
174
175
|
#grabbed;
|
|
176
|
+
#kindColours = /* @__PURE__ */ new Map();
|
|
175
177
|
#paintedKey = "";
|
|
176
178
|
#peaks;
|
|
177
179
|
#pending = [];
|
|
@@ -180,6 +182,7 @@ var SonicWaveform = class extends SonicWaveElement {
|
|
|
180
182
|
#requestPeaks;
|
|
181
183
|
#rider = createLabelRider(this.control, {
|
|
182
184
|
className: "sonic-waveform-label",
|
|
185
|
+
colourProperty: "--_sonic-waveform-marker",
|
|
183
186
|
insetProperty: "--_sonic-waveform-label-inset"
|
|
184
187
|
});
|
|
185
188
|
connectedCallback() {
|
|
@@ -199,7 +202,7 @@ var SonicWaveform = class extends SonicWaveElement {
|
|
|
199
202
|
isEmpty() {
|
|
200
203
|
return !this.#peaks || this.#peaks.samples.length === 0;
|
|
201
204
|
}
|
|
202
|
-
paint(context, { frameMs, isDirty, look, size }) {
|
|
205
|
+
paint(context, { frameMs, isDirty, isRebuilt, look, size }) {
|
|
203
206
|
const held = this.#held();
|
|
204
207
|
const timeline = frameTimeline({
|
|
205
208
|
clockSeconds: this.#clock.read(frameMs, {
|
|
@@ -235,19 +238,20 @@ var SonicWaveform = class extends SonicWaveElement {
|
|
|
235
238
|
this.#paintScene(context, {
|
|
236
239
|
...view,
|
|
237
240
|
colours: look.colours
|
|
238
|
-
});
|
|
241
|
+
}, isRebuilt);
|
|
239
242
|
if (timeline.wanted) this.#requestPeaks?.(...timeline.wanted);
|
|
240
243
|
}
|
|
241
244
|
if (timeline.isMoving) this.surface()?.requestFrame();
|
|
242
245
|
}
|
|
243
246
|
renderMarkers() {
|
|
244
247
|
const bounds = this.mapping().bounds;
|
|
245
|
-
this.#rider.measure(this.markers.flatMap(({ dimmed, label, start }) => label === void 0 || label === "" ? [] : [{
|
|
248
|
+
this.#rider.measure(this.markers.flatMap(({ dimmed, kind, label, start }) => label === void 0 || label === "" ? [] : [{
|
|
246
249
|
isDimmed: dimmed === true,
|
|
250
|
+
...kind === void 0 ? {} : { kind },
|
|
247
251
|
start: clamp(start, ...bounds),
|
|
248
252
|
text: label
|
|
249
253
|
}]));
|
|
250
|
-
this.surface()?.
|
|
254
|
+
this.surface()?.rebuild();
|
|
251
255
|
}
|
|
252
256
|
#grab() {
|
|
253
257
|
const drawn = this.#drawn ?? {
|
|
@@ -273,10 +277,21 @@ var SonicWaveform = class extends SonicWaveElement {
|
|
|
273
277
|
seconds: this.value === from ? grabbed.seconds : this.value
|
|
274
278
|
};
|
|
275
279
|
}
|
|
276
|
-
#
|
|
280
|
+
#paintMarkers(context, scene, isRebuilt) {
|
|
281
|
+
if (isRebuilt) this.#kindColours = this.#readKindColours();
|
|
282
|
+
const line = Math.max(1, Math.round(scene.dpr));
|
|
283
|
+
for (const { dimmed, kind, start } of this.markers) {
|
|
284
|
+
const x = (start - scene.startSeconds) * scene.pixelsPerSecond;
|
|
285
|
+
context.fillStyle = (isKind(kind) ? this.#kindColours.get(kind) : void 0) ?? scene.colours.marker;
|
|
286
|
+
context.globalAlpha = dimmed === true ? .5 : 1;
|
|
287
|
+
context.fillRect(x - line / 2, 0, line, scene.height);
|
|
288
|
+
}
|
|
289
|
+
context.globalAlpha = 1;
|
|
290
|
+
}
|
|
291
|
+
#paintScene(context, scene, isRebuilt) {
|
|
277
292
|
const { dpr, height, pixelsPerSecond, startSeconds, width } = scene;
|
|
278
293
|
const x = (seconds) => (seconds - startSeconds) * pixelsPerSecond;
|
|
279
|
-
const { grid
|
|
294
|
+
const { grid } = scene.colours;
|
|
280
295
|
const line = Math.max(1, Math.round(dpr));
|
|
281
296
|
const [opening, closing] = [x(this.min), x(Math.max(this.min, this.max))];
|
|
282
297
|
const [from, to] = [clamp(opening, 0, width), clamp(closing, 0, width)];
|
|
@@ -289,12 +304,20 @@ var SonicWaveform = class extends SonicWaveElement {
|
|
|
289
304
|
if (this.#peaks) paintWave(context, scene, this.#peaks);
|
|
290
305
|
context.fillStyle = grid;
|
|
291
306
|
for (const edge of [opening, closing]) context.fillRect(edge - line / 2, 0, line, height);
|
|
292
|
-
context
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
307
|
+
this.#paintMarkers(context, scene, isRebuilt);
|
|
308
|
+
}
|
|
309
|
+
#readKindColours() {
|
|
310
|
+
const kinds = [...new Set(this.markers.map(({ kind }) => kind).filter((kind) => isKind(kind)))];
|
|
311
|
+
const probes = kinds.map((kind) => {
|
|
312
|
+
const probe = document.createElement("div");
|
|
313
|
+
probe.className = "sonic-waveform-label";
|
|
314
|
+
writeKind(probe, kind, "--_sonic-waveform-marker");
|
|
315
|
+
return probe;
|
|
316
|
+
});
|
|
317
|
+
this.control.append(...probes);
|
|
318
|
+
const read = probes.map((probe) => getComputedStyle(probe).color);
|
|
319
|
+
for (const probe of probes) probe.remove();
|
|
320
|
+
return new Map(kinds.map((kind, index) => [kind, read[index] ?? ""]));
|
|
298
321
|
}
|
|
299
322
|
#sourceSeconds() {
|
|
300
323
|
return this.#readTime?.() ?? this.playback();
|