@xsynaptic/sonic-ui 0.6.0 → 0.8.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 +4 -0
- package/dist/default/define/spectrum.js +7 -0
- package/dist/default/define.js +1 -0
- package/dist/default/elements/button.js +33 -4
- package/dist/default/elements/dial.js +5 -1
- package/dist/default/elements/display-element.js +77 -0
- package/dist/default/elements/envelope.js +15 -3
- package/dist/default/elements/meter.js +1 -1
- package/dist/default/elements/radio-group.js +3 -2
- package/dist/default/elements/readout-claim.js +0 -29
- package/dist/default/elements/scale.js +43 -0
- package/dist/default/elements/slider.js +82 -3
- package/dist/default/elements/sonic-element.js +2 -67
- package/dist/default/elements/spectrum.js +230 -0
- package/dist/default/elements/switch.js +1 -1
- package/dist/default/elements/value-element.js +81 -91
- package/dist/default/elements/wave-element.js +59 -9
- package/dist/default/elements/waveform.js +56 -10
- package/dist/default/elements/wavestrip.js +45 -21
- package/dist/default/elements/xy.js +3 -2
- package/dist/default/index.js +2 -1
- package/dist/default/lib/canvas-surface.js +7 -4
- package/dist/default/lib/frame-timeline.js +2 -2
- package/dist/default/lib/hover-preview.js +46 -0
- package/dist/default/lib/marker-rider.js +7 -4
- package/dist/default/lib/mirror-children.js +64 -0
- package/dist/default/lib/owned-control.js +10 -0
- package/dist/default/lib/pointer-drag.js +7 -2
- package/dist/default/lib/spectrum-columns.js +74 -0
- package/dist/default/lib/spectrum-levels.js +55 -0
- package/dist/default/lib/strip-scene.js +12 -1
- package/dist/default/lib/time-regions.js +8 -1
- package/dist/dev/define/spectrum.d.ts +2 -0
- package/dist/dev/define/spectrum.js +8 -0
- package/dist/dev/define/spectrum.js.map +1 -0
- package/dist/dev/define.d.ts +3 -1
- package/dist/dev/define.js +1 -0
- package/dist/dev/elements/button.d.ts +2 -0
- package/dist/dev/elements/button.js +33 -4
- package/dist/dev/elements/button.js.map +1 -1
- package/dist/dev/elements/dial.js +5 -1
- package/dist/dev/elements/dial.js.map +1 -1
- package/dist/dev/elements/display-element.d.ts +29 -0
- package/dist/dev/elements/display-element.js +78 -0
- package/dist/dev/elements/display-element.js.map +1 -0
- package/dist/dev/elements/envelope.js +15 -3
- package/dist/dev/elements/envelope.js.map +1 -1
- package/dist/dev/elements/meter.js +1 -1
- package/dist/dev/elements/radio-group.js +3 -2
- package/dist/dev/elements/radio-group.js.map +1 -1
- package/dist/dev/elements/readout-claim.js +0 -29
- package/dist/dev/elements/readout-claim.js.map +1 -1
- package/dist/dev/elements/scale.js +44 -0
- package/dist/dev/elements/scale.js.map +1 -0
- package/dist/dev/elements/slider.d.ts +9 -0
- package/dist/dev/elements/slider.js +82 -3
- package/dist/dev/elements/slider.js.map +1 -1
- package/dist/dev/elements/sonic-element.d.ts +0 -8
- package/dist/dev/elements/sonic-element.js +3 -90
- package/dist/dev/elements/sonic-element.js.map +1 -1
- package/dist/dev/elements/spectrum.d.ts +59 -0
- package/dist/dev/elements/spectrum.js +231 -0
- package/dist/dev/elements/spectrum.js.map +1 -0
- package/dist/dev/elements/switch.js +1 -1
- package/dist/dev/elements/value-element.d.ts +8 -6
- package/dist/dev/elements/value-element.js +81 -91
- package/dist/dev/elements/value-element.js.map +1 -1
- package/dist/dev/elements/wave-element.d.ts +8 -2
- package/dist/dev/elements/wave-element.js +59 -9
- package/dist/dev/elements/wave-element.js.map +1 -1
- package/dist/dev/elements/waveform.d.ts +12 -4
- package/dist/dev/elements/waveform.js +56 -10
- package/dist/dev/elements/waveform.js.map +1 -1
- package/dist/dev/elements/wavestrip.d.ts +7 -0
- package/dist/dev/elements/wavestrip.js +45 -21
- package/dist/dev/elements/wavestrip.js.map +1 -1
- package/dist/dev/elements/xy.js +3 -2
- package/dist/dev/elements/xy.js.map +1 -1
- package/dist/dev/index.d.ts +4 -1
- package/dist/dev/index.js +2 -1
- package/dist/dev/lib/canvas-surface.d.ts +4 -3
- package/dist/dev/lib/canvas-surface.js +7 -4
- package/dist/dev/lib/canvas-surface.js.map +1 -1
- package/dist/dev/lib/frame-timeline.js +2 -2
- package/dist/dev/lib/frame-timeline.js.map +1 -1
- package/dist/dev/lib/hover-preview.js +47 -0
- package/dist/dev/lib/hover-preview.js.map +1 -0
- package/dist/dev/lib/marker-rider.js +7 -4
- package/dist/dev/lib/marker-rider.js.map +1 -1
- package/dist/dev/lib/mirror-children.js +80 -0
- package/dist/dev/lib/mirror-children.js.map +1 -0
- package/dist/dev/lib/owned-control.js +23 -0
- package/dist/dev/lib/owned-control.js.map +1 -0
- package/dist/dev/lib/pointer-drag.js +7 -2
- package/dist/dev/lib/pointer-drag.js.map +1 -1
- package/dist/dev/lib/spectrum-columns.js +75 -0
- package/dist/dev/lib/spectrum-columns.js.map +1 -0
- package/dist/dev/lib/spectrum-levels.js +56 -0
- package/dist/dev/lib/spectrum-levels.js.map +1 -0
- package/dist/dev/lib/strip-scene.js +12 -1
- package/dist/dev/lib/strip-scene.js.map +1 -1
- package/dist/dev/lib/time-regions.js +8 -1
- package/dist/dev/lib/time-regions.js.map +1 -1
- package/dist/skins/flat.css +2 -1
- package/dist/styles/button.css +28 -1
- package/dist/styles/controls.css +1 -0
- package/dist/styles/envelope.css +30 -30
- package/dist/styles/led.css +18 -2
- package/dist/styles/material.css +90 -29
- package/dist/styles/meter.css +22 -18
- package/dist/styles/panel.css +2 -1
- package/dist/styles/slider.css +42 -5
- package/dist/styles/spectrum.css +105 -0
- package/dist/styles/switch.css +10 -7
- package/dist/styles/waveform.css +38 -16
- package/dist/styles/wavestrip.css +22 -4
- package/dist/styles/xy.css +14 -30
- package/package.json +2 -1
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { requireChild, template } from "../lib/render.js";
|
|
2
|
+
import { SonicDisplayElement } from "./display-element.js";
|
|
3
|
+
import { columnEdges, columnLevels, gridColumns, gridRows, levelRows, loudestBin, zoneRows } from "../lib/spectrum-columns.js";
|
|
4
|
+
import { areSettled, createLevels, receiveLevels, stepLevels } from "../lib/spectrum-levels.js";
|
|
5
|
+
|
|
6
|
+
//#region src/elements/spectrum.ts
|
|
7
|
+
const colours = {
|
|
8
|
+
clip: "--_sonic-spectrum-clip",
|
|
9
|
+
grid: "--_sonic-spectrum-grid",
|
|
10
|
+
hot: "--_sonic-spectrum-hot",
|
|
11
|
+
lit: "--_sonic-spectrum-lit"
|
|
12
|
+
};
|
|
13
|
+
const numbers = {
|
|
14
|
+
clipFrom: "--_sonic-spectrum-clip-from",
|
|
15
|
+
hotFrom: "--_sonic-spectrum-hot-from"
|
|
16
|
+
};
|
|
17
|
+
const defaultFrequencies = [20, 2e4];
|
|
18
|
+
const defaultSampleRate = 48e3;
|
|
19
|
+
const renderSpectrum = template(`
|
|
20
|
+
<div aria-hidden="true" class="sonic-spectrum">
|
|
21
|
+
<canvas class="sonic-spectrum-canvas"></canvas>
|
|
22
|
+
</div>
|
|
23
|
+
`, HTMLDivElement);
|
|
24
|
+
function paintGrid(context, { dpr, height, look, range, rowOf, width }, [frequencyMin, frequencyMax]) {
|
|
25
|
+
const line = Math.max(1, Math.round(dpr));
|
|
26
|
+
const columns = gridColumns({
|
|
27
|
+
frequencyMax,
|
|
28
|
+
frequencyMin
|
|
29
|
+
}, width);
|
|
30
|
+
const rows = gridRows(range, rowOf);
|
|
31
|
+
context.beginPath();
|
|
32
|
+
for (const column of columns) context.rect(column, 0, line, height);
|
|
33
|
+
for (const row of rows) context.rect(0, row, width, line);
|
|
34
|
+
context.fillStyle = look.colours.grid;
|
|
35
|
+
context.fill();
|
|
36
|
+
}
|
|
37
|
+
function zoneFill(context, { height, look, rowOf }) {
|
|
38
|
+
const gradient = context.createLinearGradient(0, 0, 0, height);
|
|
39
|
+
const { clip, hot } = zoneRows(look.numbers, rowOf);
|
|
40
|
+
gradient.addColorStop(clip / height, look.colours.clip);
|
|
41
|
+
gradient.addColorStop(clip / height, look.colours.hot);
|
|
42
|
+
gradient.addColorStop(hot / height, look.colours.hot);
|
|
43
|
+
gradient.addColorStop(hot / height, look.colours.lit);
|
|
44
|
+
return gradient;
|
|
45
|
+
}
|
|
46
|
+
function paintBars(context, scene, bars) {
|
|
47
|
+
const { height, rowOf } = scene;
|
|
48
|
+
let previous = height;
|
|
49
|
+
context.beginPath();
|
|
50
|
+
context.moveTo(0, height);
|
|
51
|
+
for (const [column, level] of bars.entries()) {
|
|
52
|
+
const row = rowOf(level);
|
|
53
|
+
bars[column] = row;
|
|
54
|
+
if (row === previous) continue;
|
|
55
|
+
context.lineTo(column, previous);
|
|
56
|
+
context.lineTo(column, row);
|
|
57
|
+
previous = row;
|
|
58
|
+
}
|
|
59
|
+
context.lineTo(bars.length, previous);
|
|
60
|
+
context.lineTo(bars.length, height);
|
|
61
|
+
context.closePath();
|
|
62
|
+
context.fillStyle = zoneFill(context, scene);
|
|
63
|
+
context.fill();
|
|
64
|
+
}
|
|
65
|
+
function paintHolds(context, { look, rowOf }, { bars, holds }) {
|
|
66
|
+
context.beginPath();
|
|
67
|
+
for (const [column, level] of holds.entries()) {
|
|
68
|
+
const row = rowOf(level);
|
|
69
|
+
if (row < (bars[column] ?? 0)) context.rect(column, row, 1, 1);
|
|
70
|
+
}
|
|
71
|
+
context.fillStyle = look.colours.lit;
|
|
72
|
+
context.fill();
|
|
73
|
+
}
|
|
74
|
+
var SonicSpectrum = class extends SonicDisplayElement {
|
|
75
|
+
static observedAttributes = [
|
|
76
|
+
...SonicDisplayElement.observedAttributes,
|
|
77
|
+
"frequency-max",
|
|
78
|
+
"frequency-min",
|
|
79
|
+
"grid",
|
|
80
|
+
"peak-hold",
|
|
81
|
+
"sample-rate"
|
|
82
|
+
];
|
|
83
|
+
get frequencyMax() {
|
|
84
|
+
return this.numberAttribute("frequency-max", defaultFrequencies[1]);
|
|
85
|
+
}
|
|
86
|
+
set frequencyMax(hertz) {
|
|
87
|
+
this.reflect("frequency-max", hertz);
|
|
88
|
+
}
|
|
89
|
+
get frequencyMin() {
|
|
90
|
+
return this.numberAttribute("frequency-min", defaultFrequencies[0]);
|
|
91
|
+
}
|
|
92
|
+
set frequencyMin(hertz) {
|
|
93
|
+
this.reflect("frequency-min", hertz);
|
|
94
|
+
}
|
|
95
|
+
get grid() {
|
|
96
|
+
return this.getAttribute("grid") === "none" ? "none" : "on";
|
|
97
|
+
}
|
|
98
|
+
set grid(grid) {
|
|
99
|
+
this.reflect("grid", grid);
|
|
100
|
+
}
|
|
101
|
+
get peak() {
|
|
102
|
+
return this.#peak && { ...this.#peak };
|
|
103
|
+
}
|
|
104
|
+
get peakHold() {
|
|
105
|
+
return this.hasAttribute("peak-hold");
|
|
106
|
+
}
|
|
107
|
+
set peakHold(isHeld) {
|
|
108
|
+
this.reflect("peak-hold", isHeld);
|
|
109
|
+
}
|
|
110
|
+
get sampleRate() {
|
|
111
|
+
const sampleRate = this.numberAttribute("sample-rate", defaultSampleRate);
|
|
112
|
+
return sampleRate > 0 ? sampleRate : defaultSampleRate;
|
|
113
|
+
}
|
|
114
|
+
set sampleRate(hertz) {
|
|
115
|
+
this.reflect("sample-rate", hertz);
|
|
116
|
+
}
|
|
117
|
+
control = renderSpectrum();
|
|
118
|
+
canvas = requireChild(this.control, ".sonic-spectrum-canvas", HTMLCanvasElement);
|
|
119
|
+
colours = colours;
|
|
120
|
+
numbers = numbers;
|
|
121
|
+
sheet = "spectrum.css";
|
|
122
|
+
#columns;
|
|
123
|
+
#isSettled = true;
|
|
124
|
+
#lastFrameMs;
|
|
125
|
+
#levels = createLevels(0);
|
|
126
|
+
#peak;
|
|
127
|
+
#receivedRate;
|
|
128
|
+
connectedCallback() {
|
|
129
|
+
this.upgradeProperties("frequencyMax", "frequencyMin", "grid", "peakHold", "sampleRate");
|
|
130
|
+
super.connectedCallback();
|
|
131
|
+
}
|
|
132
|
+
resetPeak() {
|
|
133
|
+
this.#peak = void 0;
|
|
134
|
+
}
|
|
135
|
+
paint(context, { frameMs, isDirty, look, size }) {
|
|
136
|
+
if (this.isDisabled()) {
|
|
137
|
+
if (isDirty) this.#draw(context, look, size);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const wasSettled = this.#isSettled;
|
|
141
|
+
this.#step(frameMs, look.isReducedMotion);
|
|
142
|
+
if (isDirty || !wasSettled || !this.#isSettled) this.#draw(context, look, size);
|
|
143
|
+
if (!this.#isSettled) this.surface()?.requestFrame();
|
|
144
|
+
}
|
|
145
|
+
pull(analyser, buffer) {
|
|
146
|
+
analyser.getFloatFrequencyData(buffer);
|
|
147
|
+
}
|
|
148
|
+
receive(frame) {
|
|
149
|
+
if (frame.length !== this.#levels.bars.length) this.#levels = createLevels(frame.length);
|
|
150
|
+
this.#receivedRate = this.analyser?.context.sampleRate ?? this.sampleRate;
|
|
151
|
+
receiveLevels(this.#levels, frame, this.min);
|
|
152
|
+
const loudest = loudestBin(frame, this.#axis());
|
|
153
|
+
if (loudest && loudest.decibels > (this.#peak?.decibels ?? -Infinity)) this.#peak = loudest;
|
|
154
|
+
}
|
|
155
|
+
#axis() {
|
|
156
|
+
const [frequencyMin, frequencyMax] = this.#frequencies();
|
|
157
|
+
return {
|
|
158
|
+
binCount: this.#levels.bars.length,
|
|
159
|
+
frequencyMax,
|
|
160
|
+
frequencyMin,
|
|
161
|
+
sampleRate: this.#receivedRate ?? this.sampleRate
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
#columnsFor(width) {
|
|
165
|
+
const axis = this.#axis();
|
|
166
|
+
const key = [
|
|
167
|
+
width,
|
|
168
|
+
axis.binCount,
|
|
169
|
+
axis.sampleRate,
|
|
170
|
+
axis.frequencyMin,
|
|
171
|
+
axis.frequencyMax
|
|
172
|
+
].join(" ");
|
|
173
|
+
if (this.#columns?.key !== key) this.#columns = {
|
|
174
|
+
bars: new Float64Array(width),
|
|
175
|
+
edges: columnEdges(axis, width),
|
|
176
|
+
holds: new Float64Array(width),
|
|
177
|
+
key
|
|
178
|
+
};
|
|
179
|
+
return this.#columns;
|
|
180
|
+
}
|
|
181
|
+
#draw(context, look, size) {
|
|
182
|
+
const scene = {
|
|
183
|
+
...size,
|
|
184
|
+
look,
|
|
185
|
+
range: {
|
|
186
|
+
max: this.max,
|
|
187
|
+
min: this.min
|
|
188
|
+
},
|
|
189
|
+
rowOf: levelRows({
|
|
190
|
+
max: this.max,
|
|
191
|
+
min: this.min
|
|
192
|
+
}, size.height)
|
|
193
|
+
};
|
|
194
|
+
context.clearRect(0, 0, size.width, size.height);
|
|
195
|
+
if (this.grid === "on") paintGrid(context, scene, this.#frequencies());
|
|
196
|
+
if (this.isDisabled()) return;
|
|
197
|
+
const { bars, edges, holds } = this.#columnsFor(size.width);
|
|
198
|
+
const spread = {
|
|
199
|
+
edges,
|
|
200
|
+
floor: scene.range.min
|
|
201
|
+
};
|
|
202
|
+
columnLevels(bars, this.#levels.bars, spread);
|
|
203
|
+
paintBars(context, scene, bars);
|
|
204
|
+
if (!this.peakHold) return;
|
|
205
|
+
columnLevels(holds, this.#levels.holds, spread);
|
|
206
|
+
paintHolds(context, scene, {
|
|
207
|
+
bars,
|
|
208
|
+
holds
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
#frequencies() {
|
|
212
|
+
const { frequencyMax, frequencyMin } = this;
|
|
213
|
+
return frequencyMin > 0 && frequencyMax > frequencyMin ? [frequencyMin, frequencyMax] : defaultFrequencies;
|
|
214
|
+
}
|
|
215
|
+
#step(frameMs, isReducedMotion) {
|
|
216
|
+
const floor = this.min;
|
|
217
|
+
stepLevels(this.#levels, {
|
|
218
|
+
elapsedMs: Math.max(0, frameMs - (this.#lastFrameMs ?? frameMs)),
|
|
219
|
+
floor,
|
|
220
|
+
isHeld: this.peakHold,
|
|
221
|
+
isHoldStepped: isReducedMotion,
|
|
222
|
+
nowMs: frameMs
|
|
223
|
+
});
|
|
224
|
+
this.#isSettled = areSettled(this.#levels, floor);
|
|
225
|
+
this.#lastFrameMs = this.#isSettled ? void 0 : frameMs;
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
//#endregion
|
|
230
|
+
export { SonicSpectrum };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { clamp } from "../lib/math.js";
|
|
2
|
-
import { requireChild, template } from "../lib/render.js";
|
|
3
2
|
import { writeAttribute } from "../lib/write-attribute.js";
|
|
4
3
|
import { bindHold } from "../lib/hold.js";
|
|
4
|
+
import { requireChild, template } from "../lib/render.js";
|
|
5
5
|
import { bindDrag } from "../lib/pointer-drag.js";
|
|
6
6
|
import { SonicRadioGroupElement, isUnder, optionValue } from "./radio-group.js";
|
|
7
7
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { clamp, toNumber } from "../lib/math.js";
|
|
2
|
-
import { placeChildren, requireChild } from "../lib/render.js";
|
|
1
|
+
import { clamp, toNumber, trimFloat } from "../lib/math.js";
|
|
3
2
|
import { writeAttribute } from "../lib/write-attribute.js";
|
|
4
3
|
import { SonicFormElement } from "./form-element.js";
|
|
5
|
-
import {
|
|
4
|
+
import { requireChild } from "../lib/render.js";
|
|
5
|
+
import { bindDrag } from "../lib/pointer-drag.js";
|
|
6
6
|
import { ReadoutClaim } from "./readout-claim.js";
|
|
7
7
|
import { Readout } from "./readout.js";
|
|
8
8
|
import { ValueEntry } from "./value-entry.js";
|
|
@@ -10,9 +10,7 @@ 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";
|
|
14
13
|
import { readPxProperty } from "../lib/read-px-property.js";
|
|
15
|
-
import { readRegions } from "../lib/time-regions.js";
|
|
16
14
|
import { resetKeys, valueMapping } from "../lib/value-mapping.js";
|
|
17
15
|
|
|
18
16
|
//#region src/elements/value-element.ts
|
|
@@ -37,18 +35,6 @@ const roleAttributes = [
|
|
|
37
35
|
"role",
|
|
38
36
|
"tabindex"
|
|
39
37
|
];
|
|
40
|
-
function scaleValue(mark) {
|
|
41
|
-
const text = mark.dataset.sonicValue?.trim();
|
|
42
|
-
return text ? Number(text) : NaN;
|
|
43
|
-
}
|
|
44
|
-
function scaleMark(original) {
|
|
45
|
-
const mark = copyNode(original);
|
|
46
|
-
if (!(mark instanceof HTMLElement || mark instanceof SVGElement)) return void 0;
|
|
47
|
-
if (!Number.isFinite(scaleValue(mark))) return void 0;
|
|
48
|
-
const isTick = mark.childElementCount === 0 && mark.textContent.trim() === "";
|
|
49
|
-
mark.classList.add(isTick ? "sonic-scale-tick" : "sonic-scale-label");
|
|
50
|
-
return mark;
|
|
51
|
-
}
|
|
52
38
|
let link;
|
|
53
39
|
function linkValue(element) {
|
|
54
40
|
return link(element);
|
|
@@ -63,7 +49,9 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
63
49
|
"notched",
|
|
64
50
|
"origin",
|
|
65
51
|
"readout",
|
|
52
|
+
"spoken-step",
|
|
66
53
|
"step",
|
|
54
|
+
"tabindex",
|
|
67
55
|
"taper",
|
|
68
56
|
"value",
|
|
69
57
|
"positions"
|
|
@@ -89,13 +77,6 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
89
77
|
}
|
|
90
78
|
});
|
|
91
79
|
}
|
|
92
|
-
get buffered() {
|
|
93
|
-
return this.#buffered.map(([start, end]) => [start, end]);
|
|
94
|
-
}
|
|
95
|
-
set buffered(regions) {
|
|
96
|
-
this.#buffered = regions ? readRegions(regions).toSorted((first, second) => first[0] - second[0]) : [];
|
|
97
|
-
this.render();
|
|
98
|
-
}
|
|
99
80
|
get default() {
|
|
100
81
|
return this.optionalNumberAttribute("default");
|
|
101
82
|
}
|
|
@@ -176,6 +157,9 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
176
157
|
set parseValue(parse) {
|
|
177
158
|
this.#parseValue = parse;
|
|
178
159
|
}
|
|
160
|
+
get pointerType() {
|
|
161
|
+
return this.#dragging()?.pointerType;
|
|
162
|
+
}
|
|
179
163
|
get positions() {
|
|
180
164
|
return parseNumberList(this.getAttribute("positions"));
|
|
181
165
|
}
|
|
@@ -188,6 +172,12 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
188
172
|
set readout(isShown) {
|
|
189
173
|
this.reflect("readout", isShown);
|
|
190
174
|
}
|
|
175
|
+
get spokenStep() {
|
|
176
|
+
return this.optionalNumberAttribute("spoken-step");
|
|
177
|
+
}
|
|
178
|
+
set spokenStep(value) {
|
|
179
|
+
this.reflect("spoken-step", value);
|
|
180
|
+
}
|
|
191
181
|
get step() {
|
|
192
182
|
return this.numberAttribute("step", 1);
|
|
193
183
|
}
|
|
@@ -220,16 +210,16 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
220
210
|
return this.#textFor(this.#value);
|
|
221
211
|
}
|
|
222
212
|
#asked;
|
|
223
|
-
#buffered = [];
|
|
224
213
|
#claim = new ReadoutClaim(() => {
|
|
225
214
|
this.#renderHold();
|
|
226
215
|
});
|
|
227
216
|
#entry;
|
|
228
|
-
#escapeWatch;
|
|
229
217
|
#formatSpokenValue;
|
|
230
218
|
#formatValue;
|
|
219
|
+
#heldAt;
|
|
231
220
|
#instance = String(instanceCount += 1);
|
|
232
221
|
#isModulated = false;
|
|
222
|
+
#isRevealed = false;
|
|
233
223
|
#keyScrub;
|
|
234
224
|
#land;
|
|
235
225
|
#limit;
|
|
@@ -239,7 +229,6 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
239
229
|
#pointerDrag;
|
|
240
230
|
#positions;
|
|
241
231
|
#readout;
|
|
242
|
-
#scaleMarks;
|
|
243
232
|
#value = 0;
|
|
244
233
|
#watchers = /* @__PURE__ */ new Set();
|
|
245
234
|
attributeChangedCallback(name) {
|
|
@@ -258,7 +247,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
258
247
|
this.render();
|
|
259
248
|
}
|
|
260
249
|
connectedCallback() {
|
|
261
|
-
this.upgradeProperties("
|
|
250
|
+
this.upgradeProperties("default", "dimmed", "doublePress", "max", "midpoint", "min", "notched", "origin", "readout", "spokenStep", "step", "taper", "positions", "detent", "formatValue", "formatSpokenValue", "keyStep", "parseValue", "value");
|
|
262
251
|
super.connectedCallback();
|
|
263
252
|
}
|
|
264
253
|
bindGestures(control, signal, grab) {
|
|
@@ -284,6 +273,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
284
273
|
fromValue,
|
|
285
274
|
isOutside: false,
|
|
286
275
|
isRevealed: false,
|
|
276
|
+
pointerType: event.pointerType,
|
|
287
277
|
revealTimer: void 0,
|
|
288
278
|
state: this.#startDrag(control, axis, event)
|
|
289
279
|
};
|
|
@@ -322,19 +312,6 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
322
312
|
this.#concealKeyReveal();
|
|
323
313
|
}, { once: true });
|
|
324
314
|
}
|
|
325
|
-
bindScale(control, marks, signal) {
|
|
326
|
-
this.#scaleMarks = marks;
|
|
327
|
-
this.mirrorChildren({
|
|
328
|
-
control,
|
|
329
|
-
copy: scaleMark,
|
|
330
|
-
isCopied: (child) => child instanceof Element && child.matches("[data-sonic-value]"),
|
|
331
|
-
isPassed: (child) => child instanceof Element && child.matches(".sonic-led"),
|
|
332
|
-
place: (copies) => {
|
|
333
|
-
placeChildren(marks, copies);
|
|
334
|
-
this.#renderScale();
|
|
335
|
-
}
|
|
336
|
-
}, signal);
|
|
337
|
-
}
|
|
338
315
|
controlOrientation() {}
|
|
339
316
|
controlRole() {
|
|
340
317
|
return "slider";
|
|
@@ -342,13 +319,10 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
342
319
|
heldFrom() {
|
|
343
320
|
return this.#dragging()?.fromValue ?? this.#keyScrub?.fromValue;
|
|
344
321
|
}
|
|
345
|
-
heldWrite(
|
|
346
|
-
|
|
347
|
-
hoverReadout(value) {
|
|
348
|
-
this.#claim.hover(value);
|
|
349
|
-
this.#renderReadout();
|
|
350
|
-
this.#watchEscape(value !== void 0);
|
|
322
|
+
heldWrite(next) {
|
|
323
|
+
this.#heldAt = next;
|
|
351
324
|
}
|
|
325
|
+
holdChanged() {}
|
|
352
326
|
input(next) {
|
|
353
327
|
const previous = this.#value;
|
|
354
328
|
this.#write(this.#limit ? clamp(next, ...this.#limit) : next);
|
|
@@ -359,6 +333,9 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
359
333
|
}));
|
|
360
334
|
return true;
|
|
361
335
|
}
|
|
336
|
+
isEditing() {
|
|
337
|
+
return this.#entry?.isOpen === true;
|
|
338
|
+
}
|
|
362
339
|
isRevealed() {
|
|
363
340
|
return this.#claim.isRevealed;
|
|
364
341
|
}
|
|
@@ -384,17 +361,33 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
384
361
|
originValue() {
|
|
385
362
|
return this.origin ?? this.mapping().bounds[0];
|
|
386
363
|
}
|
|
364
|
+
playback() {
|
|
365
|
+
const from = this.heldFrom();
|
|
366
|
+
return from === void 0 ? this.#value : this.#heldAt ?? from;
|
|
367
|
+
}
|
|
368
|
+
previewValue() {}
|
|
387
369
|
proportionsChanged() {}
|
|
388
370
|
readModulationValue() {
|
|
389
371
|
return this.#modulationValue;
|
|
390
372
|
}
|
|
391
373
|
readoutValue() {
|
|
392
|
-
return this.#
|
|
374
|
+
return this.#shown().value ?? this.#value;
|
|
393
375
|
}
|
|
394
376
|
render() {
|
|
395
377
|
if (this.isBound()) this.#renderControl();
|
|
396
378
|
for (const listener of this.#watchers) listener();
|
|
397
379
|
}
|
|
380
|
+
renderReadout() {
|
|
381
|
+
const readout = this.#readout;
|
|
382
|
+
if (!readout) return;
|
|
383
|
+
const { isOpen, value } = this.#shown();
|
|
384
|
+
const text = value === void 0 ? void 0 : this.#textFor(value);
|
|
385
|
+
readout.bubble.show({
|
|
386
|
+
anchor: readout.anchor,
|
|
387
|
+
isOpen: isOpen && text !== "",
|
|
388
|
+
text
|
|
389
|
+
});
|
|
390
|
+
}
|
|
398
391
|
restoreState(state) {
|
|
399
392
|
this.value = Number(state);
|
|
400
393
|
}
|
|
@@ -440,7 +433,6 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
440
433
|
},
|
|
441
434
|
text: () => this.#parseValue ? this.valueText : String(this.#value),
|
|
442
435
|
toggle: (isOpen) => {
|
|
443
|
-
this.#claim.edit(isOpen);
|
|
444
436
|
if (isOpen) this.forwardNaming(input, true);
|
|
445
437
|
this.toggleState("editing", isOpen);
|
|
446
438
|
this.render();
|
|
@@ -501,10 +493,13 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
501
493
|
drag.state = this.#withinLimit(mapping, state);
|
|
502
494
|
if (value === void 0) return;
|
|
503
495
|
if (!wasEngaged) this.#reveal(drag);
|
|
496
|
+
const isCrossing = isOutside !== drag.isOutside;
|
|
497
|
+
if (isCrossing) {
|
|
498
|
+
drag.isOutside = isOutside;
|
|
499
|
+
this.toggleState("cancelling", isOutside);
|
|
500
|
+
}
|
|
504
501
|
this.input(isOutside ? drag.fromValue : value);
|
|
505
|
-
if (
|
|
506
|
-
drag.isOutside = isOutside;
|
|
507
|
-
this.#renderDragReveal(drag);
|
|
502
|
+
if (isCrossing) this.#renderDragReveal(drag);
|
|
508
503
|
}
|
|
509
504
|
#endHolds() {
|
|
510
505
|
this.#entry?.close(false);
|
|
@@ -536,7 +531,9 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
536
531
|
#releaseDrag(drag) {
|
|
537
532
|
clearTimeout(drag.revealTimer);
|
|
538
533
|
this.#claim.conceal("drag");
|
|
534
|
+
this.toggleState("cancelling", false);
|
|
539
535
|
this.#renderHold();
|
|
536
|
+
this.#showRevealed(false);
|
|
540
537
|
if (this.#value !== drag.fromValue) this.dispatchEvent(new Event("change", { bubbles: true }));
|
|
541
538
|
this.#springBack();
|
|
542
539
|
}
|
|
@@ -545,59 +542,43 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
545
542
|
if (this.#entry?.isOpen) {
|
|
546
543
|
for (const name of roleAttributes) control.removeAttribute(name);
|
|
547
544
|
this.forwardNaming(control, false);
|
|
548
|
-
this
|
|
545
|
+
this.renderReadout();
|
|
549
546
|
return;
|
|
550
547
|
}
|
|
551
548
|
const [low, high] = this.mapping().bounds;
|
|
552
549
|
writeAttribute(control, "role", this.controlRole());
|
|
553
550
|
writeAttribute(control, "aria-valuemin", String(low));
|
|
554
551
|
writeAttribute(control, "aria-valuemax", String(high));
|
|
555
|
-
writeAttribute(control, "aria-valuenow", String(this.#
|
|
552
|
+
writeAttribute(control, "aria-valuenow", String(this.#spokenNow()));
|
|
556
553
|
if (orientation) writeAttribute(control, "aria-orientation", orientation);
|
|
557
554
|
writeAttribute(control, "aria-valuetext", (this.#formatSpokenValue ?? this.#formatValue)?.(this.#value));
|
|
558
555
|
this.forwardNaming(control, true);
|
|
559
556
|
this.#renderDisabled(control);
|
|
560
|
-
this
|
|
557
|
+
this.renderReadout();
|
|
561
558
|
}
|
|
562
559
|
#renderControl() {
|
|
563
560
|
this.draw();
|
|
564
|
-
this.#renderScale();
|
|
565
561
|
this.toggleState("at-origin", !this.isWrapping() && this.#value === this.mapping().snap(this.originValue()));
|
|
566
562
|
this.#renderAria(this.focusTarget(), this.controlOrientation());
|
|
567
563
|
}
|
|
568
564
|
#renderDisabled(control) {
|
|
569
565
|
const isDisabled = this.isDisabled();
|
|
570
566
|
writeAttribute(control, "aria-disabled", isDisabled ? "true" : void 0);
|
|
571
|
-
|
|
567
|
+
const stop = this.getAttribute("tabindex") === "-1" ? "-1" : "0";
|
|
568
|
+
writeAttribute(control, "tabindex", isDisabled ? void 0 : stop);
|
|
572
569
|
}
|
|
573
570
|
#renderDragReveal(drag) {
|
|
574
|
-
|
|
571
|
+
const isRevealed = drag.isRevealed && !drag.isOutside;
|
|
572
|
+
if (isRevealed) this.#claim.reveal("drag");
|
|
575
573
|
else this.#claim.conceal("drag");
|
|
576
574
|
this.#renderHold();
|
|
575
|
+
this.#showRevealed(isRevealed);
|
|
577
576
|
}
|
|
578
577
|
#renderHold() {
|
|
579
|
-
this
|
|
578
|
+
if (this.heldFrom() === void 0) this.#heldAt = void 0;
|
|
579
|
+
this.renderReadout();
|
|
580
580
|
this.holdChanged();
|
|
581
581
|
}
|
|
582
|
-
#renderReadout() {
|
|
583
|
-
const readout = this.#readout;
|
|
584
|
-
if (!readout) return;
|
|
585
|
-
const { isOpen, value } = this.#claim.shown(this.#value, this.readout);
|
|
586
|
-
readout.bubble.show({
|
|
587
|
-
anchor: readout.anchor,
|
|
588
|
-
isOpen,
|
|
589
|
-
text: value === void 0 ? void 0 : this.#textFor(value)
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
#renderScale() {
|
|
593
|
-
const marks = this.#scaleMarks?.children ?? [];
|
|
594
|
-
const mapping = this.mapping();
|
|
595
|
-
for (const mark of marks) {
|
|
596
|
-
if (!(mark instanceof HTMLElement || mark instanceof SVGElement)) continue;
|
|
597
|
-
const at = String(mapping.proportionOf(scaleValue(mark)));
|
|
598
|
-
if (mark.style.getPropertyValue("--_sonic-scale-at") !== at) mark.style.setProperty("--_sonic-scale-at", at);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
582
|
#reset() {
|
|
602
583
|
this.#commit(this.default ?? NaN);
|
|
603
584
|
}
|
|
@@ -616,6 +597,28 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
616
597
|
}
|
|
617
598
|
this.input(next);
|
|
618
599
|
}
|
|
600
|
+
#shown() {
|
|
601
|
+
if (this.isEditing()) return {
|
|
602
|
+
isOpen: true,
|
|
603
|
+
value: void 0
|
|
604
|
+
};
|
|
605
|
+
const isRevealed = this.#claim.isRevealed;
|
|
606
|
+
const preview = isRevealed ? void 0 : this.previewValue();
|
|
607
|
+
return {
|
|
608
|
+
isOpen: (isRevealed || preview !== void 0) && this.readout,
|
|
609
|
+
value: preview ?? this.#value
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
#showRevealed(isRevealed) {
|
|
613
|
+
if (isRevealed === this.#isRevealed) return;
|
|
614
|
+
this.#isRevealed = isRevealed;
|
|
615
|
+
this.toggleState("revealed", isRevealed);
|
|
616
|
+
this.dispatchEvent(new Event("sonic-reveal", { bubbles: true }));
|
|
617
|
+
}
|
|
618
|
+
#spokenNow() {
|
|
619
|
+
const step = this.spokenStep;
|
|
620
|
+
return step !== void 0 && step > 0 ? trimFloat(Math.round(this.#value / step) * step) : this.#value;
|
|
621
|
+
}
|
|
619
622
|
#springBack() {
|
|
620
623
|
const target = this.springTarget();
|
|
621
624
|
if (target === void 0) return;
|
|
@@ -645,19 +648,6 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
645
648
|
#textFor(value) {
|
|
646
649
|
return this.#formatValue?.(value) ?? String(value);
|
|
647
650
|
}
|
|
648
|
-
#watchEscape(isHovered) {
|
|
649
|
-
if (!isHovered) {
|
|
650
|
-
this.#escapeWatch?.abort();
|
|
651
|
-
this.#escapeWatch = void 0;
|
|
652
|
-
return;
|
|
653
|
-
}
|
|
654
|
-
if (this.#escapeWatch) return;
|
|
655
|
-
const watch = new AbortController();
|
|
656
|
-
this.#escapeWatch = watch;
|
|
657
|
-
this.ownerDocument.addEventListener("keydown", (event) => {
|
|
658
|
-
if (event.key === "Escape" && this.#claim.dismiss()) this.#renderHold();
|
|
659
|
-
}, { signal: watch.signal });
|
|
660
|
-
}
|
|
661
651
|
#withinLimit(mapping, state) {
|
|
662
652
|
const limit = this.#limit;
|
|
663
653
|
if (!limit || mapping.isWrapping) return state;
|