@xsynaptic/sonic-ui 0.3.0 → 0.4.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/dist/default/elements/dial.js +5 -3
- package/dist/default/elements/key.js +29 -4
- package/dist/default/elements/meter.js +63 -9
- package/dist/default/elements/number.js +1 -1
- package/dist/default/elements/range-element.js +134 -21
- package/dist/default/elements/slider.js +49 -3
- package/dist/default/lib/detent.js +17 -0
- package/dist/default/lib/math.js +16 -0
- package/dist/default/lib/number-list.js +14 -0
- package/dist/default/lib/taper.js +17 -7
- package/dist/dev/elements/dial.js +5 -3
- package/dist/dev/elements/dial.js.map +1 -1
- package/dist/dev/elements/key.d.ts +4 -0
- package/dist/dev/elements/key.js +29 -4
- package/dist/dev/elements/key.js.map +1 -1
- package/dist/dev/elements/meter.d.ts +6 -0
- package/dist/dev/elements/meter.js +63 -9
- package/dist/dev/elements/meter.js.map +1 -1
- package/dist/dev/elements/number.js +1 -1
- package/dist/dev/elements/range-element.d.ts +8 -0
- package/dist/dev/elements/range-element.js +134 -21
- package/dist/dev/elements/range-element.js.map +1 -1
- package/dist/dev/elements/slider.d.ts +6 -0
- package/dist/dev/elements/slider.js +49 -3
- package/dist/dev/elements/slider.js.map +1 -1
- package/dist/dev/lib/detent.js +18 -0
- package/dist/dev/lib/detent.js.map +1 -0
- package/dist/dev/lib/math.js +17 -0
- package/dist/dev/lib/math.js.map +1 -0
- package/dist/dev/lib/number-list.js +15 -0
- package/dist/dev/lib/number-list.js.map +1 -0
- package/dist/dev/lib/taper.js +17 -7
- package/dist/dev/lib/taper.js.map +1 -1
- package/dist/styles/dial.css +43 -3
- package/dist/styles/key.css +60 -15
- package/dist/styles/led.css +8 -1
- package/dist/styles/material.css +50 -1
- package/dist/styles/meter.css +101 -5
- package/dist/styles/segmented.css +2 -7
- package/dist/styles/slider.css +94 -32
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slider.js","names":[],"sources":["../../../src/elements/slider.ts"],"sourcesContent":["import type { RangeAxis } from '#elements/range-element.ts';\n\nimport { SonicRangeElement } from '#elements/range-element.ts';\nimport { requireChild, template } from '#lib/render.ts';\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sonic-slider': SonicSlider;\n\t}\n}\n\ninterface SliderAxis extends RangeAxis {\n\t// The cap's centre at the minimum, on the same scale as `position`\n\tstartPx: number;\n}\n\nconst renderSlider = template(\n\t/* HTML */ `\n\t\t<div class=\"sonic-slider\" role=\"slider\" tabindex=\"0\">\n\t\t\t<div class=\"sonic-slider-marks\"></div>\n\t\t\t<div class=\"sonic-slider-groove\"></div>\n\t\t\t<div class=\"sonic-slider-modulation\"></div>\n\t\t\t<div class=\"sonic-slider-cap\"></div>\n\t\t\t<div class=\"sonic-slider-readout\" popover=\"manual\">\n\t\t\t\t<span></span>\n\t\t\t\t<input\n\t\t\t\t\tautocomplete=\"off\"\n\t\t\t\t\tclass=\"sonic-slider-entry\"\n\t\t\t\t\tenterkeyhint=\"done\"\n\t\t\t\t\thidden\n\t\t\t\t\tspellcheck=\"false\"\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</div>\n\t`,\n\tHTMLDivElement,\n);\n\nexport class SonicSlider extends SonicRangeElement {\n\tstatic override readonly observedAttributes = [\n\t\t...SonicRangeElement.observedAttributes,\n\t\t'modulation',\n\t\t'orientation',\n\t];\n\n\t// Named for the absent attribute, as `input.type` reads `text`\n\tget groovePress(): 'jump' | 'none' {\n\t\treturn this.getAttribute('groove-press') === 'none' ? 'none' : 'jump';\n\t}\n\n\tset groovePress(gesture: 'jump' | 'none' | undefined) {\n\t\tthis.reflect('groove-press', gesture);\n\t}\n\n\tget modulation(): number {\n\t\treturn this.numberAttribute('modulation', 0);\n\t}\n\n\tset modulation(amount: number | undefined) {\n\t\tthis.reflect('modulation', amount);\n\t}\n\n\tget orientation(): 'horizontal' | 'vertical' {\n\t\treturn this.getAttribute('orientation') === 'vertical' ? 'vertical' : 'horizontal';\n\t}\n\n\tset orientation(direction: 'horizontal' | 'vertical' | undefined) {\n\t\tthis.reflect('orientation', direction);\n\t}\n\n\treadonly #slider = renderSlider();\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties('groovePress', 'modulation', 'orientation');\n\t\tsuper.connectedCallback();\n\t}\n\n\tprotected connect(signal: AbortSignal): void {\n\t\tconst slider = this.#slider;\n\t\tconst cap = requireChild(slider, '.sonic-slider-cap', HTMLDivElement);\n\n\t\tthis.
|
|
1
|
+
{"version":3,"file":"slider.js","names":[],"sources":["../../../src/elements/slider.ts"],"sourcesContent":["import type { RangeAxis } from '#elements/range-element.ts';\n\nimport { SonicRangeElement } from '#elements/range-element.ts';\nimport { requireChild, template } from '#lib/render.ts';\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sonic-slider': SonicSlider;\n\t}\n}\n\ninterface SliderAxis extends RangeAxis {\n\t// The cap's centre at the minimum, on the same scale as `position`\n\tstartPx: number;\n}\n\nexport type BufferedRanges = Iterable<readonly [number, number]> | TimeRanges;\n\nfunction readRanges(ranges: BufferedRanges): Array<[number, number]> {\n\tif ('start' in ranges) {\n\t\treturn Array.from({ length: ranges.length }, (_entry, index) => [\n\t\t\tranges.start(index),\n\t\t\tranges.end(index),\n\t\t]);\n\t}\n\n\treturn [...ranges].map(([start, end]) => [start, end]);\n}\n\n// Along the groove, which runs past the travel by half its width at each end\nfunction grooveStop(fraction: number): string {\n\tif (fraction <= 0) return '0%';\n\tif (fraction >= 1) return '100%';\n\n\treturn `calc(${String(fraction)} * var(--_sonic-slider-travel) + var(--_sonic-slider-groove) / 2)`;\n}\n\nconst renderSlider = template(\n\t/* HTML */ `\n\t\t<div class=\"sonic-slider\" role=\"slider\" tabindex=\"0\">\n\t\t\t<div class=\"sonic-slider-scale\" aria-hidden=\"true\"></div>\n\t\t\t<div class=\"sonic-slider-marks\"></div>\n\t\t\t<div class=\"sonic-slider-groove\"></div>\n\t\t\t<div class=\"sonic-slider-modulation\"></div>\n\t\t\t<div class=\"sonic-slider-cap\"></div>\n\t\t\t<div class=\"sonic-slider-readout\" popover=\"manual\">\n\t\t\t\t<span></span>\n\t\t\t\t<input\n\t\t\t\t\tautocomplete=\"off\"\n\t\t\t\t\tclass=\"sonic-slider-entry\"\n\t\t\t\t\tenterkeyhint=\"done\"\n\t\t\t\t\thidden\n\t\t\t\t\tspellcheck=\"false\"\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</div>\n\t`,\n\tHTMLDivElement,\n);\n\nexport class SonicSlider extends SonicRangeElement {\n\tstatic override readonly observedAttributes = [\n\t\t...SonicRangeElement.observedAttributes,\n\t\t'modulation',\n\t\t'orientation',\n\t\t'spring',\n\t];\n\n\tget buffered(): Array<[number, number]> {\n\t\treturn this.#buffered.map(([start, end]) => [start, end]);\n\t}\n\n\tset buffered(ranges: BufferedRanges | undefined) {\n\t\tthis.#buffered = ranges\n\t\t\t? readRanges(ranges).toSorted((first, second) => first[0] - second[0])\n\t\t\t: [];\n\t\tthis.render();\n\t}\n\n\t// Named for the absent attribute, as `input.type` reads `text`\n\tget groovePress(): 'jump' | 'none' {\n\t\treturn this.getAttribute('groove-press') === 'none' ? 'none' : 'jump';\n\t}\n\n\tset groovePress(gesture: 'jump' | 'none' | undefined) {\n\t\tthis.reflect('groove-press', gesture);\n\t}\n\n\tget modulation(): number {\n\t\treturn this.numberAttribute('modulation', 0);\n\t}\n\n\tset modulation(amount: number | undefined) {\n\t\tthis.reflect('modulation', amount);\n\t}\n\n\tget orientation(): 'horizontal' | 'vertical' {\n\t\treturn this.getAttribute('orientation') === 'vertical' ? 'vertical' : 'horizontal';\n\t}\n\n\tset orientation(direction: 'horizontal' | 'vertical' | undefined) {\n\t\tthis.reflect('orientation', direction);\n\t}\n\n\tget spring(): boolean {\n\t\treturn this.hasAttribute('spring');\n\t}\n\n\tset spring(isSpring: boolean) {\n\t\tthis.reflect('spring', isSpring);\n\t}\n\n\t#buffered: Array<[number, number]> = [];\n\n\treadonly #slider = renderSlider();\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties('buffered', 'groovePress', 'modulation', 'orientation', 'spring');\n\t\tsuper.connectedCallback();\n\t}\n\n\tprotected connect(signal: AbortSignal): void {\n\t\tconst slider = this.#slider;\n\t\tconst cap = requireChild(slider, '.sonic-slider-cap', HTMLDivElement);\n\n\t\tthis.bindScale(slider, requireChild(slider, '.sonic-slider-scale', HTMLDivElement), signal);\n\t\tthis.render();\n\t\tthis.checkStyles(slider, 'slider.css');\n\t\tthis.bindGestures(slider, signal, (event) => {\n\t\t\tconst axis = this.#axis(slider, cap);\n\t\t\tif (event.target instanceof Node && cap.contains(event.target)) return axis;\n\n\t\t\tif (this.groovePress === 'none') return;\n\n\t\t\tthis.input(this.valueAt((axis.position(event) - axis.startPx) / axis.travelPx));\n\n\t\t\treturn axis;\n\t\t});\n\t}\n\n\tprotected override focusTarget(): HTMLElement {\n\t\treturn this.#slider;\n\t}\n\n\tprotected render(): void {\n\t\tconst slider = this.#slider;\n\t\tconst positions = this.positions();\n\t\tconst [modulationFrom, modulationTo] = this.modulationFractions(this.modulation);\n\n\t\tslider.style.setProperty('--_sonic-slider-value', String(this.fraction(this.value)));\n\t\tslider.style.setProperty('--_sonic-slider-origin', String(this.originFraction()));\n\t\tslider.style.setProperty('--_sonic-slider-modulation-from', String(modulationFrom));\n\t\tslider.style.setProperty('--_sonic-slider-modulation-to', String(modulationTo));\n\t\tif (positions === undefined) slider.style.removeProperty('--_sonic-slider-positions');\n\t\telse slider.style.setProperty('--_sonic-slider-positions', String(positions));\n\t\tthis.#renderBuffered(slider);\n\t\tthis.renderScale();\n\t\tthis.renderAria(slider, this.orientation);\n\t}\n\n\tprotected override springTarget(): number | undefined {\n\t\treturn this.spring ? this.restValue() : undefined;\n\t}\n\n\t#axis(slider: HTMLElement, cap: HTMLElement): SliderAxis {\n\t\tconst track = slider.getBoundingClientRect();\n\t\tconst capBox = cap.getBoundingClientRect();\n\n\t\tif (this.orientation === 'vertical') {\n\t\t\treturn {\n\t\t\t\tposition: (event) => -event.clientY,\n\t\t\t\tstartPx: capBox.height / 2 - track.bottom,\n\t\t\t\ttravelPx: Math.max(1, track.height - capBox.height),\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tposition: (event) => event.clientX,\n\t\t\tstartPx: track.left + capBox.width / 2,\n\t\t\ttravelPx: Math.max(1, track.width - capBox.width),\n\t\t};\n\t}\n\n\t// Hard stops in one gradient, so any number of ranges costs one layer\n\t#renderBuffered(slider: HTMLElement): void {\n\t\tif (this.#buffered.length === 0) {\n\t\t\tslider.style.removeProperty('--_sonic-slider-buffered-ranges');\n\t\t\treturn;\n\t\t}\n\n\t\tconst stops = this.#buffered.flatMap(([start, end]) => {\n\t\t\tconst from = grooveStop(this.fraction(Math.min(start, end)));\n\t\t\tconst to = grooveStop(this.fraction(Math.max(start, end)));\n\n\t\t\treturn [\n\t\t\t\t`transparent ${from}`,\n\t\t\t\t`var(--_sonic-slider-buffered) ${from} ${to}`,\n\t\t\t\t`transparent ${to}`,\n\t\t\t];\n\t\t});\n\n\t\tslider.style.setProperty(\n\t\t\t'--_sonic-slider-buffered-ranges',\n\t\t\t`linear-gradient(var(--_sonic-slider-toward), ${stops.join(', ')})`,\n\t\t);\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/lib/detent.ts
|
|
2
|
+
function isAcross(from, to, place) {
|
|
3
|
+
return from !== place && (from - place) * (to - place) <= 0;
|
|
4
|
+
}
|
|
5
|
+
function passDetent(hold, from, to) {
|
|
6
|
+
if (hold.slack === void 0 && !isAcross(from, to, hold.place)) return to;
|
|
7
|
+
const slack = (hold.slack ?? 0) + to - hold.place;
|
|
8
|
+
if (Math.abs(slack) <= hold.zone) {
|
|
9
|
+
hold.slack = slack;
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
hold.slack = void 0;
|
|
13
|
+
return hold.place + slack - Math.sign(slack) * hold.zone;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
export { passDetent };
|
|
18
|
+
//# sourceMappingURL=detent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detent.js","names":[],"sources":["../../../src/lib/detent.ts"],"sourcesContent":["// Places run 0 to 1 along the travel; `slack` is how far past the detent the pointer has pushed, set while held\nexport interface DetentHold {\n\tplace: number;\n\tslack: number | undefined;\n\tvalue: number;\n\tzone: number;\n}\n\nfunction isAcross(from: number, to: number, place: number): boolean {\n\treturn from !== place && (from - place) * (to - place) <= 0;\n}\n\n// The next place along the travel, or `undefined` while the detent holds\nexport function passDetent(hold: DetentHold, from: number, to: number): number | undefined {\n\tif (hold.slack === undefined && !isAcross(from, to, hold.place)) return to;\n\n\t// Held, `from` is the detent's place, so the move adds to the slack\n\tconst slack = (hold.slack ?? 0) + to - hold.place;\n\n\tif (Math.abs(slack) <= hold.zone) {\n\t\thold.slack = slack;\n\t\treturn undefined;\n\t}\n\n\thold.slack = undefined;\n\n\treturn hold.place + slack - Math.sign(slack) * hold.zone;\n}\n"],"mappings":";AAQA,SAAS,SAAS,MAAc,IAAY,OAAwB;CACnE,OAAO,SAAS,UAAU,OAAO,UAAU,KAAK,UAAU;AAC3D;AAGA,SAAgB,WAAW,MAAkB,MAAc,IAAgC;CAC1F,IAAI,KAAK,UAAU,UAAa,CAAC,SAAS,MAAM,IAAI,KAAK,KAAK,GAAG,OAAO;CAGxE,MAAM,SAAS,KAAK,SAAS,KAAK,KAAK,KAAK;CAE5C,IAAI,KAAK,IAAI,KAAK,KAAK,KAAK,MAAM;EACjC,KAAK,QAAQ;EACb;CACD;CAEA,KAAK,QAAQ;CAEb,OAAO,KAAK,QAAQ,QAAQ,KAAK,KAAK,KAAK,IAAI,KAAK;AACrD"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/lib/math.ts
|
|
2
|
+
function clamp(value, min, max) {
|
|
3
|
+
return Math.min(max, Math.max(min, value));
|
|
4
|
+
}
|
|
5
|
+
function clampUnit(fraction) {
|
|
6
|
+
return clamp(fraction, 0, 1);
|
|
7
|
+
}
|
|
8
|
+
function wrapUnit(fraction) {
|
|
9
|
+
return fraction - Math.floor(fraction);
|
|
10
|
+
}
|
|
11
|
+
function trimFloat(value) {
|
|
12
|
+
return Number(value.toPrecision(12));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
export { clamp, clampUnit, trimFloat, wrapUnit };
|
|
17
|
+
//# sourceMappingURL=math.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"math.js","names":[],"sources":["../../../src/lib/math.ts"],"sourcesContent":["export function clamp(value: number, min: number, max: number): number {\n\treturn Math.min(max, Math.max(min, value));\n}\n\nexport function clampUnit(fraction: number): number {\n\treturn clamp(fraction, 0, 1);\n}\n\nexport function wrapUnit(fraction: number): number {\n\treturn fraction - Math.floor(fraction);\n}\n\nexport function trimFloat(value: number): number {\n\treturn Number(value.toPrecision(12));\n}\n"],"mappings":";AAAA,SAAgB,MAAM,OAAe,KAAa,KAAqB;CACtE,OAAO,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;AAC1C;AAEA,SAAgB,UAAU,UAA0B;CACnD,OAAO,MAAM,UAAU,GAAG,CAAC;AAC5B;AAEA,SAAgB,SAAS,UAA0B;CAClD,OAAO,WAAW,KAAK,MAAM,QAAQ;AACtC;AAEA,SAAgB,UAAU,OAAuB;CAChD,OAAO,OAAO,MAAM,YAAY,EAAE,CAAC;AACpC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/lib/number-list.ts
|
|
2
|
+
function parseNumberList(text) {
|
|
3
|
+
if (text === null) return void 0;
|
|
4
|
+
const entries = [...new Set(text.split(/[\s,]+/).filter(Boolean).map(Number).filter((entry) => Number.isFinite(entry)))].toSorted((first, second) => first - second);
|
|
5
|
+
return entries.length >= 2 ? entries : void 0;
|
|
6
|
+
}
|
|
7
|
+
function nearestEntry(entries, value) {
|
|
8
|
+
let nearest = entries[0] ?? value;
|
|
9
|
+
for (const entry of entries) if (Math.abs(entry - value) < Math.abs(nearest - value)) nearest = entry;
|
|
10
|
+
return nearest;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
//#endregion
|
|
14
|
+
export { nearestEntry, parseNumberList };
|
|
15
|
+
//# sourceMappingURL=number-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"number-list.js","names":[],"sources":["../../../src/lib/number-list.ts"],"sourcesContent":["export function parseNumberList(text: null | string): Array<number> | undefined {\n\tif (text === null) return undefined;\n\n\tconst entries = [\n\t\t...new Set(\n\t\t\ttext\n\t\t\t\t.split(/[\\s,]+/)\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.map(Number)\n\t\t\t\t.filter((entry) => Number.isFinite(entry)),\n\t\t),\n\t].toSorted((first, second) => first - second);\n\n\treturn entries.length >= 2 ? entries : undefined;\n}\n\nexport function nearestEntry(entries: Array<number>, value: number): number {\n\tlet nearest = entries[0] ?? value;\n\n\tfor (const entry of entries) {\n\t\tif (Math.abs(entry - value) < Math.abs(nearest - value)) nearest = entry;\n\t}\n\n\treturn nearest;\n}\n"],"mappings":";AAAA,SAAgB,gBAAgB,MAAgD;CAC/E,IAAI,SAAS,MAAM,OAAO;CAE1B,MAAM,UAAU,CACf,GAAG,IAAI,IACN,KACE,MAAM,QAAQ,CAAC,CACf,OAAO,OAAO,CAAC,CACf,IAAI,MAAM,CAAC,CACX,QAAQ,UAAU,OAAO,SAAS,KAAK,CAAC,CAC3C,CACD,CAAC,CAAC,UAAU,OAAO,WAAW,QAAQ,MAAM;CAE5C,OAAO,QAAQ,UAAU,IAAI,UAAU;AACxC;AAEA,SAAgB,aAAa,SAAwB,OAAuB;CAC3E,IAAI,UAAU,QAAQ,MAAM;CAE5B,KAAK,MAAM,SAAS,SACnB,IAAI,KAAK,IAAI,QAAQ,KAAK,IAAI,KAAK,IAAI,UAAU,KAAK,GAAG,UAAU;CAGpE,OAAO;AACR"}
|
package/dist/dev/lib/taper.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
+
import { clampUnit } from "./math.js";
|
|
2
|
+
|
|
1
3
|
//#region src/lib/taper.ts
|
|
2
|
-
function clampUnit(fraction) {
|
|
3
|
-
return Math.min(1, Math.max(0, fraction));
|
|
4
|
-
}
|
|
5
|
-
function wrapUnit(fraction) {
|
|
6
|
-
return fraction - Math.floor(fraction);
|
|
7
|
-
}
|
|
8
4
|
function linearTaper(min, max) {
|
|
9
5
|
const range = max - min;
|
|
10
6
|
return {
|
|
@@ -30,7 +26,21 @@ function skewTaper(min, max, midpoint) {
|
|
|
30
26
|
value: (position) => min + range * clampUnit(position) ** (1 / skew)
|
|
31
27
|
};
|
|
32
28
|
}
|
|
29
|
+
function listTaper(entries) {
|
|
30
|
+
const last = entries.length - 1;
|
|
31
|
+
return {
|
|
32
|
+
position: (value) => {
|
|
33
|
+
const above = entries.findIndex((entry) => entry >= value);
|
|
34
|
+
if (above === -1) return 1;
|
|
35
|
+
const high = entries[above];
|
|
36
|
+
const low = entries[above - 1];
|
|
37
|
+
if (high === void 0 || low === void 0) return 0;
|
|
38
|
+
return (above - 1 + (value - low) / (high - low)) / last;
|
|
39
|
+
},
|
|
40
|
+
value: (position) => entries[Math.round(clampUnit(position) * last)] ?? NaN
|
|
41
|
+
};
|
|
42
|
+
}
|
|
33
43
|
|
|
34
44
|
//#endregion
|
|
35
|
-
export {
|
|
45
|
+
export { linearTaper, listTaper, logTaper, skewTaper };
|
|
36
46
|
//# sourceMappingURL=taper.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"taper.js","names":[],"sources":["../../../src/lib/taper.ts"],"sourcesContent":["// Positions run 0 to 1 along the travel\nexport interface Taper {\n\tposition: (value: number) => number;\n\tvalue: (position: number) => number;\n}\n\nexport function
|
|
1
|
+
{"version":3,"file":"taper.js","names":[],"sources":["../../../src/lib/taper.ts"],"sourcesContent":["import { clampUnit } from '#lib/math.ts';\n\n// Positions run 0 to 1 along the travel\nexport interface Taper {\n\tposition: (value: number) => number;\n\tvalue: (position: number) => number;\n}\n\nexport function linearTaper(min: number, max: number): Taper {\n\tconst range = max - min;\n\n\treturn {\n\t\tposition: (value) => (range > 0 ? clampUnit((value - min) / range) : 0),\n\t\tvalue: (position) => min + clampUnit(position) * range,\n\t};\n}\n\nexport function logTaper(min: number, max: number): Taper | undefined {\n\tif (min <= 0 || max <= min) return undefined;\n\n\tconst span = Math.log(max / min);\n\n\treturn {\n\t\tposition: (value) => clampUnit(Math.log(Math.max(min, value) / min) / span),\n\t\tvalue: (position) => min * Math.exp(clampUnit(position) * span),\n\t};\n}\n\n// JUCE's skew: a power curve through `midpoint` at half the travel\nexport function skewTaper(min: number, max: number, midpoint: number): Taper | undefined {\n\tconst range = max - min;\n\tconst proportion = (midpoint - min) / range;\n\n\tif (proportion === 0.5 || !(proportion > 0 && proportion < 1)) return undefined;\n\n\tconst skew = Math.log(0.5) / Math.log(proportion);\n\n\treturn {\n\t\tposition: (value) => clampUnit((value - min) / range) ** skew,\n\t\tvalue: (position) => min + range * clampUnit(position) ** (1 / skew),\n\t};\n}\n\n// Entries sit evenly along the travel, however unevenly they are spaced\nexport function listTaper(entries: Array<number>): Taper {\n\tconst last = entries.length - 1;\n\n\treturn {\n\t\tposition: (value) => {\n\t\t\tconst above = entries.findIndex((entry) => entry >= value);\n\t\t\tif (above === -1) return 1;\n\n\t\t\tconst high = entries[above];\n\t\t\tconst low = entries[above - 1];\n\t\t\tif (high === undefined || low === undefined) return 0;\n\n\t\t\treturn (above - 1 + (value - low) / (high - low)) / last;\n\t\t},\n\t\tvalue: (position) => entries[Math.round(clampUnit(position) * last)] ?? NaN,\n\t};\n}\n"],"mappings":";;;AAQA,SAAgB,YAAY,KAAa,KAAoB;CAC5D,MAAM,QAAQ,MAAM;CAEpB,OAAO;EACN,WAAW,UAAW,QAAQ,IAAI,WAAW,QAAQ,OAAO,KAAK,IAAI;EACrE,QAAQ,aAAa,MAAM,UAAU,QAAQ,IAAI;CAClD;AACD;AAEA,SAAgB,SAAS,KAAa,KAAgC;CACrE,IAAI,OAAO,KAAK,OAAO,KAAK,OAAO;CAEnC,MAAM,OAAO,KAAK,IAAI,MAAM,GAAG;CAE/B,OAAO;EACN,WAAW,UAAU,UAAU,KAAK,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,IAAI,IAAI;EAC1E,QAAQ,aAAa,MAAM,KAAK,IAAI,UAAU,QAAQ,IAAI,IAAI;CAC/D;AACD;AAGA,SAAgB,UAAU,KAAa,KAAa,UAAqC;CACxF,MAAM,QAAQ,MAAM;CACpB,MAAM,cAAc,WAAW,OAAO;CAEtC,IAAI,eAAe,MAAO,EAAE,aAAa,KAAK,aAAa,IAAI,OAAO;CAEtE,MAAM,OAAO,KAAK,IAAI,EAAG,IAAI,KAAK,IAAI,UAAU;CAEhD,OAAO;EACN,WAAW,UAAU,WAAW,QAAQ,OAAO,KAAK,KAAK;EACzD,QAAQ,aAAa,MAAM,QAAQ,UAAU,QAAQ,MAAM,IAAI;CAChE;AACD;AAGA,SAAgB,UAAU,SAA+B;CACxD,MAAM,OAAO,QAAQ,SAAS;CAE9B,OAAO;EACN,WAAW,UAAU;GACpB,MAAM,QAAQ,QAAQ,WAAW,UAAU,SAAS,KAAK;GACzD,IAAI,UAAU,IAAI,OAAO;GAEzB,MAAM,OAAO,QAAQ;GACrB,MAAM,MAAM,QAAQ,QAAQ;GAC5B,IAAI,SAAS,UAAa,QAAQ,QAAW,OAAO;GAEpD,QAAQ,QAAQ,KAAK,QAAQ,QAAQ,OAAO,QAAQ;EACrD;EACA,QAAQ,aAAa,QAAQ,KAAK,MAAM,UAAU,QAAQ,IAAI,IAAI,MAAM;CACzE;AACD"}
|
package/dist/styles/dial.css
CHANGED
|
@@ -27,9 +27,11 @@
|
|
|
27
27
|
|
|
28
28
|
sonic-dial:not(:defined, [hidden]) {
|
|
29
29
|
display: block;
|
|
30
|
+
visibility: hidden;
|
|
30
31
|
flex-shrink: 0;
|
|
31
32
|
inline-size: var(--_sonic-dial-size);
|
|
32
33
|
block-size: var(--_sonic-dial-size);
|
|
34
|
+
overflow: hidden;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
.sonic-dial {
|
|
@@ -43,6 +45,8 @@
|
|
|
43
45
|
/* A fraction of the knob's angle */
|
|
44
46
|
--_sonic-dial-face-drift: var(--sonic-dial-face-drift, 0.1);
|
|
45
47
|
--_sonic-dial-notch-ratio: var(--sonic-dial-notch-ratio, 0.1);
|
|
48
|
+
--_sonic-dial-scale-ratio: var(--sonic-dial-scale-ratio, 0.2);
|
|
49
|
+
--_sonic-dial-scale-font-ratio: var(--sonic-dial-scale-font-ratio, 0.175);
|
|
46
50
|
|
|
47
51
|
/* Centred on six o'clock */
|
|
48
52
|
--_sonic-dial-sweep: var(--sonic-dial-sweep, 300deg);
|
|
@@ -52,12 +56,13 @@
|
|
|
52
56
|
--_sonic-unit: calc(var(--_sonic-dial-size) / 40);
|
|
53
57
|
--_sonic-dial-lit: var(--_sonic-lit);
|
|
54
58
|
--_sonic-dial-notch-band: 0px;
|
|
59
|
+
--_sonic-dial-scale-band: 0px;
|
|
55
60
|
--_sonic-dial-notch-ends: 1;
|
|
56
61
|
--_sonic-dial-start: calc(180deg + (1turn - var(--_sonic-dial-sweep)) / 2);
|
|
57
62
|
--_sonic-dial-angle: calc(var(--_sonic-dial-value, 0) * var(--_sonic-dial-sweep));
|
|
58
63
|
--_sonic-dial-ring-width: calc(var(--_sonic-dial-size) * var(--_sonic-dial-ring-ratio));
|
|
59
64
|
--_sonic-dial-cap-inset: calc(
|
|
60
|
-
var(--_sonic-dial-notch-band) + var(--_sonic-dial-size) *
|
|
65
|
+
var(--_sonic-dial-scale-band) + var(--_sonic-dial-notch-band) + var(--_sonic-dial-size) *
|
|
61
66
|
(var(--_sonic-dial-ring-ratio) + var(--_sonic-dial-gap-ratio))
|
|
62
67
|
);
|
|
63
68
|
|
|
@@ -99,6 +104,10 @@
|
|
|
99
104
|
--_sonic-dial-notch-band: calc(var(--_sonic-dial-size) * var(--_sonic-dial-notch-ratio));
|
|
100
105
|
}
|
|
101
106
|
|
|
107
|
+
:has(> [data-sonic-value]) > .sonic-dial {
|
|
108
|
+
--_sonic-dial-scale-band: calc(var(--_sonic-dial-size) * var(--_sonic-dial-scale-ratio));
|
|
109
|
+
}
|
|
110
|
+
|
|
102
111
|
/* Set on `--_sonic-dial-lit`, since `--_sonic-lit` cannot reference itself */
|
|
103
112
|
[dimmed] > .sonic-dial {
|
|
104
113
|
--_sonic-dial-lit: var(--_sonic-lit-off);
|
|
@@ -117,7 +126,7 @@
|
|
|
117
126
|
);
|
|
118
127
|
|
|
119
128
|
position: absolute;
|
|
120
|
-
inset:
|
|
129
|
+
inset: var(--_sonic-dial-scale-band);
|
|
121
130
|
background: repeating-conic-gradient(
|
|
122
131
|
from calc(var(--_sonic-dial-start) - var(--_sonic-dial-notch-width) / 2),
|
|
123
132
|
var(--_sonic-etch) 0 var(--_sonic-dial-notch-width),
|
|
@@ -139,9 +148,40 @@
|
|
|
139
148
|
mask-composite: intersect;
|
|
140
149
|
}
|
|
141
150
|
|
|
151
|
+
.sonic-dial-scale {
|
|
152
|
+
font-size: calc(var(--_sonic-dial-size) * var(--_sonic-dial-scale-font-ratio));
|
|
153
|
+
|
|
154
|
+
/* The near edge hugs the band's inner edge, and each mark grows outward along its angle */
|
|
155
|
+
& > * {
|
|
156
|
+
--_sonic-dial-scale-angle: calc(
|
|
157
|
+
var(--_sonic-dial-start) + var(--_sonic-scale-at, 0) * var(--_sonic-dial-sweep)
|
|
158
|
+
);
|
|
159
|
+
--_sonic-dial-scale-sin: sin(var(--_sonic-dial-scale-angle));
|
|
160
|
+
--_sonic-dial-scale-cos: cos(var(--_sonic-dial-scale-angle));
|
|
161
|
+
--_sonic-dial-scale-radius: calc(
|
|
162
|
+
var(--_sonic-dial-size) / 2 - var(--_sonic-dial-scale-band) + var(--_sonic-unit)
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
inset: calc(50% - var(--_sonic-dial-scale-cos) * var(--_sonic-dial-scale-radius)) auto auto
|
|
166
|
+
calc(50% + var(--_sonic-dial-scale-sin) * var(--_sonic-dial-scale-radius));
|
|
167
|
+
translate: calc(-50% + var(--_sonic-dial-scale-sin) * 50%)
|
|
168
|
+
calc(-50% - var(--_sonic-dial-scale-cos) * 50%);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
& > .sonic-scale-tick {
|
|
172
|
+
--_sonic-dial-tick-length: calc(var(--_sonic-dial-scale-band) * 0.4);
|
|
173
|
+
|
|
174
|
+
inline-size: var(--_sonic-unit);
|
|
175
|
+
block-size: var(--_sonic-dial-tick-length);
|
|
176
|
+
rotate: var(--_sonic-dial-scale-angle);
|
|
177
|
+
translate: calc(-50% + var(--_sonic-dial-scale-sin) * var(--_sonic-dial-tick-length) / 2)
|
|
178
|
+
calc(-50% - var(--_sonic-dial-scale-cos) * var(--_sonic-dial-tick-length) / 2);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
142
182
|
:is(.sonic-dial-ring, .sonic-dial-modulation) {
|
|
143
183
|
position: absolute;
|
|
144
|
-
inset: var(--_sonic-dial-notch-band);
|
|
184
|
+
inset: calc(var(--_sonic-dial-scale-band) + var(--_sonic-dial-notch-band));
|
|
145
185
|
border-radius: 50%;
|
|
146
186
|
mask: radial-gradient(
|
|
147
187
|
closest-side,
|
package/dist/styles/key.css
CHANGED
|
@@ -4,6 +4,18 @@
|
|
|
4
4
|
initial-value: 32px;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
@property --_sonic-key-busy-angle {
|
|
8
|
+
syntax: '<angle>';
|
|
9
|
+
inherits: false;
|
|
10
|
+
initial-value: 0deg;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@keyframes sonic-key-busy {
|
|
14
|
+
to {
|
|
15
|
+
--_sonic-key-busy-angle: 1turn;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
7
19
|
@layer sonic {
|
|
8
20
|
:is(sonic-key, .sonic-key) {
|
|
9
21
|
--_sonic-key-size: var(--sonic-key-size, 2rem);
|
|
@@ -50,11 +62,7 @@
|
|
|
50
62
|
font: inherit;
|
|
51
63
|
color: var(--_sonic-ink);
|
|
52
64
|
cursor: pointer;
|
|
53
|
-
background:
|
|
54
|
-
var(--_sonic-light-fall),
|
|
55
|
-
color-mix(in oklab, var(--_sonic-unlit) 55%, #000),
|
|
56
|
-
color-mix(in oklab, var(--_sonic-unlit) 85%, #000)
|
|
57
|
-
);
|
|
65
|
+
background: var(--_sonic-well-floor);
|
|
58
66
|
border: 0;
|
|
59
67
|
border-radius: var(--_sonic-key-corner);
|
|
60
68
|
box-shadow: var(--_sonic-well);
|
|
@@ -66,12 +74,11 @@
|
|
|
66
74
|
touch-action: none;
|
|
67
75
|
}
|
|
68
76
|
|
|
69
|
-
.sonic-key:active:where(:not(:disabled)),
|
|
77
|
+
.sonic-key:active:where(:not(:disabled, [aria-disabled='true'])),
|
|
70
78
|
.sonic-key:is([aria-pressed='true'], :where([momentary]:state(pressed)) > *) {
|
|
71
79
|
--_sonic-key-shift: calc(var(--_sonic-key-depth) / 2);
|
|
72
80
|
--_sonic-key-scale: var(--_sonic-key-press-scale);
|
|
73
|
-
--_sonic-key-drop:
|
|
74
|
-
var(--_sonic-unit) var(--_sonic-drop-shade);
|
|
81
|
+
--_sonic-key-drop: var(--_sonic-press-drop);
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
.sonic-key:is([aria-pressed='true'], :where([momentary]:state(pressed)) > *) {
|
|
@@ -87,26 +94,63 @@
|
|
|
87
94
|
);
|
|
88
95
|
}
|
|
89
96
|
|
|
90
|
-
.sonic-key:disabled {
|
|
97
|
+
.sonic-key:is(:disabled, [aria-disabled='true']) {
|
|
91
98
|
--_sonic-lit: var(--_sonic-lit-disabled);
|
|
92
99
|
|
|
93
100
|
color: var(--_sonic-etch);
|
|
94
101
|
cursor: default;
|
|
95
102
|
}
|
|
96
103
|
|
|
97
|
-
.sonic-key:not(
|
|
98
|
-
|
|
99
|
-
:
|
|
100
|
-
|
|
104
|
+
.sonic-key:not(
|
|
105
|
+
[aria-pressed='true'],
|
|
106
|
+
:disabled,
|
|
107
|
+
[aria-disabled='true'],
|
|
108
|
+
:where([momentary]:state(pressed)) > *
|
|
109
|
+
):is(:focus-visible, :active) {
|
|
101
110
|
color: var(--_sonic-ink-lift);
|
|
102
111
|
}
|
|
103
112
|
|
|
104
113
|
@media (hover: hover) {
|
|
105
|
-
|
|
114
|
+
/* fallow-ignore-next-line code-duplication -- `:hover` sits under `(hover: hover)` and its `:focus-visible` partner outside it */
|
|
115
|
+
.sonic-key:not(
|
|
116
|
+
[aria-pressed='true'],
|
|
117
|
+
:disabled,
|
|
118
|
+
[aria-disabled='true'],
|
|
119
|
+
:where([momentary]:state(pressed)) > *
|
|
120
|
+
):hover {
|
|
106
121
|
color: var(--_sonic-ink-lift);
|
|
107
122
|
}
|
|
108
123
|
}
|
|
109
124
|
|
|
125
|
+
/* Turns with the arc, so evenly shaded */
|
|
126
|
+
[busy] > .sonic-key::after {
|
|
127
|
+
position: absolute;
|
|
128
|
+
inset: 0;
|
|
129
|
+
box-sizing: border-box;
|
|
130
|
+
padding: calc(var(--_sonic-key-size) * var(--_sonic-key-bevel-ratio));
|
|
131
|
+
pointer-events: none;
|
|
132
|
+
content: '';
|
|
133
|
+
background: conic-gradient(
|
|
134
|
+
from var(--_sonic-key-busy-angle),
|
|
135
|
+
transparent 0 55%,
|
|
136
|
+
var(--_sonic-lit)
|
|
137
|
+
);
|
|
138
|
+
border-radius: var(--_sonic-key-corner);
|
|
139
|
+
mask:
|
|
140
|
+
linear-gradient(#000 0 0) content-box exclude,
|
|
141
|
+
linear-gradient(#000 0 0);
|
|
142
|
+
animation: sonic-key-busy 1s linear infinite;
|
|
143
|
+
|
|
144
|
+
@media (prefers-reduced-motion: reduce) {
|
|
145
|
+
background: color-mix(in oklab, var(--_sonic-lit) 45%, transparent);
|
|
146
|
+
animation: none;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
@media (forced-colors: active) {
|
|
150
|
+
forced-color-adjust: none;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
110
154
|
.sonic-key-cap {
|
|
111
155
|
position: absolute;
|
|
112
156
|
inset: var(--_sonic-key-gap);
|
|
@@ -165,6 +209,7 @@
|
|
|
165
209
|
drop-shadow(0 0 var(--_sonic-unit) color-mix(in oklab, var(--_sonic-lit) 35%, transparent));
|
|
166
210
|
}
|
|
167
211
|
|
|
212
|
+
/* fallow-ignore-next-line code-duplication -- one pressed state, restated for each part of the cap it reaches */
|
|
168
213
|
.sonic-key:is([aria-pressed='true'], :where([momentary]:state(pressed)) > *)
|
|
169
214
|
.sonic-key-cap
|
|
170
215
|
> [data-sonic-when='off'],
|
|
@@ -185,7 +230,7 @@
|
|
|
185
230
|
--_sonic-face: var(--_sonic-lit);
|
|
186
231
|
--_sonic-ink: HighlightText;
|
|
187
232
|
|
|
188
|
-
&:disabled {
|
|
233
|
+
&:is(:disabled, [aria-disabled='true']) {
|
|
189
234
|
--_sonic-ink: ButtonFace;
|
|
190
235
|
}
|
|
191
236
|
|
package/dist/styles/led.css
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
.sonic-led {
|
|
9
9
|
--_sonic-led-size: var(--sonic-led-size, 0.5rem);
|
|
10
10
|
--_sonic-led-lens-ratio: var(--sonic-led-lens-ratio, 0.625);
|
|
11
|
+
--_sonic-lit-alt: var(--sonic-lit-alt, oklch(79% 0.2 150deg));
|
|
11
12
|
--_sonic-unit: calc(var(--_sonic-led-size) / 8);
|
|
12
13
|
--_sonic-led-bezel: color-mix(in oklab, var(--_sonic-unlit) 55%, #000);
|
|
13
14
|
|
|
@@ -28,6 +29,8 @@
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
@media (forced-colors: active) {
|
|
32
|
+
--_sonic-lit-alt: Mark;
|
|
33
|
+
|
|
31
34
|
forced-color-adjust: none;
|
|
32
35
|
background: none;
|
|
33
36
|
|
|
@@ -38,6 +41,10 @@
|
|
|
38
41
|
}
|
|
39
42
|
}
|
|
40
43
|
|
|
44
|
+
.sonic-led[data-sonic-lit='alt'] {
|
|
45
|
+
--_sonic-lit: var(--_sonic-lit-alt);
|
|
46
|
+
}
|
|
47
|
+
|
|
41
48
|
.sonic-led:is(
|
|
42
49
|
[data-sonic-lit],
|
|
43
50
|
:where(
|
|
@@ -68,7 +75,7 @@
|
|
|
68
75
|
background: none;
|
|
69
76
|
|
|
70
77
|
&::after {
|
|
71
|
-
background:
|
|
78
|
+
background: var(--_sonic-lit);
|
|
72
79
|
}
|
|
73
80
|
}
|
|
74
81
|
}
|
package/dist/styles/material.css
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
initial-value: 24px;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
@property --_sonic-detent-zone {
|
|
8
|
+
syntax: '<length>';
|
|
9
|
+
inherits: true;
|
|
10
|
+
initial-value: 8px;
|
|
11
|
+
}
|
|
12
|
+
|
|
7
13
|
@layer sonic {
|
|
8
14
|
/* Resolved per control rather than on `:root`, so each follows its own cap and unit */
|
|
9
15
|
:is(
|
|
@@ -93,6 +99,11 @@
|
|
|
93
99
|
color-mix(in oklab, var(--_sonic-focus) 60%, transparent);
|
|
94
100
|
}
|
|
95
101
|
|
|
102
|
+
/* A gesture distance, absolute like the travel */
|
|
103
|
+
:is(.sonic-dial, .sonic-number, .sonic-slider) {
|
|
104
|
+
--_sonic-detent-zone: var(--sonic-detent-zone, 8px);
|
|
105
|
+
}
|
|
106
|
+
|
|
96
107
|
:is(.sonic-dial, .sonic-slider) {
|
|
97
108
|
/* On the control, since the readout's font size reads it */
|
|
98
109
|
--_sonic-readout-size: var(--sonic-readout-size, 1.5rem);
|
|
@@ -153,6 +164,11 @@
|
|
|
153
164
|
}
|
|
154
165
|
|
|
155
166
|
:is(.sonic-key, .sonic-segmented) {
|
|
167
|
+
--_sonic-well-floor: linear-gradient(
|
|
168
|
+
var(--_sonic-light-fall),
|
|
169
|
+
color-mix(in oklab, var(--_sonic-unlit) 55%, #000),
|
|
170
|
+
color-mix(in oklab, var(--_sonic-unlit) 85%, #000)
|
|
171
|
+
);
|
|
156
172
|
--_sonic-engraving: drop-shadow(
|
|
157
173
|
calc(-0.4 * var(--_sonic-cast-x)) calc(-0.4 * var(--_sonic-cast-y))
|
|
158
174
|
calc(0.4 * var(--_sonic-unit)) rgb(0 0 0 / 30%)
|
|
@@ -162,6 +178,12 @@
|
|
|
162
178
|
);
|
|
163
179
|
}
|
|
164
180
|
|
|
181
|
+
/* On the segment rather than the strip, where forced colours clear the drop shade */
|
|
182
|
+
:is(.sonic-key, .sonic-segmented-segment) {
|
|
183
|
+
--_sonic-press-drop: calc(0.5 * var(--_sonic-cast-x)) calc(0.5 * var(--_sonic-cast-y))
|
|
184
|
+
var(--_sonic-unit) var(--_sonic-drop-shade);
|
|
185
|
+
}
|
|
186
|
+
|
|
165
187
|
/* The well's full blur would fill a slot this narrow */
|
|
166
188
|
:is(.sonic-meter, .sonic-slider) {
|
|
167
189
|
--_sonic-groove:
|
|
@@ -292,7 +314,34 @@
|
|
|
292
314
|
}
|
|
293
315
|
}
|
|
294
316
|
|
|
317
|
+
/* Printed on the consumer's panel rather than the cap, so the text takes the page's colour and font */
|
|
318
|
+
:is(.sonic-dial-scale, .sonic-slider-scale) {
|
|
319
|
+
position: absolute;
|
|
320
|
+
inset: 0;
|
|
321
|
+
line-height: 1;
|
|
322
|
+
white-space: nowrap;
|
|
323
|
+
pointer-events: none;
|
|
324
|
+
|
|
325
|
+
& > * {
|
|
326
|
+
position: absolute;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
& svg {
|
|
330
|
+
display: block;
|
|
331
|
+
inline-size: 1em;
|
|
332
|
+
block-size: 1em;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
& > .sonic-scale-tick {
|
|
336
|
+
background: var(--_sonic-etch);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
295
340
|
@media (forced-colors: active) {
|
|
341
|
+
.sonic-scale-tick {
|
|
342
|
+
forced-color-adjust: none;
|
|
343
|
+
}
|
|
344
|
+
|
|
296
345
|
:is(
|
|
297
346
|
.sonic-dial,
|
|
298
347
|
.sonic-key,
|
|
@@ -327,7 +376,7 @@
|
|
|
327
376
|
|
|
328
377
|
:is(
|
|
329
378
|
:disabled > :is(.sonic-dial, .sonic-slider),
|
|
330
|
-
.sonic-key:disabled,
|
|
379
|
+
.sonic-key:is(:disabled, [aria-disabled='true']),
|
|
331
380
|
.sonic-segmented-segment:disabled
|
|
332
381
|
) {
|
|
333
382
|
--_sonic-ink: GrayText;
|