@xsynaptic/sonic-ui 0.17.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +122 -19
- package/dist/default/elements/button.js +2 -5
- package/dist/default/elements/dial.js +2 -7
- package/dist/default/elements/display-element.js +9 -12
- package/dist/default/elements/envelope.js +31 -78
- package/dist/default/elements/field-gesture.js +81 -0
- package/dist/default/elements/meter.js +4 -1
- package/dist/default/elements/number.js +0 -7
- package/dist/default/elements/position-group.js +42 -26
- package/dist/default/elements/radio-group.js +59 -56
- package/dist/default/elements/scale.js +3 -3
- package/dist/default/elements/segmented.js +0 -5
- package/dist/default/elements/slider.js +11 -20
- package/dist/default/elements/sonic-element.js +3 -1
- package/dist/default/elements/split.js +14 -13
- package/dist/default/elements/switch.js +31 -47
- package/dist/default/elements/toggle.js +20 -49
- package/dist/default/elements/value-element.js +72 -94
- package/dist/default/elements/value-gestures.js +22 -22
- package/dist/default/elements/wave-element.js +16 -20
- package/dist/default/elements/waveform.js +42 -241
- package/dist/default/elements/wavestrip.js +10 -5
- package/dist/default/elements/xy.js +67 -119
- package/dist/default/index.js +2 -1
- package/dist/default/lib/canvas-surface.js +25 -0
- package/dist/default/lib/clock.js +23 -0
- package/dist/default/lib/crossfade.js +1 -0
- package/dist/default/lib/envelope-curve.js +1 -0
- package/dist/default/lib/peaks-request.js +44 -0
- package/dist/default/lib/positions.js +58 -0
- package/dist/default/lib/scrub.js +12 -0
- package/dist/default/lib/spoken-duration.js +30 -0
- package/dist/default/lib/value-model.js +62 -0
- package/dist/default/lib/waveform-buckets.js +7 -1
- package/dist/default/lib/waveform-scene.js +108 -0
- package/dist/default/lib/zoom-gesture.js +97 -1
- package/dist/dev/elements/button.d.ts +2 -0
- package/dist/dev/elements/button.js +14 -5
- package/dist/dev/elements/button.js.map +1 -1
- package/dist/dev/elements/dial.d.ts +2 -0
- package/dist/dev/elements/dial.js +16 -7
- package/dist/dev/elements/dial.js.map +1 -1
- package/dist/dev/elements/display-element.d.ts +5 -3
- package/dist/dev/elements/display-element.js +11 -9
- package/dist/dev/elements/display-element.js.map +1 -1
- package/dist/dev/elements/envelope.js +48 -78
- package/dist/dev/elements/envelope.js.map +1 -1
- package/dist/dev/elements/field-gesture.js +82 -0
- package/dist/dev/elements/field-gesture.js.map +1 -0
- package/dist/dev/elements/meter.d.ts +10 -5
- package/dist/dev/elements/meter.js +5 -1
- package/dist/dev/elements/meter.js.map +1 -1
- package/dist/dev/elements/number.js +13 -7
- package/dist/dev/elements/number.js.map +1 -1
- package/dist/dev/elements/position-group.d.ts +12 -6
- package/dist/dev/elements/position-group.js +42 -26
- package/dist/dev/elements/position-group.js.map +1 -1
- package/dist/dev/elements/radio-group.d.ts +11 -7
- package/dist/dev/elements/radio-group.js +59 -56
- package/dist/dev/elements/radio-group.js.map +1 -1
- package/dist/dev/elements/scale.js +3 -3
- package/dist/dev/elements/scale.js.map +1 -1
- package/dist/dev/elements/segmented.js +12 -5
- package/dist/dev/elements/segmented.js.map +1 -1
- package/dist/dev/elements/slider.d.ts +4 -2
- package/dist/dev/elements/slider.js +25 -20
- package/dist/dev/elements/slider.js.map +1 -1
- package/dist/dev/elements/sonic-element.d.ts +13 -2
- package/dist/dev/elements/sonic-element.js +63 -11
- package/dist/dev/elements/sonic-element.js.map +1 -1
- package/dist/dev/elements/split.d.ts +1 -0
- package/dist/dev/elements/split.js +14 -13
- package/dist/dev/elements/split.js.map +1 -1
- package/dist/dev/elements/switch.d.ts +2 -2
- package/dist/dev/elements/switch.js +38 -47
- package/dist/dev/elements/switch.js.map +1 -1
- package/dist/dev/elements/toggle.js +32 -49
- package/dist/dev/elements/toggle.js.map +1 -1
- package/dist/dev/elements/value-element.d.ts +11 -5
- package/dist/dev/elements/value-element.js +72 -94
- package/dist/dev/elements/value-element.js.map +1 -1
- package/dist/dev/elements/value-gestures.js +22 -22
- package/dist/dev/elements/value-gestures.js.map +1 -1
- package/dist/dev/elements/wave-element.d.ts +8 -5
- package/dist/dev/elements/wave-element.js +30 -20
- package/dist/dev/elements/wave-element.js.map +1 -1
- package/dist/dev/elements/waveform.d.ts +20 -22
- package/dist/dev/elements/waveform.js +42 -241
- package/dist/dev/elements/waveform.js.map +1 -1
- package/dist/dev/elements/wavestrip.d.ts +5 -1
- package/dist/dev/elements/wavestrip.js +10 -5
- package/dist/dev/elements/wavestrip.js.map +1 -1
- package/dist/dev/elements/xy.js +81 -119
- package/dist/dev/elements/xy.js.map +1 -1
- package/dist/dev/index.d.ts +5 -3
- package/dist/dev/index.js +2 -1
- package/dist/dev/lib/canvas-surface.d.ts +1 -0
- package/dist/dev/lib/canvas-surface.js +25 -0
- package/dist/dev/lib/canvas-surface.js.map +1 -1
- package/dist/dev/lib/clock.d.ts +5 -0
- package/dist/dev/lib/clock.js +24 -0
- package/dist/dev/lib/clock.js.map +1 -0
- package/dist/dev/lib/crossfade.d.ts +1 -0
- package/dist/dev/lib/crossfade.js +1 -0
- package/dist/dev/lib/crossfade.js.map +1 -1
- package/dist/dev/lib/envelope-curve.d.ts +1 -0
- package/dist/dev/lib/envelope-curve.js +1 -0
- package/dist/dev/lib/envelope-curve.js.map +1 -1
- package/dist/dev/lib/mirror-children.js.map +1 -1
- package/dist/dev/lib/owned-control.js.map +1 -1
- package/dist/dev/lib/peaks-request.d.ts +5 -0
- package/dist/dev/lib/peaks-request.js +45 -0
- package/dist/dev/lib/peaks-request.js.map +1 -0
- package/dist/dev/lib/positions.d.ts +7 -0
- package/dist/dev/lib/positions.js +59 -0
- package/dist/dev/lib/positions.js.map +1 -0
- package/dist/dev/lib/scrub.d.ts +8 -0
- package/dist/dev/lib/scrub.js +13 -0
- package/dist/dev/lib/scrub.js.map +1 -0
- package/dist/dev/lib/spoken-duration.js +31 -0
- package/dist/dev/lib/spoken-duration.js.map +1 -0
- package/dist/dev/lib/time-regions.d.ts +1 -0
- package/dist/dev/lib/time-regions.js.map +1 -1
- package/dist/dev/lib/units.d.ts +8 -0
- package/dist/dev/lib/value-model.js +63 -0
- package/dist/dev/lib/value-model.js.map +1 -0
- package/dist/dev/lib/waveform-buckets.d.ts +2 -1
- package/dist/dev/lib/waveform-buckets.js +7 -1
- package/dist/dev/lib/waveform-buckets.js.map +1 -1
- package/dist/dev/lib/waveform-scene.d.ts +11 -0
- package/dist/dev/lib/waveform-scene.js +109 -0
- package/dist/dev/lib/waveform-scene.js.map +1 -0
- package/dist/dev/lib/zoom-gesture.js +97 -1
- package/dist/dev/lib/zoom-gesture.js.map +1 -1
- package/dist/skins/amber.css +1 -0
- package/dist/skins/ivory.css +1 -0
- package/dist/skins/lime.css +1 -0
- package/dist/skins/slate.css +1 -0
- package/dist/styles/button.css +45 -11
- package/dist/styles/dial.css +10 -9
- package/dist/styles/envelope.css +10 -4
- package/dist/styles/led.css +5 -1
- package/dist/styles/material/arc.css +3 -2
- package/dist/styles/material/bracket.css +2 -2
- package/dist/styles/material/cap.css +33 -12
- package/dist/styles/material/core.css +4 -0
- package/dist/styles/material/glass.css +1 -1
- package/dist/styles/material/groove.css +4 -3
- package/dist/styles/material/keycap.css +3 -2
- package/dist/styles/material/lens.css +1 -1
- package/dist/styles/material/pane.css +5 -4
- package/dist/styles/material/readout.css +6 -6
- package/dist/styles/material/well.css +2 -2
- package/dist/styles/meter.css +2 -7
- package/dist/styles/number.css +5 -1
- package/dist/styles/panel.css +4 -3
- package/dist/styles/ring.css +1 -1
- package/dist/styles/screen.css +5 -1
- package/dist/styles/segmented.css +17 -4
- package/dist/styles/slider.css +9 -3
- package/dist/styles/spectrum.css +16 -3
- package/dist/styles/switch.css +35 -10
- package/dist/styles/toggle.css +14 -7
- package/dist/styles/waveform.css +17 -5
- package/dist/styles/wavestrip.css +11 -3
- package/dist/styles/xy.css +9 -5
- package/package.json +1 -6
- package/dist/default/dat.js +0 -51
- package/dist/default/lib/asked-value.js +0 -21
- package/dist/default/lib/fill-watch.js +0 -29
- package/dist/dev/dat.d.ts +0 -19
- package/dist/dev/dat.js +0 -52
- package/dist/dev/dat.js.map +0 -1
- package/dist/dev/lib/asked-value.js +0 -22
- package/dist/dev/lib/asked-value.js.map +0 -1
- package/dist/dev/lib/fill-watch.js +0 -30
- package/dist/dev/lib/fill-watch.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"waveform-buckets.js","names":[],"sources":["../../../src/lib/waveform-buckets.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"waveform-buckets.js","names":[],"sources":["../../../src/lib/waveform-buckets.ts"],"sourcesContent":["/** Interleaved min, max per channel per pair; `fullScale` unset follows the array: 128, 32768 or 1 */\nexport interface WaveformPeaks {\n\tchannels?: number;\n\tfullScale?: number;\n\tpairsPerSecond: number;\n\tsamples: Float32Array | Int8Array | Int16Array;\n}\n\ninterface WaveformBucket {\n\tfromPair: number;\n\thigh: number;\n\tlow: number;\n\ttoPair: number;\n\tx: number;\n}\n\ninterface BucketView {\n\tpixelsPerSecond: number;\n\tstartSeconds: number;\n\twidth: number;\n}\n\nfunction fullScaleOf({ fullScale, samples }: WaveformPeaks): number {\n\tif (fullScale !== undefined) return fullScale;\n\tif (samples instanceof Int8Array) return 128;\n\n\treturn samples instanceof Int16Array ? 32_768 : 1;\n}\n\nfunction foldPairs(peaks: WaveformPeaks, fromPair: number, toPair: number): [number, number] {\n\tconst { samples } = peaks;\n\tconst channels = Math.max(1, peaks.channels ?? 1);\n\tconst stride = channels * 2;\n\tconst pairsTotal = Math.floor(samples.length / stride);\n\tconst fullScale = fullScaleOf(peaks);\n\tlet low = 0;\n\tlet high = 0;\n\n\tfor (let pair = Math.max(0, fromPair); pair < Math.min(pairsTotal, toPair); pair += 1) {\n\t\tfor (let channel = 0; channel < channels; channel += 1) {\n\t\t\tconst at = pair * stride + channel * 2;\n\n\t\t\tlow = Math.min(low, samples[at] ?? 0);\n\t\t\thigh = Math.max(high, samples[at + 1] ?? 0);\n\t\t}\n\t}\n\n\treturn [low / fullScale, high / fullScale];\n}\n\n// Keyed to absolute pairs; keyed to the window, the same samples re-bucket every frame and judder\nexport function waveformBuckets(peaks: WaveformPeaks, view: BucketView): Array<WaveformBucket> {\n\tconst { pairsPerSecond } = peaks;\n\tif (pairsPerSecond <= 0 || view.pixelsPerSecond <= 0) return [];\n\n\tconst pxPerPair = view.pixelsPerSecond / pairsPerSecond;\n\tconst pairs = Math.max(1, Math.round(1 / pxPerPair));\n\tconst openingPair = view.startSeconds * pairsPerSecond;\n\tconst first = Math.floor(openingPair / pairs) - 1;\n\tconst count = Math.ceil(view.width / (pairs * pxPerPair)) + 3;\n\tconst buckets: Array<WaveformBucket> = [];\n\n\tfor (let index = 0; index < count; index += 1) {\n\t\tconst fromPair = (first + index) * pairs;\n\t\tconst toPair = fromPair + pairs;\n\t\tconst [low, high] = foldPairs(peaks, fromPair, toPair);\n\n\t\tbuckets.push({ fromPair, high, low, toPair, x: (fromPair - openingPair) * pxPerPair });\n\t}\n\n\treturn buckets;\n}\n"],"mappings":";AAsBA,SAAS,YAAY,EAAE,WAAW,WAAkC;CACnE,IAAI,cAAc,QAAW,OAAO;CACpC,IAAI,mBAAmB,WAAW,OAAO;CAEzC,OAAO,mBAAmB,aAAa,QAAS;AACjD;AAEA,SAAS,UAAU,OAAsB,UAAkB,QAAkC;CAC5F,MAAM,EAAE,YAAY;CACpB,MAAM,WAAW,KAAK,IAAI,GAAG,MAAM,YAAY,CAAC;CAChD,MAAM,SAAS,WAAW;CAC1B,MAAM,aAAa,KAAK,MAAM,QAAQ,SAAS,MAAM;CACrD,MAAM,YAAY,YAAY,KAAK;CACnC,IAAI,MAAM;CACV,IAAI,OAAO;CAEX,KAAK,IAAI,OAAO,KAAK,IAAI,GAAG,QAAQ,GAAG,OAAO,KAAK,IAAI,YAAY,MAAM,GAAG,QAAQ,GACnF,KAAK,IAAI,UAAU,GAAG,UAAU,UAAU,WAAW,GAAG;EACvD,MAAM,KAAK,OAAO,SAAS,UAAU;EAErC,MAAM,KAAK,IAAI,KAAK,QAAQ,OAAO,CAAC;EACpC,OAAO,KAAK,IAAI,MAAM,QAAQ,KAAK,MAAM,CAAC;CAC3C;CAGD,OAAO,CAAC,MAAM,WAAW,OAAO,SAAS;AAC1C;AAGA,SAAgB,gBAAgB,OAAsB,MAAyC;CAC9F,MAAM,EAAE,mBAAmB;CAC3B,IAAI,kBAAkB,KAAK,KAAK,mBAAmB,GAAG,OAAO,CAAC;CAE9D,MAAM,YAAY,KAAK,kBAAkB;CACzC,MAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,SAAS,CAAC;CACnD,MAAM,cAAc,KAAK,eAAe;CACxC,MAAM,QAAQ,KAAK,MAAM,cAAc,KAAK,IAAI;CAChD,MAAM,QAAQ,KAAK,KAAK,KAAK,SAAS,QAAQ,UAAU,IAAI;CAC5D,MAAM,UAAiC,CAAC;CAExC,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,SAAS,GAAG;EAC9C,MAAM,YAAY,QAAQ,SAAS;EACnC,MAAM,SAAS,WAAW;EAC1B,MAAM,CAAC,KAAK,QAAQ,UAAU,OAAO,UAAU,MAAM;EAErD,QAAQ,KAAK;GAAE;GAAU;GAAM;GAAK;GAAQ,IAAI,WAAW,eAAe;EAAU,CAAC;CACtF;CAEA,OAAO;AACR"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/lib/waveform-scene.d.ts
|
|
2
|
+
export declare const waveformColours: {
|
|
3
|
+
readonly ends: "--_sonic-waveform-ends";
|
|
4
|
+
readonly grid: "--_sonic-waveform-grid";
|
|
5
|
+
readonly marker: "--_sonic-waveform-marker";
|
|
6
|
+
readonly placeholder: "--_sonic-waveform-placeholder";
|
|
7
|
+
readonly wave: "--_sonic-waveform-wave";
|
|
8
|
+
readonly waveEdge: "--_sonic-waveform-wave-edge";
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
//# sourceMappingURL=waveform-scene.d.ts.map
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { clamp } from "./math.js";
|
|
2
|
+
import { isKind } from "./marker-band.js";
|
|
3
|
+
import { waveformBuckets } from "./waveform-buckets.js";
|
|
4
|
+
|
|
5
|
+
//#region src/lib/waveform-scene.ts
|
|
6
|
+
const waveformColours = {
|
|
7
|
+
ends: "--_sonic-waveform-ends",
|
|
8
|
+
grid: "--_sonic-waveform-grid",
|
|
9
|
+
marker: "--_sonic-waveform-marker",
|
|
10
|
+
placeholder: "--_sonic-waveform-placeholder",
|
|
11
|
+
wave: "--_sonic-waveform-wave",
|
|
12
|
+
waveEdge: "--_sonic-waveform-wave-edge"
|
|
13
|
+
};
|
|
14
|
+
const amplitudeMargin = .94;
|
|
15
|
+
const hatchPitchPx = 8;
|
|
16
|
+
const placeholderWavelengthPx = 48;
|
|
17
|
+
const placeholderAmplitude = .2;
|
|
18
|
+
function paintHatch(context, scene, [from, to]) {
|
|
19
|
+
if (to <= from) return;
|
|
20
|
+
const { dpr, height } = scene;
|
|
21
|
+
const pitch = Math.max(2, Math.round(hatchPitchPx * dpr));
|
|
22
|
+
const offset = scene.startSeconds * scene.pixelsPerSecond;
|
|
23
|
+
context.save();
|
|
24
|
+
context.beginPath();
|
|
25
|
+
context.rect(from, 0, to - from, height);
|
|
26
|
+
context.clip();
|
|
27
|
+
context.beginPath();
|
|
28
|
+
for (let x = Math.floor((from - height + offset) / pitch) * pitch - offset; x < to; x += pitch) {
|
|
29
|
+
context.moveTo(x, height);
|
|
30
|
+
context.lineTo(x + height, 0);
|
|
31
|
+
}
|
|
32
|
+
context.lineWidth = Math.max(1, Math.round(dpr));
|
|
33
|
+
context.strokeStyle = scene.colours.ends;
|
|
34
|
+
context.stroke();
|
|
35
|
+
context.restore();
|
|
36
|
+
}
|
|
37
|
+
function paintPlaceholders(context, scene) {
|
|
38
|
+
if (scene.pending.length === 0) return;
|
|
39
|
+
const { dpr, height, pixelsPerSecond, startSeconds } = scene;
|
|
40
|
+
const wavelength = placeholderWavelengthPx * dpr;
|
|
41
|
+
const center = height / 2;
|
|
42
|
+
const origin = startSeconds * pixelsPerSecond;
|
|
43
|
+
const waveY = (x) => center - Math.sin(((x + origin) / wavelength + scene.phase) * 2 * Math.PI) * center * placeholderAmplitude;
|
|
44
|
+
context.beginPath();
|
|
45
|
+
for (const [from, to] of scene.pending) {
|
|
46
|
+
const opening = (from - startSeconds) * pixelsPerSecond;
|
|
47
|
+
const closing = (to - startSeconds) * pixelsPerSecond;
|
|
48
|
+
context.moveTo(opening, waveY(opening));
|
|
49
|
+
for (let x = opening + dpr; x < closing; x += dpr) context.lineTo(x, waveY(x));
|
|
50
|
+
context.lineTo(closing, waveY(closing));
|
|
51
|
+
}
|
|
52
|
+
context.lineWidth = Math.max(1, Math.round(dpr));
|
|
53
|
+
context.strokeStyle = scene.colours.placeholder;
|
|
54
|
+
context.stroke();
|
|
55
|
+
}
|
|
56
|
+
function waveFill(context, scene) {
|
|
57
|
+
const { wave, waveEdge } = scene.colours;
|
|
58
|
+
const gradient = context.createLinearGradient(0, 0, 0, scene.height);
|
|
59
|
+
gradient.addColorStop(0, waveEdge);
|
|
60
|
+
gradient.addColorStop(.5, wave);
|
|
61
|
+
gradient.addColorStop(1, waveEdge);
|
|
62
|
+
return gradient;
|
|
63
|
+
}
|
|
64
|
+
function paintWave(context, scene, peaks) {
|
|
65
|
+
const buckets = waveformBuckets(peaks, scene);
|
|
66
|
+
const [first] = buckets;
|
|
67
|
+
if (!first) return;
|
|
68
|
+
const center = scene.height / 2;
|
|
69
|
+
const amplitudePx = center * amplitudeMargin;
|
|
70
|
+
context.fillStyle = waveFill(context, scene);
|
|
71
|
+
context.beginPath();
|
|
72
|
+
context.moveTo(first.x, center);
|
|
73
|
+
for (const bucket of buckets) context.lineTo(bucket.x, center - bucket.high * amplitudePx);
|
|
74
|
+
for (const bucket of buckets.toReversed()) context.lineTo(bucket.x, center - bucket.low * amplitudePx);
|
|
75
|
+
context.closePath();
|
|
76
|
+
context.fill();
|
|
77
|
+
}
|
|
78
|
+
function paintMarkers(context, scene, drawn) {
|
|
79
|
+
const line = Math.max(1, Math.round(scene.dpr));
|
|
80
|
+
for (const { dimmed, kind, start } of drawn.markers) {
|
|
81
|
+
const x = (start - scene.startSeconds) * scene.pixelsPerSecond;
|
|
82
|
+
context.fillStyle = (isKind(kind) ? drawn.kindColours.get(kind) : void 0) ?? scene.colours.marker;
|
|
83
|
+
context.globalAlpha = dimmed === true ? .5 : 1;
|
|
84
|
+
context.fillRect(x - line / 2, 0, line, scene.height);
|
|
85
|
+
}
|
|
86
|
+
context.globalAlpha = 1;
|
|
87
|
+
}
|
|
88
|
+
function paintWaveform(context, scene, drawn) {
|
|
89
|
+
const { dpr, height, pixelsPerSecond, startSeconds, width } = scene;
|
|
90
|
+
const x = (seconds) => (seconds - startSeconds) * pixelsPerSecond;
|
|
91
|
+
const { ends, grid } = scene.colours;
|
|
92
|
+
const line = Math.max(1, Math.round(dpr));
|
|
93
|
+
const [opening, closing] = [x(drawn.range[0]), x(drawn.range[1])];
|
|
94
|
+
const [from, to] = [clamp(opening, 0, width), clamp(closing, 0, width)];
|
|
95
|
+
context.clearRect(0, 0, width, height);
|
|
96
|
+
paintHatch(context, scene, [0, from]);
|
|
97
|
+
paintHatch(context, scene, [to, width]);
|
|
98
|
+
context.fillStyle = grid;
|
|
99
|
+
if (to > from) context.fillRect(from, Math.round((height - line) / 2), to - from, line);
|
|
100
|
+
paintPlaceholders(context, scene);
|
|
101
|
+
if (drawn.peaks) paintWave(context, scene, drawn.peaks);
|
|
102
|
+
context.fillStyle = ends;
|
|
103
|
+
for (const edge of [opening, closing]) context.fillRect(edge - line / 2, 0, line, height);
|
|
104
|
+
paintMarkers(context, scene, drawn);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
//#endregion
|
|
108
|
+
export { paintWaveform, waveformColours };
|
|
109
|
+
//# sourceMappingURL=waveform-scene.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"waveform-scene.js","names":[],"sources":["../../../src/lib/waveform-scene.ts"],"sourcesContent":["import type { View } from '#lib/frame-timeline.ts';\nimport type { WaveformPeaks } from '#lib/waveform-buckets.ts';\n\nimport { isKind } from '#lib/marker-band.ts';\nimport { clamp } from '#lib/math.ts';\nimport { waveformBuckets } from '#lib/waveform-buckets.ts';\n\ntype Colour = keyof typeof waveformColours;\n\ninterface Scene extends View {\n\tcolours: Record<Colour, string>;\n}\n\ninterface Drawn {\n\tkindColours: ReadonlyMap<string, string>;\n\tmarkers: ReadonlyArray<{ dimmed?: boolean; kind?: string; start: number }>;\n\tpeaks: undefined | WaveformPeaks;\n\trange: [number, number];\n}\n\nexport const waveformColours = {\n\tends: '--_sonic-waveform-ends',\n\tgrid: '--_sonic-waveform-grid',\n\tmarker: '--_sonic-waveform-marker',\n\tplaceholder: '--_sonic-waveform-placeholder',\n\twave: '--_sonic-waveform-wave',\n\twaveEdge: '--_sonic-waveform-wave-edge',\n} as const;\n\nconst amplitudeMargin = 0.94;\n\nconst hatchPitchPx = 8;\nconst placeholderWavelengthPx = 48;\nconst placeholderAmplitude = 0.2;\n\nfunction paintHatch(\n\tcontext: CanvasRenderingContext2D,\n\tscene: Scene,\n\t[from, to]: [number, number],\n): void {\n\tif (to <= from) return;\n\n\tconst { dpr, height } = scene;\n\tconst pitch = Math.max(2, Math.round(hatchPitchPx * dpr));\n\tconst offset = scene.startSeconds * scene.pixelsPerSecond;\n\n\tcontext.save();\n\tcontext.beginPath();\n\tcontext.rect(from, 0, to - from, height);\n\tcontext.clip();\n\tcontext.beginPath();\n\tfor (let x = Math.floor((from - height + offset) / pitch) * pitch - offset; x < to; x += pitch) {\n\t\tcontext.moveTo(x, height);\n\t\tcontext.lineTo(x + height, 0);\n\t}\n\tcontext.lineWidth = Math.max(1, Math.round(dpr));\n\tcontext.strokeStyle = scene.colours.ends;\n\tcontext.stroke();\n\tcontext.restore();\n}\n\nfunction paintPlaceholders(context: CanvasRenderingContext2D, scene: Scene): void {\n\tif (scene.pending.length === 0) return;\n\n\tconst { dpr, height, pixelsPerSecond, startSeconds } = scene;\n\tconst wavelength = placeholderWavelengthPx * dpr;\n\tconst center = height / 2;\n\tconst origin = startSeconds * pixelsPerSecond;\n\tconst waveY = (x: number): number =>\n\t\tcenter -\n\t\tMath.sin(((x + origin) / wavelength + scene.phase) * 2 * Math.PI) *\n\t\t\tcenter *\n\t\t\tplaceholderAmplitude;\n\n\tcontext.beginPath();\n\tfor (const [from, to] of scene.pending) {\n\t\tconst opening = (from - startSeconds) * pixelsPerSecond;\n\t\tconst closing = (to - startSeconds) * pixelsPerSecond;\n\n\t\tcontext.moveTo(opening, waveY(opening));\n\t\tfor (let x = opening + dpr; x < closing; x += dpr) context.lineTo(x, waveY(x));\n\t\tcontext.lineTo(closing, waveY(closing));\n\t}\n\tcontext.lineWidth = Math.max(1, Math.round(dpr));\n\tcontext.strokeStyle = scene.colours.placeholder;\n\tcontext.stroke();\n}\n\nfunction waveFill(context: CanvasRenderingContext2D, scene: Scene): CanvasGradient {\n\tconst { wave, waveEdge } = scene.colours;\n\tconst gradient = context.createLinearGradient(0, 0, 0, scene.height);\n\n\tgradient.addColorStop(0, waveEdge);\n\tgradient.addColorStop(0.5, wave);\n\tgradient.addColorStop(1, waveEdge);\n\n\treturn gradient;\n}\n\nfunction paintWave(context: CanvasRenderingContext2D, scene: Scene, peaks: WaveformPeaks): void {\n\tconst buckets = waveformBuckets(peaks, scene);\n\tconst [first] = buckets;\n\tif (!first) return;\n\n\tconst center = scene.height / 2;\n\tconst amplitudePx = center * amplitudeMargin;\n\n\tcontext.fillStyle = waveFill(context, scene);\n\tcontext.beginPath();\n\tcontext.moveTo(first.x, center);\n\tfor (const bucket of buckets) context.lineTo(bucket.x, center - bucket.high * amplitudePx);\n\tfor (const bucket of buckets.toReversed())\n\t\tcontext.lineTo(bucket.x, center - bucket.low * amplitudePx);\n\tcontext.closePath();\n\tcontext.fill();\n}\n\nfunction paintMarkers(context: CanvasRenderingContext2D, scene: Scene, drawn: Drawn): void {\n\tconst line = Math.max(1, Math.round(scene.dpr));\n\n\tfor (const { dimmed, kind, start } of drawn.markers) {\n\t\tconst x = (start - scene.startSeconds) * scene.pixelsPerSecond;\n\n\t\tcontext.fillStyle =\n\t\t\t(isKind(kind) ? drawn.kindColours.get(kind) : undefined) ?? scene.colours.marker;\n\t\tcontext.globalAlpha = dimmed === true ? 0.5 : 1;\n\t\tcontext.fillRect(x - line / 2, 0, line, scene.height);\n\t}\n\tcontext.globalAlpha = 1;\n}\n\nexport function paintWaveform(context: CanvasRenderingContext2D, scene: Scene, drawn: Drawn): void {\n\tconst { dpr, height, pixelsPerSecond, startSeconds, width } = scene;\n\tconst x = (seconds: number): number => (seconds - startSeconds) * pixelsPerSecond;\n\tconst { ends, grid } = scene.colours;\n\tconst line = Math.max(1, Math.round(dpr));\n\tconst [opening, closing] = [x(drawn.range[0]), x(drawn.range[1])];\n\tconst [from, to] = [clamp(opening, 0, width), clamp(closing, 0, width)];\n\n\tcontext.clearRect(0, 0, width, height);\n\tpaintHatch(context, scene, [0, from]);\n\tpaintHatch(context, scene, [to, width]);\n\tcontext.fillStyle = grid;\n\tif (to > from) context.fillRect(from, Math.round((height - line) / 2), to - from, line);\n\tpaintPlaceholders(context, scene);\n\tif (drawn.peaks) paintWave(context, scene, drawn.peaks);\n\t// Scrolling lines sit at fractional x; rounding them judders\n\tcontext.fillStyle = ends;\n\tfor (const edge of [opening, closing]) context.fillRect(edge - line / 2, 0, line, height);\n\tpaintMarkers(context, scene, drawn);\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { clamp } from "./math.js";
|
|
2
|
+
import { capturePointer } from "./pointer-drag.js";
|
|
2
3
|
|
|
3
4
|
//#region src/lib/zoom-gesture.ts
|
|
4
5
|
const wheelRate = .01;
|
|
@@ -6,6 +7,11 @@ const linePx = 16;
|
|
|
6
7
|
const pixelMode = 0;
|
|
7
8
|
const wheelCapPx = 25;
|
|
8
9
|
const minSpanPx = 16;
|
|
10
|
+
const zoomKeys = /* @__PURE__ */ new Map([
|
|
11
|
+
["+", 1],
|
|
12
|
+
["-", -1],
|
|
13
|
+
["=", 1]
|
|
14
|
+
]);
|
|
9
15
|
const zoomKeyFactor = Math.exp(wheelCapPx * wheelRate);
|
|
10
16
|
function wheelFactor(deltaY, deltaMode) {
|
|
11
17
|
const pixels = deltaMode === pixelMode ? deltaY : deltaY * linePx;
|
|
@@ -14,7 +20,97 @@ function wheelFactor(deltaY, deltaMode) {
|
|
|
14
20
|
function pinchFactor(startSpanPx, spanPx) {
|
|
15
21
|
return Math.max(minSpanPx, Math.abs(spanPx)) / Math.max(minSpanPx, Math.abs(startSpanPx));
|
|
16
22
|
}
|
|
23
|
+
function bindPinch(control, options, signal) {
|
|
24
|
+
const touches = /* @__PURE__ */ new Map();
|
|
25
|
+
let pinch;
|
|
26
|
+
let isPinchSpent = false;
|
|
27
|
+
const spanPx = ([first, second]) => (touches.get(second) ?? 0) - (touches.get(first) ?? 0);
|
|
28
|
+
const touchPair = () => {
|
|
29
|
+
const [first, second, third] = touches.keys();
|
|
30
|
+
if (first === void 0 || second === void 0 || third !== void 0) return void 0;
|
|
31
|
+
return [first, second];
|
|
32
|
+
};
|
|
33
|
+
control.addEventListener("pointerdown", (event) => {
|
|
34
|
+
if (event.pointerType !== "touch" || !options.isZoomable() || options.isDisabled()) return;
|
|
35
|
+
touches.set(event.pointerId, event.clientX);
|
|
36
|
+
if (pinch || isPinchSpent) return;
|
|
37
|
+
const pointerIds = touchPair();
|
|
38
|
+
if (!pointerIds) return;
|
|
39
|
+
options.claim();
|
|
40
|
+
capturePointer(control, event.pointerId);
|
|
41
|
+
pinch = {
|
|
42
|
+
pointerIds,
|
|
43
|
+
startSpanPx: spanPx(pointerIds),
|
|
44
|
+
startZoom: options.zoom()
|
|
45
|
+
};
|
|
46
|
+
}, { signal });
|
|
47
|
+
control.addEventListener("pointermove", (event) => {
|
|
48
|
+
if (!touches.has(event.pointerId)) return;
|
|
49
|
+
touches.set(event.pointerId, event.clientX);
|
|
50
|
+
if (!pinch?.pointerIds.includes(event.pointerId)) return;
|
|
51
|
+
options.zoomTo(pinch.startZoom * pinchFactor(pinch.startSpanPx, spanPx(pinch.pointerIds)));
|
|
52
|
+
}, { signal });
|
|
53
|
+
for (const type of ["pointerup", "pointercancel"]) control.addEventListener(type, (event) => {
|
|
54
|
+
if (!touches.delete(event.pointerId)) return;
|
|
55
|
+
if (pinch?.pointerIds.includes(event.pointerId)) {
|
|
56
|
+
pinch = void 0;
|
|
57
|
+
isPinchSpent = true;
|
|
58
|
+
}
|
|
59
|
+
if (touches.size === 0) isPinchSpent = false;
|
|
60
|
+
}, { signal });
|
|
61
|
+
return {
|
|
62
|
+
isPinching: () => pinch !== void 0 || isPinchSpent,
|
|
63
|
+
isTouched: () => touches.size > 0
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function bindWheel(control, options, signal) {
|
|
67
|
+
control.addEventListener("wheel", (event) => {
|
|
68
|
+
if (!event.ctrlKey && !event.metaKey || options.isDisabled()) return;
|
|
69
|
+
event.preventDefault();
|
|
70
|
+
options.zoomTo(options.zoom() * wheelFactor(event.deltaY, event.deltaMode));
|
|
71
|
+
}, {
|
|
72
|
+
passive: false,
|
|
73
|
+
signal
|
|
74
|
+
});
|
|
75
|
+
let startZoom = options.zoom();
|
|
76
|
+
for (const type of ["gesturestart", "gesturechange"]) control.addEventListener(type, (event) => {
|
|
77
|
+
if (options.isDisabled() || options.isTouched()) return;
|
|
78
|
+
event.preventDefault();
|
|
79
|
+
if (type === "gesturestart") startZoom = options.zoom();
|
|
80
|
+
else if ("scale" in event && typeof event.scale === "number") options.zoomTo(startZoom * event.scale);
|
|
81
|
+
}, { signal });
|
|
82
|
+
}
|
|
83
|
+
function bindZoom(control, options, signal) {
|
|
84
|
+
const { isPinching, isTouched } = bindPinch(control, options, signal);
|
|
85
|
+
let wheel;
|
|
86
|
+
const sync = () => {
|
|
87
|
+
wheel?.abort();
|
|
88
|
+
wheel = void 0;
|
|
89
|
+
if (signal.aborted || !options.isZoomable()) return;
|
|
90
|
+
wheel = new AbortController();
|
|
91
|
+
bindWheel(control, {
|
|
92
|
+
...options,
|
|
93
|
+
isTouched
|
|
94
|
+
}, wheel.signal);
|
|
95
|
+
};
|
|
96
|
+
signal.addEventListener("abort", sync, { once: true });
|
|
97
|
+
sync();
|
|
98
|
+
return {
|
|
99
|
+
isPinching,
|
|
100
|
+
sync
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function bindZoomKeys(control, target, signal) {
|
|
104
|
+
control.addEventListener("keydown", (event) => {
|
|
105
|
+
if (!target.isZoomable() || target.isDisabled() || event.target !== control) return;
|
|
106
|
+
if (event.ctrlKey || event.metaKey || event.altKey) return;
|
|
107
|
+
const direction = zoomKeys.get(event.key);
|
|
108
|
+
if (direction === void 0) return;
|
|
109
|
+
event.preventDefault();
|
|
110
|
+
target.zoomTo(target.zoom() * zoomKeyFactor ** direction);
|
|
111
|
+
}, { signal });
|
|
112
|
+
}
|
|
17
113
|
|
|
18
114
|
//#endregion
|
|
19
|
-
export { pinchFactor, wheelFactor, zoomKeyFactor };
|
|
115
|
+
export { bindZoom, bindZoomKeys, pinchFactor, wheelFactor, zoomKeyFactor };
|
|
20
116
|
//# sourceMappingURL=zoom-gesture.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zoom-gesture.js","names":[],"sources":["../../../src/lib/zoom-gesture.ts"],"sourcesContent":["import { clamp } from '#lib/math.ts';\n\nconst wheelRate = 0.01;\nconst linePx = 16;\nconst pixelMode = 0;\n\nconst wheelCapPx = 25;\n\nconst minSpanPx = 16;\n\nexport const zoomKeyFactor = Math.exp(wheelCapPx * wheelRate);\n\nexport function wheelFactor(deltaY: number, deltaMode: number): number {\n\tconst pixels = deltaMode === pixelMode ? deltaY : deltaY * linePx;\n\n\treturn Math.exp(-clamp(pixels, -wheelCapPx, wheelCapPx) * wheelRate);\n}\n\nexport function pinchFactor(startSpanPx: number, spanPx: number): number {\n\treturn Math.max(minSpanPx, Math.abs(spanPx)) / Math.max(minSpanPx, Math.abs(startSpanPx));\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"zoom-gesture.js","names":[],"sources":["../../../src/lib/zoom-gesture.ts"],"sourcesContent":["import { clamp } from '#lib/math.ts';\nimport { capturePointer } from '#lib/pointer-drag.ts';\n\ninterface Pinch {\n\tpointerIds: [number, number];\n\tstartSpanPx: number;\n\tstartZoom: number;\n}\n\ninterface ZoomTarget {\n\tisDisabled: () => boolean;\n\tisZoomable: () => boolean;\n\tzoom: () => number;\n\tzoomTo: (target: number) => void;\n}\n\ninterface ZoomOptions extends ZoomTarget {\n\tclaim: () => void;\n}\n\ninterface Touches {\n\tisPinching: () => boolean;\n\tisTouched: () => boolean;\n}\n\nexport interface ZoomGesture {\n\tisPinching: () => boolean;\n\tsync: () => void;\n}\n\nconst wheelRate = 0.01;\nconst linePx = 16;\nconst pixelMode = 0;\n\nconst wheelCapPx = 25;\n\nconst minSpanPx = 16;\n\nconst zoomKeys = new Map([\n\t['+', 1],\n\t['-', -1],\n\t['=', 1],\n]);\n\nexport const zoomKeyFactor = Math.exp(wheelCapPx * wheelRate);\n\nexport function wheelFactor(deltaY: number, deltaMode: number): number {\n\tconst pixels = deltaMode === pixelMode ? deltaY : deltaY * linePx;\n\n\treturn Math.exp(-clamp(pixels, -wheelCapPx, wheelCapPx) * wheelRate);\n}\n\nexport function pinchFactor(startSpanPx: number, spanPx: number): number {\n\treturn Math.max(minSpanPx, Math.abs(spanPx)) / Math.max(minSpanPx, Math.abs(startSpanPx));\n}\n\nfunction bindPinch(control: HTMLElement, options: ZoomOptions, signal: AbortSignal): Touches {\n\tconst touches = new Map<number, number>();\n\tlet pinch: Pinch | undefined;\n\tlet isPinchSpent = false;\n\n\tconst spanPx = ([first, second]: [number, number]): number =>\n\t\t(touches.get(second) ?? 0) - (touches.get(first) ?? 0);\n\tconst touchPair = (): [number, number] | undefined => {\n\t\tconst [first, second, third] = touches.keys();\n\t\tif (first === undefined || second === undefined || third !== undefined) return undefined;\n\n\t\treturn [first, second];\n\t};\n\n\tcontrol.addEventListener(\n\t\t'pointerdown',\n\t\t(event) => {\n\t\t\tif (event.pointerType !== 'touch' || !options.isZoomable() || options.isDisabled()) return;\n\n\t\t\ttouches.set(event.pointerId, event.clientX);\n\t\t\tif (pinch || isPinchSpent) return;\n\n\t\t\tconst pointerIds = touchPair();\n\t\t\tif (!pointerIds) return;\n\n\t\t\toptions.claim();\n\t\t\tcapturePointer(control, event.pointerId);\n\t\t\tpinch = { pointerIds, startSpanPx: spanPx(pointerIds), startZoom: options.zoom() };\n\t\t},\n\t\t{ signal },\n\t);\n\tcontrol.addEventListener(\n\t\t'pointermove',\n\t\t(event) => {\n\t\t\tif (!touches.has(event.pointerId)) return;\n\n\t\t\ttouches.set(event.pointerId, event.clientX);\n\t\t\tif (!pinch?.pointerIds.includes(event.pointerId)) return;\n\n\t\t\toptions.zoomTo(pinch.startZoom * pinchFactor(pinch.startSpanPx, spanPx(pinch.pointerIds)));\n\t\t},\n\t\t{ signal },\n\t);\n\tfor (const type of ['pointerup', 'pointercancel'] as const) {\n\t\tcontrol.addEventListener(\n\t\t\ttype,\n\t\t\t(event) => {\n\t\t\t\tif (!touches.delete(event.pointerId)) return;\n\n\t\t\t\tif (pinch?.pointerIds.includes(event.pointerId)) {\n\t\t\t\t\tpinch = undefined;\n\t\t\t\t\tisPinchSpent = true;\n\t\t\t\t}\n\t\t\t\tif (touches.size === 0) isPinchSpent = false;\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t}\n\n\treturn {\n\t\tisPinching: () => pinch !== undefined || isPinchSpent,\n\t\tisTouched: () => touches.size > 0,\n\t};\n}\n\nfunction bindWheel(\n\tcontrol: HTMLElement,\n\toptions: Pick<Touches, 'isTouched'> & ZoomTarget,\n\tsignal: AbortSignal,\n): void {\n\t// Chromium cannot cancel a wheel heard only on the `display: contents` host\n\tcontrol.addEventListener(\n\t\t'wheel',\n\t\t(event) => {\n\t\t\tif ((!event.ctrlKey && !event.metaKey) || options.isDisabled()) return;\n\n\t\t\tevent.preventDefault();\n\t\t\toptions.zoomTo(options.zoom() * wheelFactor(event.deltaY, event.deltaMode));\n\t\t},\n\t\t{ passive: false, signal },\n\t);\n\n\tlet startZoom = options.zoom();\n\n\t// Safari sends a trackpad pinch as gesture events, never as a ctrl wheel\n\tfor (const type of ['gesturestart', 'gesturechange']) {\n\t\tcontrol.addEventListener(\n\t\t\ttype,\n\t\t\t(event) => {\n\t\t\t\tif (options.isDisabled() || options.isTouched()) return;\n\n\t\t\t\tevent.preventDefault();\n\t\t\t\tif (type === 'gesturestart') startZoom = options.zoom();\n\t\t\t\telse if ('scale' in event && typeof event.scale === 'number') {\n\t\t\t\t\toptions.zoomTo(startZoom * event.scale);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t}\n}\n\nexport function bindZoom(\n\tcontrol: HTMLElement,\n\toptions: ZoomOptions,\n\tsignal: AbortSignal,\n): ZoomGesture {\n\tconst { isPinching, isTouched } = bindPinch(control, options, signal);\n\tlet wheel: AbortController | undefined;\n\n\t// The wheel listener is not passive, so it is bound only while zooming is on\n\tconst sync = (): void => {\n\t\twheel?.abort();\n\t\twheel = undefined;\n\t\tif (signal.aborted || !options.isZoomable()) return;\n\n\t\twheel = new AbortController();\n\t\tbindWheel(control, { ...options, isTouched }, wheel.signal);\n\t};\n\n\tsignal.addEventListener('abort', sync, { once: true });\n\tsync();\n\n\treturn { isPinching, sync };\n}\n\nexport function bindZoomKeys(control: HTMLElement, target: ZoomTarget, signal: AbortSignal): void {\n\tcontrol.addEventListener(\n\t\t'keydown',\n\t\t(event) => {\n\t\t\tif (!target.isZoomable() || target.isDisabled() || event.target !== control) return;\n\t\t\tif (event.ctrlKey || event.metaKey || event.altKey) return;\n\n\t\t\tconst direction = zoomKeys.get(event.key);\n\t\t\tif (direction === undefined) return;\n\n\t\t\tevent.preventDefault();\n\t\t\ttarget.zoomTo(target.zoom() * zoomKeyFactor ** direction);\n\t\t},\n\t\t{ signal },\n\t);\n}\n"],"mappings":"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"}
|
package/dist/skins/amber.css
CHANGED
package/dist/skins/ivory.css
CHANGED
package/dist/skins/lime.css
CHANGED
package/dist/skins/slate.css
CHANGED
package/dist/styles/button.css
CHANGED
|
@@ -31,22 +31,36 @@
|
|
|
31
31
|
overflow: hidden;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
sonic-button:not(:defined, [hidden]):has(> :not(
|
|
34
|
+
sonic-button:not(:defined, [hidden]):has(> :not(.sonic-led)) {
|
|
35
35
|
inline-size: max-content;
|
|
36
36
|
min-inline-size: calc(var(--_sonic-button-size) * var(--_sonic-button-aspect-ratio));
|
|
37
|
-
padding-inline: calc(var(--_sonic-button-size) * var(--sonic-button-padding-ratio, 0.25));
|
|
38
37
|
white-space: nowrap;
|
|
39
38
|
}
|
|
40
39
|
|
|
40
|
+
sonic-button:not(:defined, [hidden]):has(> :not(svg, .sonic-led)) {
|
|
41
|
+
padding-inline: calc(var(--_sonic-button-size) * var(--sonic-button-padding-ratio, 0.25));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
:where(sonic-button:not(:defined)) > svg {
|
|
45
|
+
display: block;
|
|
46
|
+
inline-size: auto;
|
|
47
|
+
block-size: calc(var(--_sonic-button-size) * var(--sonic-button-icon-ratio, 0.5));
|
|
48
|
+
aspect-ratio: auto 1;
|
|
49
|
+
}
|
|
50
|
+
|
|
41
51
|
.sonic-button {
|
|
42
52
|
--_sonic-button-gap-ratio: var(--sonic-button-gap-ratio, 0);
|
|
43
53
|
--_sonic-button-radius-ratio: var(--sonic-button-radius-ratio, 0.2);
|
|
44
54
|
--_sonic-button-bevel-ratio: var(--sonic-button-bevel-ratio, 0.075);
|
|
45
55
|
--_sonic-button-face-radius-ratio: var(--sonic-button-face-radius-ratio, 0.15);
|
|
56
|
+
--_sonic-button-face-radius-own: calc(
|
|
57
|
+
var(--_sonic-button-size) * var(--sonic-button-face-radius-ratio)
|
|
58
|
+
);
|
|
46
59
|
--_sonic-button-icon-ratio: var(--sonic-button-icon-ratio, 0.5);
|
|
47
60
|
--_sonic-button-led-ratio: var(--sonic-button-led-ratio, 0.2);
|
|
48
61
|
--_sonic-button-led-icon-ratio: var(--sonic-button-led-icon-ratio, 0.35);
|
|
49
62
|
--_sonic-button-font-ratio: var(--sonic-button-font-ratio, 0.34);
|
|
63
|
+
--_sonic-button-font-own: calc(var(--_sonic-button-size) * var(--sonic-button-font-ratio));
|
|
50
64
|
--_sonic-button-padding-ratio: var(--sonic-button-padding-ratio, 0.25);
|
|
51
65
|
--_sonic-button-depth-ratio: var(--sonic-button-depth-ratio, calc(0.03 * var(--_sonic-relief)));
|
|
52
66
|
--_sonic-button-press-scale: var(--sonic-button-press-scale, 0.985);
|
|
@@ -55,7 +69,11 @@
|
|
|
55
69
|
var(--_sonic-button-press-scale)
|
|
56
70
|
);
|
|
57
71
|
--_sonic-unit: calc(var(--_sonic-button-size) / 32);
|
|
58
|
-
--_sonic-button-
|
|
72
|
+
--_sonic-button-radius-own: calc(var(--_sonic-button-size) * var(--sonic-button-radius-ratio));
|
|
73
|
+
--_sonic-button-corner: var(
|
|
74
|
+
--_sonic-button-radius-own,
|
|
75
|
+
var(--sonic-radius, calc(var(--_sonic-button-size) * var(--_sonic-button-radius-ratio)))
|
|
76
|
+
);
|
|
59
77
|
--_sonic-button-gap: calc(var(--_sonic-button-size) * var(--_sonic-button-gap-ratio));
|
|
60
78
|
--_sonic-keycap-depth: calc(var(--_sonic-button-size) * var(--_sonic-button-depth-ratio));
|
|
61
79
|
|
|
@@ -71,11 +89,11 @@
|
|
|
71
89
|
border: 0;
|
|
72
90
|
border-radius: var(--_sonic-button-corner);
|
|
73
91
|
box-shadow: var(--_sonic-well);
|
|
74
|
-
transition: color
|
|
92
|
+
transition: color var(--_sonic-fade-duration) ease-out;
|
|
75
93
|
}
|
|
76
94
|
|
|
77
95
|
/* An `auto` width stretches in a column flex or grid parent */
|
|
78
|
-
.sonic-button:where(:has(> .sonic-button-cap > :not(
|
|
96
|
+
.sonic-button:where(:has(> .sonic-button-cap > :not(.sonic-led))) {
|
|
79
97
|
inline-size: max-content;
|
|
80
98
|
min-inline-size: calc(var(--_sonic-button-size) * var(--_sonic-button-aspect-ratio));
|
|
81
99
|
}
|
|
@@ -222,8 +240,18 @@
|
|
|
222
240
|
.sonic-button-cap {
|
|
223
241
|
--_sonic-keycap-corner: max(0px, var(--_sonic-button-corner) - var(--_sonic-button-gap));
|
|
224
242
|
--_sonic-keycap-bevel: calc(var(--_sonic-button-size) * var(--_sonic-button-bevel-ratio));
|
|
225
|
-
|
|
226
|
-
|
|
243
|
+
|
|
244
|
+
/* Invalid without the shared radius; with it the face follows the cap's corner, as an option's does */
|
|
245
|
+
--_sonic-button-face-follow: max(
|
|
246
|
+
0px,
|
|
247
|
+
var(--_sonic-keycap-corner) - var(--_sonic-keycap-bevel) + 0 * var(--sonic-radius)
|
|
248
|
+
);
|
|
249
|
+
--_sonic-keycap-face-corner: var(
|
|
250
|
+
--_sonic-button-face-radius-own,
|
|
251
|
+
var(
|
|
252
|
+
--_sonic-button-face-follow,
|
|
253
|
+
calc(var(--_sonic-button-size) * var(--_sonic-button-face-radius-ratio))
|
|
254
|
+
)
|
|
227
255
|
);
|
|
228
256
|
|
|
229
257
|
position: absolute;
|
|
@@ -244,14 +272,21 @@
|
|
|
244
272
|
|
|
245
273
|
& > :not(svg, .sonic-led) {
|
|
246
274
|
padding-inline: calc(var(--_sonic-button-size) * var(--_sonic-button-padding-ratio));
|
|
247
|
-
font-size:
|
|
275
|
+
font-size: var(
|
|
276
|
+
--_sonic-button-font-own,
|
|
277
|
+
var(
|
|
278
|
+
--sonic-legend-font-size,
|
|
279
|
+
calc(var(--_sonic-button-size) * var(--_sonic-button-font-ratio))
|
|
280
|
+
)
|
|
281
|
+
);
|
|
248
282
|
line-height: 1;
|
|
249
283
|
white-space: nowrap;
|
|
250
284
|
}
|
|
251
285
|
|
|
252
286
|
& > svg {
|
|
253
|
-
inline-size:
|
|
287
|
+
inline-size: auto;
|
|
254
288
|
block-size: calc(var(--_sonic-button-size) * var(--_sonic-button-icon-ratio));
|
|
289
|
+
aspect-ratio: auto 1;
|
|
255
290
|
mask-image: linear-gradient(
|
|
256
291
|
var(--_sonic-light-fall),
|
|
257
292
|
#000 15%,
|
|
@@ -261,7 +296,7 @@
|
|
|
261
296
|
}
|
|
262
297
|
}
|
|
263
298
|
|
|
264
|
-
.sonic-button-cap:has(> :not(
|
|
299
|
+
.sonic-button-cap:has(> :not(.sonic-led)) {
|
|
265
300
|
position: relative;
|
|
266
301
|
inset: auto;
|
|
267
302
|
block-size: calc(var(--_sonic-button-size) - 2 * var(--_sonic-button-gap));
|
|
@@ -269,7 +304,6 @@
|
|
|
269
304
|
}
|
|
270
305
|
|
|
271
306
|
.sonic-button-cap:has(> .sonic-led) > svg {
|
|
272
|
-
inline-size: calc(var(--_sonic-button-size) * var(--_sonic-button-led-icon-ratio));
|
|
273
307
|
block-size: calc(var(--_sonic-button-size) * var(--_sonic-button-led-icon-ratio));
|
|
274
308
|
}
|
|
275
309
|
|
package/dist/styles/dial.css
CHANGED
|
@@ -313,10 +313,11 @@
|
|
|
313
313
|
&::before {
|
|
314
314
|
inset: 0;
|
|
315
315
|
background: repeating-conic-gradient(
|
|
316
|
-
rgb(
|
|
317
|
-
rgb(
|
|
316
|
+
rgb(from var(--_sonic-shade) r g b / calc(0.3 * var(--_sonic-relief))) 0,
|
|
317
|
+
rgb(from var(--_sonic-shine) r g b / calc(0.12 * var(--_sonic-relief)))
|
|
318
318
|
calc(var(--_sonic-dial-ridge-angle) / 2),
|
|
319
|
-
rgb(
|
|
319
|
+
rgb(from var(--_sonic-shade) r g b / calc(0.3 * var(--_sonic-relief)))
|
|
320
|
+
var(--_sonic-dial-ridge-angle)
|
|
320
321
|
);
|
|
321
322
|
rotate: var(--_sonic-dial-angle);
|
|
322
323
|
}
|
|
@@ -329,15 +330,15 @@
|
|
|
329
330
|
calc(
|
|
330
331
|
var(--_sonic-dial-face-drift) * var(--_sonic-dial-angle) - var(--_sonic-light-tilt)
|
|
331
332
|
),
|
|
332
|
-
rgb(
|
|
333
|
+
rgb(from var(--_sonic-shine) r g b / calc(0.16 * var(--_sonic-relief))),
|
|
333
334
|
transparent 12%,
|
|
334
|
-
rgb(
|
|
335
|
+
rgb(from var(--_sonic-shade) r g b / calc(0.1 * var(--_sonic-relief))) 25%,
|
|
335
336
|
transparent 38%,
|
|
336
|
-
rgb(
|
|
337
|
+
rgb(from var(--_sonic-shine) r g b / calc(0.12 * var(--_sonic-relief))) 50%,
|
|
337
338
|
transparent 62%,
|
|
338
|
-
rgb(
|
|
339
|
+
rgb(from var(--_sonic-shade) r g b / calc(0.1 * var(--_sonic-relief))) 75%,
|
|
339
340
|
transparent 88%,
|
|
340
|
-
rgb(
|
|
341
|
+
rgb(from var(--_sonic-shine) r g b / calc(0.16 * var(--_sonic-relief)))
|
|
341
342
|
),
|
|
342
343
|
var(--_sonic-face);
|
|
343
344
|
box-shadow: var(--_sonic-face-shadow);
|
|
@@ -368,7 +369,7 @@
|
|
|
368
369
|
background: var(--_sonic-ink);
|
|
369
370
|
border-radius: calc(var(--_sonic-dial-indicator-width) / 2);
|
|
370
371
|
box-shadow: inset 0 0 calc(0.75 * var(--_sonic-unit))
|
|
371
|
-
rgb(
|
|
372
|
+
rgb(from var(--_sonic-shade) r g b / calc(0.55 * var(--_sonic-relief)));
|
|
372
373
|
clip-path: shape(
|
|
373
374
|
from 0 100%,
|
|
374
375
|
line to calc(50% - var(--_sonic-dial-indicator-tip)) var(--_sonic-dial-indicator-tip),
|
package/dist/styles/envelope.css
CHANGED
|
@@ -32,7 +32,13 @@
|
|
|
32
32
|
--_sonic-envelope-curve-ratio: var(--sonic-envelope-curve-ratio, 0.08);
|
|
33
33
|
--_sonic-unit: calc(var(--_sonic-envelope-size) / 64);
|
|
34
34
|
--_sonic-envelope-inset: calc(var(--_sonic-envelope-size) * var(--_sonic-envelope-inset-ratio));
|
|
35
|
-
--_sonic-
|
|
35
|
+
--_sonic-envelope-radius-own: calc(
|
|
36
|
+
var(--_sonic-envelope-size) * var(--sonic-envelope-radius-ratio)
|
|
37
|
+
);
|
|
38
|
+
--_sonic-glass-radius: var(
|
|
39
|
+
--_sonic-envelope-radius-own,
|
|
40
|
+
var(--sonic-radius, calc(var(--_sonic-envelope-size) * var(--_sonic-envelope-radius-ratio)))
|
|
41
|
+
);
|
|
36
42
|
|
|
37
43
|
inline-size: calc(var(--_sonic-envelope-size) * var(--_sonic-envelope-aspect-ratio));
|
|
38
44
|
block-size: var(--_sonic-envelope-size);
|
|
@@ -124,9 +130,9 @@
|
|
|
124
130
|
var(--_sonic-point-halo),
|
|
125
131
|
var(--_sonic-focus-shadow, 0 0 transparent);
|
|
126
132
|
transition:
|
|
127
|
-
background-color
|
|
128
|
-
border-color
|
|
129
|
-
box-shadow
|
|
133
|
+
background-color var(--_sonic-fade-duration) ease-out,
|
|
134
|
+
border-color var(--_sonic-fade-duration) ease-out,
|
|
135
|
+
box-shadow var(--_sonic-fade-duration) ease-out;
|
|
130
136
|
}
|
|
131
137
|
|
|
132
138
|
.sonic-envelope-handle {
|
package/dist/styles/led.css
CHANGED
|
@@ -117,7 +117,11 @@
|
|
|
117
117
|
&::after {
|
|
118
118
|
background: radial-gradient(
|
|
119
119
|
closest-side,
|
|
120
|
-
color-mix(
|
|
120
|
+
color-mix(
|
|
121
|
+
in oklab,
|
|
122
|
+
var(--_sonic-lit) calc(100% - 45% * var(--_sonic-relief)),
|
|
123
|
+
var(--_sonic-shine)
|
|
124
|
+
),
|
|
121
125
|
var(--_sonic-lit)
|
|
122
126
|
);
|
|
123
127
|
}
|
|
@@ -13,9 +13,10 @@
|
|
|
13
13
|
);
|
|
14
14
|
--_sonic-arc-shade: radial-gradient(
|
|
15
15
|
closest-side,
|
|
16
|
-
rgb(
|
|
16
|
+
rgb(from var(--_sonic-shade) r g b / calc(0.55 * var(--_sonic-relief)))
|
|
17
|
+
calc(100% - var(--_sonic-arc-width)),
|
|
17
18
|
transparent calc(100% - var(--_sonic-arc-width) * 0.4),
|
|
18
|
-
rgb(
|
|
19
|
+
rgb(from var(--_sonic-shade) r g b / calc(0.25 * var(--_sonic-relief))) 100%
|
|
19
20
|
);
|
|
20
21
|
}
|
|
21
22
|
}
|
|
@@ -23,36 +23,57 @@
|
|
|
23
23
|
--_sonic-lit-disabled: color-mix(in oklab, var(--_sonic-ink) 25%, var(--_sonic-unlit));
|
|
24
24
|
--_sonic-skirt: linear-gradient(
|
|
25
25
|
var(--_sonic-light-fall),
|
|
26
|
-
color-mix(
|
|
27
|
-
|
|
26
|
+
color-mix(
|
|
27
|
+
in oklab,
|
|
28
|
+
var(--_sonic-cap) calc(100% - 30% * var(--_sonic-relief)),
|
|
29
|
+
var(--_sonic-shine)
|
|
30
|
+
),
|
|
31
|
+
color-mix(
|
|
32
|
+
in oklab,
|
|
33
|
+
var(--_sonic-cap) calc(100% - 45% * var(--_sonic-relief)),
|
|
34
|
+
var(--_sonic-shade)
|
|
35
|
+
)
|
|
28
36
|
);
|
|
29
37
|
--_sonic-face: linear-gradient(
|
|
30
38
|
var(--_sonic-light-fall),
|
|
31
|
-
color-mix(
|
|
32
|
-
|
|
39
|
+
color-mix(
|
|
40
|
+
in oklab,
|
|
41
|
+
var(--_sonic-cap) calc(100% - 15% * var(--_sonic-relief)),
|
|
42
|
+
var(--_sonic-shade)
|
|
43
|
+
),
|
|
44
|
+
color-mix(
|
|
45
|
+
in oklab,
|
|
46
|
+
var(--_sonic-cap) calc(100% - 10% * var(--_sonic-relief)),
|
|
47
|
+
var(--_sonic-shine)
|
|
48
|
+
)
|
|
33
49
|
);
|
|
34
50
|
--_sonic-sheen: linear-gradient(
|
|
35
51
|
105deg,
|
|
36
52
|
transparent 20%,
|
|
37
|
-
rgb(
|
|
53
|
+
rgb(from var(--_sonic-shine) r g b / calc(0.1 * var(--_sonic-relief))) 45%,
|
|
38
54
|
transparent 55%,
|
|
39
|
-
rgb(
|
|
55
|
+
rgb(from var(--_sonic-shade) r g b / calc(0.06 * var(--_sonic-relief))) 80%
|
|
40
56
|
);
|
|
41
57
|
--_sonic-press-transition:
|
|
42
|
-
scale
|
|
43
|
-
|
|
58
|
+
scale var(--_sonic-press-duration) cubic-bezier(0.4, 0, 0.2, 1),
|
|
59
|
+
translate var(--_sonic-press-duration) cubic-bezier(0.4, 0, 0.2, 1),
|
|
60
|
+
box-shadow var(--_sonic-press-duration) cubic-bezier(0.4, 0, 0.2, 1);
|
|
44
61
|
--_sonic-face-shadow:
|
|
45
62
|
inset var(--_sonic-cast-x) var(--_sonic-cast-y) calc(1.5 * var(--_sonic-unit))
|
|
46
|
-
rgb(
|
|
63
|
+
rgb(from var(--_sonic-shade) r g b / calc(0.35 * var(--_sonic-relief))),
|
|
47
64
|
calc(0.5 * var(--_sonic-cast-x)) calc(0.5 * var(--_sonic-cast-y)) var(--_sonic-unit)
|
|
48
|
-
rgb(
|
|
65
|
+
rgb(from var(--_sonic-shine) r g b / calc(0.12 * var(--_sonic-relief)));
|
|
49
66
|
--_sonic-rim-width: max(1px, round(0.75 * var(--_sonic-unit), var(--_sonic-snap)));
|
|
50
67
|
--_sonic-rim: 0 0 0 var(--_sonic-rim-width)
|
|
51
68
|
var(
|
|
52
69
|
--sonic-cap-edge,
|
|
53
|
-
color-mix(
|
|
70
|
+
color-mix(
|
|
71
|
+
in oklab,
|
|
72
|
+
var(--_sonic-cap) calc(100% - 60% * var(--_sonic-relief)),
|
|
73
|
+
var(--_sonic-shade)
|
|
74
|
+
)
|
|
54
75
|
);
|
|
55
|
-
--_sonic-drop-shade: rgb(
|
|
76
|
+
--_sonic-drop-shade: rgb(from var(--_sonic-shade) r g b / calc(0.65 * var(--_sonic-relief)));
|
|
56
77
|
--_sonic-focus-shadow: 0 0 transparent;
|
|
57
78
|
--_sonic-focus-glow: 0 0 max(4px, 3 * var(--_sonic-unit)) max(1px, 0.5 * var(--_sonic-unit))
|
|
58
79
|
color-mix(in oklab, var(--_sonic-focus) calc(60% * var(--_sonic-focus-strength)), transparent);
|