@xsynaptic/sonic-ui 0.2.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/README.md +2 -2
- package/dist/default/define/number.js +7 -0
- package/dist/default/define.js +1 -0
- package/dist/default/elements/dial.js +24 -10
- package/dist/default/elements/key.js +29 -4
- package/dist/default/elements/meter.js +63 -9
- package/dist/default/elements/number.js +46 -0
- package/dist/default/elements/range-element.js +172 -36
- package/dist/default/elements/slider.js +63 -3
- package/dist/default/index.js +2 -1
- 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 -4
- package/dist/dev/define/number.d.ts +2 -0
- package/dist/dev/define/number.js +8 -0
- package/dist/dev/define/number.js.map +1 -0
- package/dist/dev/define.d.ts +3 -1
- package/dist/dev/define.js +1 -0
- package/dist/dev/elements/dial.d.ts +3 -0
- package/dist/dev/elements/dial.js +24 -10
- 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.d.ts +16 -0
- package/dist/dev/elements/number.js +47 -0
- package/dist/dev/elements/number.js.map +1 -0
- package/dist/dev/elements/range-element.d.ts +12 -0
- package/dist/dev/elements/range-element.js +172 -36
- package/dist/dev/elements/range-element.js.map +1 -1
- package/dist/dev/elements/slider.d.ts +8 -0
- package/dist/dev/elements/slider.js +63 -3
- package/dist/dev/elements/slider.js.map +1 -1
- package/dist/dev/index.d.ts +2 -1
- package/dist/dev/index.js +2 -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/read-px-property.js.map +1 -1
- package/dist/dev/lib/taper.js +17 -4
- package/dist/dev/lib/taper.js.map +1 -1
- package/dist/styles/controls.css +2 -0
- package/dist/styles/dial.css +80 -6
- package/dist/styles/key.css +96 -11
- package/dist/styles/led.css +82 -0
- package/dist/styles/material.css +150 -20
- package/dist/styles/meter.css +120 -8
- package/dist/styles/number.css +81 -0
- package/dist/styles/screen.css +6 -39
- package/dist/styles/segmented.css +23 -7
- package/dist/styles/slider.css +143 -30
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @xsynaptic/sonic-ui
|
|
2
2
|
|
|
3
|
-
Native custom elements for audio interfaces
|
|
3
|
+
Native custom elements for audio interfaces. Each control renders in the light DOM, drawn in CSS, skinned with `--sonic-*` custom properties. No framework, no runtime dependencies.
|
|
4
4
|
|
|
5
5
|
Early and unstable: any 0.x release may break the API.
|
|
6
6
|
|
|
@@ -34,7 +34,7 @@ The styles sit in `@layer sonic`, so list it after your resets. A skin (`slate`,
|
|
|
34
34
|
- **Attributes and properties** reflect each other: `dial.max = 200` writes `max="200"`. `value` and the key's `pressed` are the live state and never write their attribute, as on native inputs.
|
|
35
35
|
- **Events:** `change` when a control settles, and `input` while a dial or slider moves; both bubble.
|
|
36
36
|
- **Formatting:** `formatValue` sets the text the readout and assistive technology read, and `parseValue` reads typed entry back. `formatPercent` and `parsePercent` from the package root show 0 to 1 as a percentage.
|
|
37
|
-
- **Forms:**
|
|
37
|
+
- **Forms:** controls that hold a value submit under their `name`, reset, take a `<label>`, and follow a disabled `<fieldset>`, as native inputs do.
|
|
38
38
|
|
|
39
39
|
## Browsers
|
|
40
40
|
|
package/dist/default/define.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { template } from "../lib/render.js";
|
|
2
|
-
import { SonicRangeElement } from "./range-element.js";
|
|
1
|
+
import { requireChild, template } from "../lib/render.js";
|
|
3
2
|
import { readPxProperty } from "../lib/read-px-property.js";
|
|
3
|
+
import { SonicRangeElement } from "./range-element.js";
|
|
4
4
|
|
|
5
5
|
//#region src/elements/dial.ts
|
|
6
6
|
const renderDial = template(`
|
|
7
7
|
<div class="sonic-dial" role="slider" tabindex="0">
|
|
8
|
+
<div class="sonic-dial-scale" aria-hidden="true"></div>
|
|
8
9
|
<div class="sonic-dial-notches"></div>
|
|
9
10
|
<div class="sonic-dial-ring"></div>
|
|
10
11
|
<div class="sonic-dial-modulation"></div>
|
|
@@ -25,7 +26,17 @@ const renderDial = template(`
|
|
|
25
26
|
`, HTMLDivElement);
|
|
26
27
|
const fallbackTravelPx = 160;
|
|
27
28
|
var SonicDial = class extends SonicRangeElement {
|
|
28
|
-
static observedAttributes = [
|
|
29
|
+
static observedAttributes = [
|
|
30
|
+
...SonicRangeElement.observedAttributes,
|
|
31
|
+
"endless",
|
|
32
|
+
"modulation"
|
|
33
|
+
];
|
|
34
|
+
get endless() {
|
|
35
|
+
return this.hasAttribute("endless");
|
|
36
|
+
}
|
|
37
|
+
set endless(isEndless) {
|
|
38
|
+
this.reflect("endless", isEndless);
|
|
39
|
+
}
|
|
29
40
|
get modulation() {
|
|
30
41
|
return this.numberAttribute("modulation", 0);
|
|
31
42
|
}
|
|
@@ -34,12 +45,12 @@ var SonicDial = class extends SonicRangeElement {
|
|
|
34
45
|
}
|
|
35
46
|
#dial = renderDial();
|
|
36
47
|
connectedCallback() {
|
|
37
|
-
this.upgradeProperties("modulation");
|
|
48
|
+
this.upgradeProperties("endless", "modulation");
|
|
38
49
|
super.connectedCallback();
|
|
39
50
|
}
|
|
40
51
|
connect(signal) {
|
|
41
52
|
const dial = this.#dial;
|
|
42
|
-
this.
|
|
53
|
+
this.bindScale(dial, requireChild(dial, ".sonic-dial-scale", HTMLDivElement), signal);
|
|
43
54
|
this.render();
|
|
44
55
|
this.checkStyles(dial, "dial.css");
|
|
45
56
|
this.bindGestures(dial, signal, () => ({
|
|
@@ -53,16 +64,19 @@ var SonicDial = class extends SonicRangeElement {
|
|
|
53
64
|
render() {
|
|
54
65
|
const dial = this.#dial;
|
|
55
66
|
const positions = this.positions();
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
dial.style.setProperty("--_sonic-dial-value", String(value));
|
|
67
|
+
const [modulationFrom, modulationTo] = this.modulationFractions(this.endless ? 0 : this.modulation);
|
|
68
|
+
dial.style.setProperty("--_sonic-dial-value", String(this.fraction(this.value)));
|
|
59
69
|
dial.style.setProperty("--_sonic-dial-origin", String(this.originFraction()));
|
|
60
|
-
dial.style.setProperty("--_sonic-dial-modulation-from", String(
|
|
61
|
-
dial.style.setProperty("--_sonic-dial-modulation-to", String(
|
|
70
|
+
dial.style.setProperty("--_sonic-dial-modulation-from", String(modulationFrom));
|
|
71
|
+
dial.style.setProperty("--_sonic-dial-modulation-to", String(modulationTo));
|
|
62
72
|
if (positions === void 0) dial.style.removeProperty("--_sonic-dial-positions");
|
|
63
73
|
else dial.style.setProperty("--_sonic-dial-positions", String(positions));
|
|
74
|
+
this.renderScale();
|
|
64
75
|
this.renderAria(dial);
|
|
65
76
|
}
|
|
77
|
+
wraps() {
|
|
78
|
+
return this.endless;
|
|
79
|
+
}
|
|
66
80
|
};
|
|
67
81
|
|
|
68
82
|
//#endregion
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { requireChild, template } from "../lib/render.js";
|
|
2
|
+
import { writeAttribute } from "../lib/write-attribute.js";
|
|
2
3
|
import { SonicFormElement } from "./form-element.js";
|
|
3
4
|
import { copyNode } from "../lib/copy-node.js";
|
|
4
5
|
|
|
@@ -10,11 +11,19 @@ const holdKeys = /* @__PURE__ */ new Set([" ", "Enter"]);
|
|
|
10
11
|
var SonicKey = class extends SonicFormElement {
|
|
11
12
|
static observedAttributes = [
|
|
12
13
|
...SonicFormElement.observedAttributes,
|
|
14
|
+
"busy",
|
|
13
15
|
"momentary",
|
|
14
16
|
"pressed",
|
|
17
|
+
"soft-disabled",
|
|
15
18
|
"toggle",
|
|
16
19
|
"value"
|
|
17
20
|
];
|
|
21
|
+
get busy() {
|
|
22
|
+
return this.hasAttribute("busy");
|
|
23
|
+
}
|
|
24
|
+
set busy(isBusy) {
|
|
25
|
+
this.reflect("busy", isBusy);
|
|
26
|
+
}
|
|
18
27
|
get defaultPressed() {
|
|
19
28
|
return this.hasAttribute("pressed");
|
|
20
29
|
}
|
|
@@ -35,6 +44,12 @@ var SonicKey = class extends SonicFormElement {
|
|
|
35
44
|
this.#pressed = isPressed === true;
|
|
36
45
|
this.render();
|
|
37
46
|
}
|
|
47
|
+
get softDisabled() {
|
|
48
|
+
return this.hasAttribute("soft-disabled");
|
|
49
|
+
}
|
|
50
|
+
set softDisabled(isSoftDisabled) {
|
|
51
|
+
this.reflect("soft-disabled", isSoftDisabled);
|
|
52
|
+
}
|
|
38
53
|
get toggle() {
|
|
39
54
|
return this.hasAttribute("toggle");
|
|
40
55
|
}
|
|
@@ -53,7 +68,7 @@ var SonicKey = class extends SonicFormElement {
|
|
|
53
68
|
#pressed = false;
|
|
54
69
|
attributeChangedCallback(name) {
|
|
55
70
|
if (name === "pressed") this.#isDirty = false;
|
|
56
|
-
if (
|
|
71
|
+
if (this.isDisabled() || this.#isSoftDisabled()) this.#release();
|
|
57
72
|
this.render();
|
|
58
73
|
}
|
|
59
74
|
formResetCallback() {
|
|
@@ -65,7 +80,7 @@ var SonicKey = class extends SonicFormElement {
|
|
|
65
80
|
connect(signal) {
|
|
66
81
|
const key = this.#key;
|
|
67
82
|
const cap = requireChild(key, ".sonic-key-cap", HTMLSpanElement);
|
|
68
|
-
this.upgradeProperties("defaultPressed", "momentary", "toggle", "pressed", "value");
|
|
83
|
+
this.upgradeProperties("busy", "defaultPressed", "momentary", "softDisabled", "toggle", "pressed", "value");
|
|
69
84
|
this.mirrorChildren({
|
|
70
85
|
control: key,
|
|
71
86
|
copy: (originals) => {
|
|
@@ -77,7 +92,12 @@ var SonicKey = class extends SonicFormElement {
|
|
|
77
92
|
signal.addEventListener("abort", () => {
|
|
78
93
|
this.#release();
|
|
79
94
|
}, { once: true });
|
|
80
|
-
key.addEventListener("click", () => {
|
|
95
|
+
key.addEventListener("click", (event) => {
|
|
96
|
+
if (this.#isSoftDisabled()) {
|
|
97
|
+
event.preventDefault();
|
|
98
|
+
event.stopImmediatePropagation();
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
81
101
|
if (!this.toggle) return;
|
|
82
102
|
this.pressed = !this.pressed;
|
|
83
103
|
this.dispatchEvent(new Event("change", { bubbles: true }));
|
|
@@ -90,6 +110,8 @@ var SonicKey = class extends SonicFormElement {
|
|
|
90
110
|
render() {
|
|
91
111
|
const key = this.#key;
|
|
92
112
|
key.disabled = this.isDisabled();
|
|
113
|
+
writeAttribute(key, "aria-disabled", this.#isSoftDisabled() ? "true" : void 0);
|
|
114
|
+
writeAttribute(key, "aria-busy", this.busy ? "true" : void 0);
|
|
93
115
|
key.removeAttribute("aria-pressed");
|
|
94
116
|
if (this.toggle) key.setAttribute("aria-pressed", String(this.pressed));
|
|
95
117
|
this.toggleState("pressed", this.pressed);
|
|
@@ -124,7 +146,7 @@ var SonicKey = class extends SonicFormElement {
|
|
|
124
146
|
}, { signal });
|
|
125
147
|
}
|
|
126
148
|
#hold(holder) {
|
|
127
|
-
if (this.isDisabled() || this.#holder !== void 0) return;
|
|
149
|
+
if (this.isDisabled() || this.#isSoftDisabled() || this.#holder !== void 0) return;
|
|
128
150
|
this.#holder = holder;
|
|
129
151
|
this.pressed = true;
|
|
130
152
|
this.dispatchEvent(new Event("change", { bubbles: true }));
|
|
@@ -132,6 +154,9 @@ var SonicKey = class extends SonicFormElement {
|
|
|
132
154
|
#isMomentary() {
|
|
133
155
|
return this.momentary && !this.toggle;
|
|
134
156
|
}
|
|
157
|
+
#isSoftDisabled() {
|
|
158
|
+
return this.softDisabled && !this.isDisabled();
|
|
159
|
+
}
|
|
135
160
|
#release() {
|
|
136
161
|
if (this.#holder === void 0) return;
|
|
137
162
|
this.#holder = void 0;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { template } from "../lib/render.js";
|
|
2
2
|
import { SonicElement } from "./sonic-element.js";
|
|
3
|
+
import { parseNumberList } from "../lib/number-list.js";
|
|
4
|
+
import { linearTaper } from "../lib/taper.js";
|
|
3
5
|
|
|
4
6
|
//#region src/elements/meter.ts
|
|
5
7
|
const renderMeter = template(`
|
|
@@ -14,20 +16,30 @@ const holdMs = 1500;
|
|
|
14
16
|
function toDecibels(amplitude) {
|
|
15
17
|
return 20 * Math.log10(Math.abs(amplitude));
|
|
16
18
|
}
|
|
19
|
+
function lightsBelow(lights, zone) {
|
|
20
|
+
return `calc(${lights.map((threshold) => `sign(max(0, var(--_sonic-meter-${zone}-from) - (${String(threshold)})))`).join(" + ")})`;
|
|
21
|
+
}
|
|
17
22
|
var SonicMeter = class extends SonicElement {
|
|
18
23
|
static observedAttributes = [
|
|
19
24
|
"disabled",
|
|
25
|
+
"lights",
|
|
20
26
|
"max",
|
|
21
|
-
"min"
|
|
27
|
+
"min",
|
|
28
|
+
"origin",
|
|
29
|
+
"scale"
|
|
22
30
|
];
|
|
23
31
|
get level() {
|
|
24
32
|
return this.#level;
|
|
25
33
|
}
|
|
26
34
|
set level(amplitude) {
|
|
27
35
|
if (!Number.isFinite(amplitude)) return;
|
|
28
|
-
const decibels = toDecibels(amplitude);
|
|
29
36
|
const now = performance.now();
|
|
30
37
|
this.#level = amplitude;
|
|
38
|
+
if (this.scale === "linear") {
|
|
39
|
+
this.#render(now);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const decibels = toDecibels(amplitude);
|
|
31
43
|
this.#target = decibels;
|
|
32
44
|
this.#bar = Math.max(this.#bar, decibels);
|
|
33
45
|
if (decibels >= this.#peak) {
|
|
@@ -38,6 +50,12 @@ var SonicMeter = class extends SonicElement {
|
|
|
38
50
|
this.#render(now);
|
|
39
51
|
this.#schedule(now);
|
|
40
52
|
}
|
|
53
|
+
get lights() {
|
|
54
|
+
return parseNumberList(this.getAttribute("lights"));
|
|
55
|
+
}
|
|
56
|
+
set lights(thresholds) {
|
|
57
|
+
this.reflect("lights", thresholds?.join(" "));
|
|
58
|
+
}
|
|
41
59
|
get max() {
|
|
42
60
|
return this.numberAttribute("max", 0);
|
|
43
61
|
}
|
|
@@ -56,24 +74,39 @@ var SonicMeter = class extends SonicElement {
|
|
|
56
74
|
set orientation(direction) {
|
|
57
75
|
this.reflect("orientation", direction);
|
|
58
76
|
}
|
|
77
|
+
get origin() {
|
|
78
|
+
return this.optionalNumberAttribute("origin");
|
|
79
|
+
}
|
|
80
|
+
set origin(value) {
|
|
81
|
+
this.reflect("origin", value);
|
|
82
|
+
}
|
|
83
|
+
get scale() {
|
|
84
|
+
return this.getAttribute("scale") === "linear" ? "linear" : "db";
|
|
85
|
+
}
|
|
86
|
+
set scale(scale) {
|
|
87
|
+
this.reflect("scale", scale);
|
|
88
|
+
}
|
|
59
89
|
#bar = -Infinity;
|
|
60
90
|
#clipAt = -Infinity;
|
|
61
91
|
#frame;
|
|
62
92
|
#lastFrame;
|
|
63
93
|
#level = 0;
|
|
94
|
+
#lights;
|
|
64
95
|
#meter = renderMeter();
|
|
65
96
|
#peak = -Infinity;
|
|
66
97
|
#peakAt = -Infinity;
|
|
67
98
|
#target = -Infinity;
|
|
68
99
|
attributeChangedCallback() {
|
|
69
100
|
const now = performance.now();
|
|
101
|
+
this.#renderLights();
|
|
70
102
|
this.#render(now);
|
|
71
103
|
this.#schedule(now);
|
|
72
104
|
}
|
|
73
105
|
connect(signal) {
|
|
74
106
|
const now = performance.now();
|
|
75
|
-
this.upgradeProperties("max", "min", "orientation", "level");
|
|
107
|
+
this.upgradeProperties("lights", "max", "min", "orientation", "origin", "scale", "level");
|
|
76
108
|
this.appendOnce(this.#meter);
|
|
109
|
+
this.#renderLights();
|
|
77
110
|
this.#render(now);
|
|
78
111
|
this.#schedule(now);
|
|
79
112
|
this.checkStyles(this.#meter, "meter.css");
|
|
@@ -83,21 +116,25 @@ var SonicMeter = class extends SonicElement {
|
|
|
83
116
|
this.#lastFrame = void 0;
|
|
84
117
|
}, { once: true });
|
|
85
118
|
}
|
|
86
|
-
#fraction(
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
return
|
|
119
|
+
#fraction(level) {
|
|
120
|
+
const lights = this.#lights;
|
|
121
|
+
if (lights) return lights.filter((threshold) => threshold <= level).length / lights.length;
|
|
122
|
+
return linearTaper(this.min, this.max).position(level);
|
|
90
123
|
}
|
|
91
124
|
#isSettled(now) {
|
|
125
|
+
if (this.scale === "linear") return true;
|
|
92
126
|
const floor = this.min;
|
|
93
127
|
return this.#bar <= Math.max(this.#target, floor) && this.#peak <= Math.max(this.#bar, floor) && now - this.#clipAt >= holdMs;
|
|
94
128
|
}
|
|
95
129
|
#render(now) {
|
|
96
130
|
const meter = this.#meter;
|
|
131
|
+
const origin = this.origin === void 0 ? 0 : this.#fraction(this.origin);
|
|
97
132
|
meter.style.setProperty("--_sonic-meter-min", String(this.min));
|
|
98
133
|
meter.style.setProperty("--_sonic-meter-max", String(this.max));
|
|
99
|
-
|
|
100
|
-
|
|
134
|
+
meter.style.setProperty("--_sonic-meter-origin", String(origin));
|
|
135
|
+
if (this.disabled || this.scale === "linear") {
|
|
136
|
+
const level = this.disabled ? origin : this.#fraction(this.#level);
|
|
137
|
+
meter.style.setProperty("--_sonic-meter-level", String(level));
|
|
101
138
|
meter.style.setProperty("--_sonic-meter-peak", "0");
|
|
102
139
|
meter.style.setProperty("--_sonic-meter-clipped", "0");
|
|
103
140
|
return;
|
|
@@ -106,6 +143,23 @@ var SonicMeter = class extends SonicElement {
|
|
|
106
143
|
meter.style.setProperty("--_sonic-meter-peak", String(this.#fraction(this.#peak)));
|
|
107
144
|
meter.style.setProperty("--_sonic-meter-clipped", now - this.#clipAt < holdMs ? "1" : "0");
|
|
108
145
|
}
|
|
146
|
+
#renderLights() {
|
|
147
|
+
const meter = this.#meter;
|
|
148
|
+
const lights = this.lights;
|
|
149
|
+
this.#lights = lights;
|
|
150
|
+
this.toggleState("ladder", lights !== void 0);
|
|
151
|
+
if (!lights) {
|
|
152
|
+
for (const name of [
|
|
153
|
+
"count",
|
|
154
|
+
"hot-lights",
|
|
155
|
+
"clip-lights"
|
|
156
|
+
]) meter.style.removeProperty(`--_sonic-meter-${name}`);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
meter.style.setProperty("--_sonic-meter-count", String(lights.length));
|
|
160
|
+
meter.style.setProperty("--_sonic-meter-hot-lights", lightsBelow(lights, "hot"));
|
|
161
|
+
meter.style.setProperty("--_sonic-meter-clip-lights", lightsBelow(lights, "clip"));
|
|
162
|
+
}
|
|
109
163
|
#schedule(now) {
|
|
110
164
|
if (this.#frame !== void 0 || !this.isConnected || this.#isSettled(now)) return;
|
|
111
165
|
if (this.#lastFrame === void 0) this.#lastFrame = now;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { requireChild, template } from "../lib/render.js";
|
|
2
|
+
import { readPxProperty } from "../lib/read-px-property.js";
|
|
3
|
+
import { SonicRangeElement } from "./range-element.js";
|
|
4
|
+
|
|
5
|
+
//#region src/elements/number.ts
|
|
6
|
+
const renderNumber = template(`
|
|
7
|
+
<div class="sonic-number" role="spinbutton" tabindex="0">
|
|
8
|
+
<span aria-hidden="true" class="sonic-number-value"></span>
|
|
9
|
+
<input
|
|
10
|
+
autocomplete="off"
|
|
11
|
+
class="sonic-number-entry"
|
|
12
|
+
enterkeyhint="done"
|
|
13
|
+
hidden
|
|
14
|
+
spellcheck="false"
|
|
15
|
+
type="text"
|
|
16
|
+
/>
|
|
17
|
+
</div>
|
|
18
|
+
`, HTMLDivElement);
|
|
19
|
+
const fallbackTravelPx = 160;
|
|
20
|
+
var SonicNumber = class extends SonicRangeElement {
|
|
21
|
+
#number = renderNumber();
|
|
22
|
+
#digits = requireChild(this.#number, ".sonic-number-value", HTMLSpanElement);
|
|
23
|
+
connect(signal) {
|
|
24
|
+
const number = this.#number;
|
|
25
|
+
this.appendOnce(number);
|
|
26
|
+
this.render();
|
|
27
|
+
this.checkStyles(number, "number.css");
|
|
28
|
+
this.bindGestures(number, signal, () => ({
|
|
29
|
+
position: (event) => -event.clientY,
|
|
30
|
+
travelPx: readPxProperty(getComputedStyle(number), "--_sonic-number-travel", fallbackTravelPx)
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
controlRole() {
|
|
34
|
+
return "spinbutton";
|
|
35
|
+
}
|
|
36
|
+
focusTarget() {
|
|
37
|
+
return this.#number;
|
|
38
|
+
}
|
|
39
|
+
render() {
|
|
40
|
+
this.#digits.textContent = this.valueText();
|
|
41
|
+
this.renderAria(this.#number);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
//#endregion
|
|
46
|
+
export { SonicNumber };
|