@xsynaptic/sonic-ui 0.28.0 → 0.28.1
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 +6 -0
- package/dist/default/elements/ticker.js +24 -6
- package/dist/dev/elements/meter.d.ts +1 -0
- package/dist/dev/elements/position-group.d.ts +1 -0
- package/dist/dev/elements/spectrum.d.ts +1 -0
- package/dist/dev/elements/ticker.d.ts +1 -1
- package/dist/dev/elements/ticker.js +24 -6
- package/dist/dev/elements/ticker.js.map +1 -1
- package/dist/dev/elements/value-element.d.ts +1 -0
- package/dist/dev/elements/wavestrip.d.ts +1 -0
- package/dist/dev/lib/crossfade.d.ts +1 -0
- package/dist/styles/ticker.css +3 -3
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @xsynaptic/sonic-ui
|
|
2
2
|
|
|
3
|
+
## 0.28.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Ticker: setting `text` to the text it already shows no longer sends the tape back to the start, and `disabled` now holds the ticker at rest with no scrolling and no drag.
|
|
8
|
+
|
|
3
9
|
## 0.28.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
|
@@ -17,7 +17,7 @@ const fadePx = 12;
|
|
|
17
17
|
const holdMs = 2e3;
|
|
18
18
|
const ratePxPerSecond = 40;
|
|
19
19
|
var SonicTicker = class extends SonicElement {
|
|
20
|
-
static observedAttributes = ["paused"];
|
|
20
|
+
static observedAttributes = ["disabled", "paused"];
|
|
21
21
|
get cancellable() {
|
|
22
22
|
return this.hasAttribute("cancellable");
|
|
23
23
|
}
|
|
@@ -34,12 +34,15 @@ var SonicTicker = class extends SonicElement {
|
|
|
34
34
|
return this.#originals().map((original) => original.textContent).join("");
|
|
35
35
|
}
|
|
36
36
|
set text(text) {
|
|
37
|
+
const next = text ?? "";
|
|
38
|
+
if (this.#holds(next)) return;
|
|
37
39
|
for (const original of this.#originals()) original.remove();
|
|
38
|
-
if (
|
|
40
|
+
if (next !== "") this.prepend(next);
|
|
39
41
|
}
|
|
40
42
|
control = renderTicker();
|
|
41
43
|
sheet = "ticker.css";
|
|
42
44
|
sheetToken = "--_sonic-ticker-fade";
|
|
45
|
+
#drag;
|
|
43
46
|
#fade = fadePx;
|
|
44
47
|
#heading = 1;
|
|
45
48
|
#isClickSwallowed = false;
|
|
@@ -52,22 +55,31 @@ var SonicTicker = class extends SonicElement {
|
|
|
52
55
|
#position = 0;
|
|
53
56
|
#reducedMotion = matchMedia("(prefers-reduced-motion: reduce)");
|
|
54
57
|
#running;
|
|
58
|
+
#tape = requireChild(this.control, ".sonic-ticker-tape", HTMLSpanElement);
|
|
55
59
|
#travel = {
|
|
56
60
|
distance: 0,
|
|
57
61
|
hold: holdMs,
|
|
58
62
|
rate: ratePxPerSecond
|
|
59
63
|
};
|
|
60
|
-
attributeChangedCallback() {
|
|
64
|
+
attributeChangedCallback(name) {
|
|
65
|
+
if (name === "disabled" && this.isBound()) {
|
|
66
|
+
this.#drag?.end();
|
|
67
|
+
this.#run(this.#tape, {
|
|
68
|
+
from: 0,
|
|
69
|
+
heading: 1
|
|
70
|
+
});
|
|
71
|
+
}
|
|
61
72
|
this.render();
|
|
62
73
|
}
|
|
63
74
|
connect(signal) {
|
|
64
75
|
const control = this.control;
|
|
65
|
-
const tape =
|
|
76
|
+
const tape = this.#tape;
|
|
66
77
|
const measure = () => {
|
|
67
78
|
this.#measure(tape);
|
|
68
79
|
};
|
|
69
80
|
const observer = new ResizeObserver(measure);
|
|
70
81
|
const drag = this.#bindDrag(tape, signal);
|
|
82
|
+
this.#drag = drag;
|
|
71
83
|
this.upgradeProperties("cancellable", "paused", "text");
|
|
72
84
|
mirrorChildren(this, {
|
|
73
85
|
canCopyLinks: true,
|
|
@@ -117,7 +129,7 @@ var SonicTicker = class extends SonicElement {
|
|
|
117
129
|
}, { signal });
|
|
118
130
|
return bindDrag(control, {
|
|
119
131
|
grab: (event) => {
|
|
120
|
-
if (this.#travel.distance <= 0) return;
|
|
132
|
+
if (this.#travel.distance <= 0 || this.isDisabled()) return;
|
|
121
133
|
return {
|
|
122
134
|
from: 0,
|
|
123
135
|
isDragging: false,
|
|
@@ -193,6 +205,12 @@ var SonicTicker = class extends SonicElement {
|
|
|
193
205
|
view.disconnect();
|
|
194
206
|
}, { once: true });
|
|
195
207
|
}
|
|
208
|
+
#holds(text) {
|
|
209
|
+
const [only, ...rest] = this.#originals();
|
|
210
|
+
if (only === void 0) return text === "";
|
|
211
|
+
if (rest.length > 0 || !(only instanceof Text)) return false;
|
|
212
|
+
return only.data === text;
|
|
213
|
+
}
|
|
196
214
|
#isPaused() {
|
|
197
215
|
return this.paused || this.#isHovered || this.#isPressed || this.#isOffScreen || this.control.closest(":focus-visible") !== null;
|
|
198
216
|
}
|
|
@@ -226,7 +244,7 @@ var SonicTicker = class extends SonicElement {
|
|
|
226
244
|
this.#writeFades(this.#position);
|
|
227
245
|
}
|
|
228
246
|
#run(tape, departure = this.#where()) {
|
|
229
|
-
const leg = !this.#isFocusInside && !this.#reducedMotion.matches && !this.hasState("dragging") ? tickerLeg(this.#travel, departure) : void 0;
|
|
247
|
+
const leg = !this.#isFocusInside && !this.#reducedMotion.matches && !this.hasState("dragging") && !this.isDisabled() ? tickerLeg(this.#travel, departure) : void 0;
|
|
230
248
|
this.#stop();
|
|
231
249
|
this.#heading = departure.heading;
|
|
232
250
|
if (leg) this.#start(tape, leg);
|
|
@@ -17,7 +17,7 @@ export declare class SonicTicker extends SonicElement {
|
|
|
17
17
|
protected readonly control: HTMLSpanElement;
|
|
18
18
|
protected readonly sheet = "ticker.css";
|
|
19
19
|
protected readonly sheetToken = "--_sonic-ticker-fade";
|
|
20
|
-
attributeChangedCallback(): void;
|
|
20
|
+
attributeChangedCallback(name: string): void;
|
|
21
21
|
protected connect(signal: AbortSignal): void;
|
|
22
22
|
protected render(): void;
|
|
23
23
|
}
|
|
@@ -17,7 +17,7 @@ const fadePx = 12;
|
|
|
17
17
|
const holdMs = 2e3;
|
|
18
18
|
const ratePxPerSecond = 40;
|
|
19
19
|
var SonicTicker = class extends SonicElement {
|
|
20
|
-
static observedAttributes = ["paused"];
|
|
20
|
+
static observedAttributes = ["disabled", "paused"];
|
|
21
21
|
get cancellable() {
|
|
22
22
|
return this.hasAttribute("cancellable");
|
|
23
23
|
}
|
|
@@ -34,12 +34,15 @@ var SonicTicker = class extends SonicElement {
|
|
|
34
34
|
return this.#originals().map((original) => original.textContent).join("");
|
|
35
35
|
}
|
|
36
36
|
set text(text) {
|
|
37
|
+
const next = text ?? "";
|
|
38
|
+
if (this.#holds(next)) return;
|
|
37
39
|
for (const original of this.#originals()) original.remove();
|
|
38
|
-
if (
|
|
40
|
+
if (next !== "") this.prepend(next);
|
|
39
41
|
}
|
|
40
42
|
control = renderTicker();
|
|
41
43
|
sheet = "ticker.css";
|
|
42
44
|
sheetToken = "--_sonic-ticker-fade";
|
|
45
|
+
#drag;
|
|
43
46
|
#fade = fadePx;
|
|
44
47
|
#heading = 1;
|
|
45
48
|
#isClickSwallowed = false;
|
|
@@ -52,22 +55,31 @@ var SonicTicker = class extends SonicElement {
|
|
|
52
55
|
#position = 0;
|
|
53
56
|
#reducedMotion = matchMedia("(prefers-reduced-motion: reduce)");
|
|
54
57
|
#running;
|
|
58
|
+
#tape = requireChild(this.control, ".sonic-ticker-tape", HTMLSpanElement);
|
|
55
59
|
#travel = {
|
|
56
60
|
distance: 0,
|
|
57
61
|
hold: holdMs,
|
|
58
62
|
rate: ratePxPerSecond
|
|
59
63
|
};
|
|
60
|
-
attributeChangedCallback() {
|
|
64
|
+
attributeChangedCallback(name) {
|
|
65
|
+
if (name === "disabled" && this.isBound()) {
|
|
66
|
+
this.#drag?.end();
|
|
67
|
+
this.#run(this.#tape, {
|
|
68
|
+
from: 0,
|
|
69
|
+
heading: 1
|
|
70
|
+
});
|
|
71
|
+
}
|
|
61
72
|
this.render();
|
|
62
73
|
}
|
|
63
74
|
connect(signal) {
|
|
64
75
|
const control = this.control;
|
|
65
|
-
const tape =
|
|
76
|
+
const tape = this.#tape;
|
|
66
77
|
const measure = () => {
|
|
67
78
|
this.#measure(tape);
|
|
68
79
|
};
|
|
69
80
|
const observer = new ResizeObserver(measure);
|
|
70
81
|
const drag = this.#bindDrag(tape, signal);
|
|
82
|
+
this.#drag = drag;
|
|
71
83
|
this.upgradeProperties("cancellable", "paused", "text");
|
|
72
84
|
mirrorChildren(this, {
|
|
73
85
|
canCopyLinks: true,
|
|
@@ -117,7 +129,7 @@ var SonicTicker = class extends SonicElement {
|
|
|
117
129
|
}, { signal });
|
|
118
130
|
return bindDrag(control, {
|
|
119
131
|
grab: (event) => {
|
|
120
|
-
if (this.#travel.distance <= 0) return;
|
|
132
|
+
if (this.#travel.distance <= 0 || this.isDisabled()) return;
|
|
121
133
|
return {
|
|
122
134
|
from: 0,
|
|
123
135
|
isDragging: false,
|
|
@@ -193,6 +205,12 @@ var SonicTicker = class extends SonicElement {
|
|
|
193
205
|
view.disconnect();
|
|
194
206
|
}, { once: true });
|
|
195
207
|
}
|
|
208
|
+
#holds(text) {
|
|
209
|
+
const [only, ...rest] = this.#originals();
|
|
210
|
+
if (only === void 0) return text === "";
|
|
211
|
+
if (rest.length > 0 || !(only instanceof Text)) return false;
|
|
212
|
+
return only.data === text;
|
|
213
|
+
}
|
|
196
214
|
#isPaused() {
|
|
197
215
|
return this.paused || this.#isHovered || this.#isPressed || this.#isOffScreen || this.control.closest(":focus-visible") !== null;
|
|
198
216
|
}
|
|
@@ -226,7 +244,7 @@ var SonicTicker = class extends SonicElement {
|
|
|
226
244
|
this.#writeFades(this.#position);
|
|
227
245
|
}
|
|
228
246
|
#run(tape, departure = this.#where()) {
|
|
229
|
-
const leg = !this.#isFocusInside && !this.#reducedMotion.matches && !this.hasState("dragging") ? tickerLeg(this.#travel, departure) : void 0;
|
|
247
|
+
const leg = !this.#isFocusInside && !this.#reducedMotion.matches && !this.hasState("dragging") && !this.isDisabled() ? tickerLeg(this.#travel, departure) : void 0;
|
|
230
248
|
this.#stop();
|
|
231
249
|
this.#heading = departure.heading;
|
|
232
250
|
if (leg) this.#start(tape, leg);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ticker.js","names":[],"sources":["../../../src/elements/ticker.ts"],"sourcesContent":["import type { TickerDeparture, TickerHeading, TickerLeg, TickerTravel } from '#lib/ticker-leg.ts';\n\nimport { SonicElement } from '#elements/sonic-element.ts';\nimport { outsideCancelZone } from '#lib/cancel-zone.ts';\nimport { copyNode } from '#lib/copy-node.ts';\nimport { dragThresholdPx } from '#lib/drag-step.ts';\nimport { clamp } from '#lib/math.ts';\nimport { mirrorChildren } from '#lib/mirror-children.ts';\nimport { bindDrag, capturePointer } from '#lib/pointer-drag.ts';\nimport { readMsProperty } from '#lib/read-ms-property.ts';\nimport { readPxProperty } from '#lib/read-px-property.ts';\nimport { placeChildren, requireChild, template } from '#lib/render.ts';\nimport {\n\tclippedEnds,\n\tfadeWidth,\n\tlegDeparture,\n\tlegFades,\n\tlegPosition,\n\ttickerLeg,\n} from '#lib/ticker-leg.ts';\nimport { writeAttribute } from '#lib/write-attribute.ts';\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sonic-ticker': SonicTicker;\n\t}\n}\n\nconst renderTicker = template(\n\t/* HTML */ `<span class=\"sonic-ticker\"><span class=\"sonic-ticker-tape\"></span></span>`,\n\tHTMLSpanElement,\n);\n\nconst fadePx = 12;\n\nconst holdMs = 2000;\n\nconst ratePxPerSecond = 40;\n\ninterface Running {\n\tanimation: Animation;\n\tfades: Array<Animation>;\n\tleg: TickerLeg;\n}\n\ninterface TapeDrag {\n\tfrom: number;\n\tisDragging: boolean;\n\toutside: ((event: PointerEvent) => boolean) | undefined;\n\tthresholdPx: number;\n\tx: number;\n}\n\nexport class SonicTicker extends SonicElement {\n\tstatic override readonly observedAttributes = ['paused'];\n\n\t// fallow-ignore-next-line code-duplication -- one accessor pair per reflected attribute\n\tget cancellable(): boolean {\n\t\treturn this.hasAttribute('cancellable');\n\t}\n\n\tset cancellable(isCancellable: boolean) {\n\t\tthis.reflect('cancellable', isCancellable);\n\t}\n\n\tget paused(): boolean {\n\t\treturn this.hasAttribute('paused');\n\t}\n\n\tset paused(isPaused: boolean) {\n\t\tthis.reflect('paused', isPaused);\n\t}\n\n\tget text(): string {\n\t\treturn this.#originals()\n\t\t\t.map((original) => original.textContent)\n\t\t\t.join('');\n\t}\n\n\tset text(text: string | undefined) {\n\t\tfor (const original of this.#originals()) original.remove();\n\t\tif (text !== undefined && text !== '') this.prepend(text);\n\t}\n\n\tprotected override readonly control = renderTicker();\n\n\tprotected override readonly sheet = 'ticker.css';\n\n\tprotected override readonly sheetToken = '--_sonic-ticker-fade';\n\n\t#fade = fadePx;\n\n\t#heading: TickerHeading = 1;\n\n\t#isClickSwallowed = false;\n\n\t#isFocusInside = false;\n\n\t#isHovered = false;\n\n\t#isOffScreen = false;\n\n\t#isPressed = false;\n\n\t#mark: ReturnType<typeof setTimeout> | undefined;\n\n\t#measured = '';\n\n\t#position = 0;\n\n\treadonly #reducedMotion = matchMedia('(prefers-reduced-motion: reduce)');\n\n\t#running: Running | undefined;\n\n\t#travel: TickerTravel = { distance: 0, hold: holdMs, rate: ratePxPerSecond };\n\n\tattributeChangedCallback(): void {\n\t\tthis.render();\n\t}\n\n\tprotected connect(signal: AbortSignal): void {\n\t\tconst control = this.control;\n\t\tconst tape = requireChild(control, '.sonic-ticker-tape', HTMLSpanElement);\n\t\tconst measure = (): void => {\n\t\t\tthis.#measure(tape);\n\t\t};\n\t\tconst observer = new ResizeObserver(measure);\n\t\tconst drag = this.#bindDrag(tape, signal);\n\n\t\tthis.upgradeProperties('cancellable', 'paused', 'text');\n\t\tmirrorChildren(\n\t\t\tthis,\n\t\t\t{\n\t\t\t\tcanCopyLinks: true,\n\t\t\t\tcontrol,\n\t\t\t\tcopy: copyNode,\n\t\t\t\tplace: (copies) => {\n\t\t\t\t\tplaceChildren(tape, copies);\n\t\t\t\t\tdrag.end();\n\t\t\t\t\tthis.#measure(tape, { from: 0, heading: 1 });\n\t\t\t\t},\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t\tthis.render();\n\n\t\tobserver.observe(control);\n\t\tobserver.observe(tape);\n\t\tif ('fonts' in document) document.fonts.addEventListener('loadingdone', measure, { signal });\n\t\tthis.#bindFocus(tape, signal);\n\t\tthis.#bindPauses(signal);\n\t\tthis.#reducedMotion.addEventListener(\n\t\t\t'change',\n\t\t\t() => {\n\t\t\t\tthis.#run(tape);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tobserver.disconnect();\n\t\t\t\tthis.#stop();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\tprotected render(): void {\n\t\tif (!this.isBound()) return;\n\n\t\tthis.toggleState('paused', this.paused);\n\t\tthis.#syncPause();\n\t}\n\n\t#bindDrag(tape: HTMLElement, signal: AbortSignal): { end: () => void } {\n\t\tconst control = this.control;\n\n\t\tcontrol.addEventListener(\n\t\t\t'click',\n\t\t\t(event) => {\n\t\t\t\tif (!this.#isClickSwallowed) return;\n\n\t\t\t\tthis.#isClickSwallowed = false;\n\t\t\t\tevent.preventDefault();\n\t\t\t\tevent.stopPropagation();\n\t\t\t},\n\t\t\t{ capture: true, signal },\n\t\t);\n\t\t// In WebKit, dragging a link that wraps the ticker fires `dragstart` on the link, outside the control\n\t\tthis.getRootNode().addEventListener(\n\t\t\t'dragstart',\n\t\t\t(event) => {\n\t\t\t\tif (this.#isPressed) event.preventDefault();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\n\t\treturn bindDrag<TapeDrag>(\n\t\t\tcontrol,\n\t\t\t{\n\t\t\t\tgrab: (event) => {\n\t\t\t\t\tif (this.#travel.distance <= 0) return;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tfrom: 0,\n\t\t\t\t\t\tisDragging: false,\n\t\t\t\t\t\toutside: undefined,\n\t\t\t\t\t\tthresholdPx: dragThresholdPx(event.pointerType),\n\t\t\t\t\t\tx: event.clientX,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\tisCaptureLate: true,\n\t\t\t\tmove: (held, event) => {\n\t\t\t\t\tif (!held.isDragging) {\n\t\t\t\t\t\tif (Math.abs(event.clientX - held.x) < held.thresholdPx) return;\n\n\t\t\t\t\t\tconst { from, heading } = this.#where();\n\n\t\t\t\t\t\theld.isDragging = true;\n\t\t\t\t\t\theld.from = from;\n\t\t\t\t\t\theld.outside = this.cancellable\n\t\t\t\t\t\t\t? outsideCancelZone(control, '--_sonic-ticker-cancel-zone')\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\theld.x = event.clientX;\n\t\t\t\t\t\tcapturePointer(control, event.pointerId);\n\t\t\t\t\t\tthis.toggleState('dragging', true);\n\t\t\t\t\t\tthis.#stop();\n\t\t\t\t\t\tthis.#heading = heading;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst isOutside = held.outside?.(event) === true;\n\n\t\t\t\t\tthis.toggleState('cancelling', isOutside);\n\t\t\t\t\tthis.#place(tape, isOutside ? held.from : held.from - (event.clientX - held.x));\n\t\t\t\t},\n\t\t\t\trelease: (held) => {\n\t\t\t\t\tif (!held.isDragging) return;\n\n\t\t\t\t\t// Safari sends no click after a drag, so the flag is cleared on a timer or it would cancel the next real click\n\t\t\t\t\tthis.#isClickSwallowed = true;\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tthis.#isClickSwallowed = false;\n\t\t\t\t\t}, 0);\n\t\t\t\t\tthis.toggleState('dragging', false);\n\t\t\t\t\tthis.toggleState('cancelling', false);\n\t\t\t\t\tthis.#run(tape);\n\t\t\t\t},\n\t\t\t\ttoggle: (isPressed) => {\n\t\t\t\t\tthis.#isPressed = isPressed;\n\t\t\t\t\tthis.#syncPause();\n\t\t\t\t},\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t#bindFocus(tape: HTMLElement, signal: AbortSignal): void {\n\t\tconst control = this.control;\n\n\t\tcontrol.addEventListener(\n\t\t\t'focusout',\n\t\t\t(event) => {\n\t\t\t\tif (event.relatedTarget instanceof Node && control.contains(event.relatedTarget)) return;\n\n\t\t\t\tcontrol.scrollLeft = 0;\n\t\t\t\tthis.#isFocusInside = false;\n\t\t\t\tthis.#run(tape);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tcontrol.addEventListener(\n\t\t\t'focusin',\n\t\t\t(event) => {\n\t\t\t\tthis.#isFocusInside = true;\n\t\t\t\tthis.#run(tape);\n\t\t\t\tif (event.target instanceof Element) event.target.scrollIntoView({ block: 'nearest' });\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t}\n\n\t#bindPauses(signal: AbortSignal): void {\n\t\tconst control = this.control;\n\n\t\tfor (const type of ['pointerenter', 'pointerleave'] as const) {\n\t\t\tcontrol.addEventListener(\n\t\t\t\ttype,\n\t\t\t\t(event) => {\n\t\t\t\t\tif (event.pointerType !== 'mouse') return;\n\n\t\t\t\t\tthis.#isHovered = type === 'pointerenter';\n\t\t\t\t\tthis.#syncPause();\n\t\t\t\t},\n\t\t\t\t{ signal },\n\t\t\t);\n\t\t}\n\t\tfor (const type of ['focusin', 'focusout'] as const) {\n\t\t\tthis.getRootNode().addEventListener(\n\t\t\t\ttype,\n\t\t\t\t() => {\n\t\t\t\t\tthis.#syncPause();\n\t\t\t\t},\n\t\t\t\t{ signal },\n\t\t\t);\n\t\t}\n\n\t\tconst view = new IntersectionObserver((entries) => {\n\t\t\tthis.#isOffScreen = entries.at(-1)?.isIntersecting === false;\n\t\t\tthis.#syncPause();\n\t\t});\n\n\t\tview.observe(control);\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tview.disconnect();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\t#isPaused(): boolean {\n\t\treturn (\n\t\t\tthis.paused ||\n\t\t\tthis.#isHovered ||\n\t\t\tthis.#isPressed ||\n\t\t\tthis.#isOffScreen ||\n\t\t\tthis.control.closest(':focus-visible') !== null\n\t\t);\n\t}\n\n\t#measure(tape: HTMLElement, departure?: TickerDeparture): void {\n\t\tconst control = this.control;\n\t\tconst styles = getComputedStyle(control);\n\t\tconst box =\n\t\t\tcontrol.clientWidth -\n\t\t\treadPxProperty(styles, 'padding-left', 0) -\n\t\t\treadPxProperty(styles, 'padding-right', 0);\n\t\tconst travel = {\n\t\t\tdistance: Math.max(0, Math.round(tape.offsetWidth - box)),\n\t\t\thold: readMsProperty(styles, '--_sonic-ticker-hold', holdMs),\n\t\t\trate: readPxProperty(styles, '--_sonic-ticker-rate', ratePxPerSecond),\n\t\t};\n\t\tconst fade = readPxProperty(styles, '--_sonic-ticker-fade', fadePx);\n\t\tconst measured = [...Object.values(travel), fade].join(' ');\n\t\tif (!departure && measured === this.#measured) return;\n\n\t\tconst from = departure ?? this.#where();\n\n\t\tthis.#fade = fade;\n\t\tthis.#measured = measured;\n\t\tthis.#travel = travel;\n\t\tthis.toggleState('overflowing', travel.distance > 0);\n\t\tthis.#run(tape, from);\n\t}\n\n\t#originals(): Array<ChildNode> {\n\t\treturn [...this.childNodes].filter((child) => child !== this.control);\n\t}\n\n\t#place(tape: HTMLElement, position: number): void {\n\t\tconst { distance } = this.#travel;\n\n\t\tthis.#position = clamp(position, 0, distance);\n\t\ttape.style.translate = this.#position > 0 ? `${String(-this.#position)}px` : '';\n\t\twriteAttribute(this.control, 'data-sonic-clipped', clippedEnds(this.#position, distance));\n\t\tthis.#writeFades(this.#position);\n\t}\n\n\t#run(tape: HTMLElement, departure: TickerDeparture = this.#where()): void {\n\t\tconst canTravel =\n\t\t\t!this.#isFocusInside && !this.#reducedMotion.matches && !this.hasState('dragging');\n\t\tconst leg = canTravel ? tickerLeg(this.#travel, departure) : undefined;\n\n\t\tthis.#stop();\n\t\tthis.#heading = departure.heading;\n\t\tif (leg) this.#start(tape, leg);\n\t\telse this.#place(tape, this.#isFocusInside ? 0 : departure.from);\n\t}\n\n\t#start(tape: HTMLElement, leg: TickerLeg): void {\n\t\tconst animation = tape.animate(\n\t\t\t{ translate: [`${String(-leg.from)}px`, `${String(-leg.to)}px`] },\n\t\t\t{ delay: leg.hold, duration: leg.duration, fill: 'both' },\n\t\t);\n\n\t\tanimation.addEventListener('finish', () => {\n\t\t\tthis.#run(tape, { from: leg.to, heading: leg.heading });\n\t\t});\n\t\tthis.#running = { animation, fades: [], leg };\n\t\ttape.style.translate = '';\n\t\twriteAttribute(\n\t\t\tthis.control,\n\t\t\t'data-sonic-clipped',\n\t\t\tclippedEnds(leg.from, this.#travel.distance),\n\t\t);\n\t\tthis.#syncPause();\n\t}\n\n\t#startFades(leg: TickerLeg, elapsed: number): Array<Animation> {\n\t\tconst fades = legFades(leg, this.#travel.distance, this.#fade);\n\n\t\treturn (['start', 'end'] as const).flatMap((end) => {\n\t\t\tconst { delay, duration, widths } = fades[end];\n\t\t\tif (duration <= 0 || delay + duration <= elapsed) return [];\n\n\t\t\treturn this.control.animate(\n\t\t\t\t{ [`--_sonic-ticker-fade-${end}`]: widths.map((width) => `${String(width)}px`) },\n\t\t\t\t{ delay: delay - elapsed, duration, fill: 'both' },\n\t\t\t);\n\t\t});\n\t}\n\n\t#stop(): void {\n\t\tconst running = this.#running;\n\n\t\tclearTimeout(this.#mark);\n\t\tif (!running) return;\n\n\t\tfor (const fade of running.fades) fade.cancel();\n\t\trunning.animation.cancel();\n\t\tthis.#running = undefined;\n\t}\n\n\t// Calling `play()` on a finished animation restarts it, so the fades are recreated on resume, not paused\n\t#syncPause(): void {\n\t\tconst running = this.#running;\n\t\tif (!running) return;\n\n\t\tconst { animation, leg } = running;\n\t\tconst elapsed = Number(animation.currentTime);\n\n\t\tclearTimeout(this.#mark);\n\t\tfor (const fade of running.fades) fade.cancel();\n\t\trunning.fades = [];\n\t\tthis.#writeFades(legPosition(leg, elapsed));\n\t\tif (elapsed >= leg.hold) writeAttribute(this.control, 'data-sonic-clipped', 'start end');\n\t\tif (this.#isPaused()) {\n\t\t\tanimation.pause();\n\t\t\treturn;\n\t\t}\n\t\tif (animation.playState === 'paused') animation.play();\n\t\trunning.fades = this.#startFades(leg, elapsed);\n\t\tif (elapsed >= leg.hold) return;\n\n\t\tthis.#mark = setTimeout(() => {\n\t\t\twriteAttribute(this.control, 'data-sonic-clipped', 'start end');\n\t\t}, leg.hold - elapsed);\n\t}\n\n\t#where(): TickerDeparture {\n\t\tconst running = this.#running;\n\t\tif (!running) return { from: this.#position, heading: this.#heading };\n\n\t\treturn legDeparture(running.leg, Number(running.animation.currentTime));\n\t}\n\n\t#writeFades(position: number): void {\n\t\tconst { style } = this.control;\n\n\t\tstyle.setProperty('--_sonic-ticker-fade-start', `${String(fadeWidth(position, this.#fade))}px`);\n\t\tstyle.setProperty(\n\t\t\t'--_sonic-ticker-fade-end',\n\t\t\t`${String(fadeWidth(this.#travel.distance - position, this.#fade))}px`,\n\t\t);\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ticker.js","names":[],"sources":["../../../src/elements/ticker.ts"],"sourcesContent":["import type { TickerDeparture, TickerHeading, TickerLeg, TickerTravel } from '#lib/ticker-leg.ts';\n\nimport { SonicElement } from '#elements/sonic-element.ts';\nimport { outsideCancelZone } from '#lib/cancel-zone.ts';\nimport { copyNode } from '#lib/copy-node.ts';\nimport { dragThresholdPx } from '#lib/drag-step.ts';\nimport { clamp } from '#lib/math.ts';\nimport { mirrorChildren } from '#lib/mirror-children.ts';\nimport { bindDrag, capturePointer } from '#lib/pointer-drag.ts';\nimport { readMsProperty } from '#lib/read-ms-property.ts';\nimport { readPxProperty } from '#lib/read-px-property.ts';\nimport { placeChildren, requireChild, template } from '#lib/render.ts';\nimport {\n\tclippedEnds,\n\tfadeWidth,\n\tlegDeparture,\n\tlegFades,\n\tlegPosition,\n\ttickerLeg,\n} from '#lib/ticker-leg.ts';\nimport { writeAttribute } from '#lib/write-attribute.ts';\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sonic-ticker': SonicTicker;\n\t}\n}\n\nconst renderTicker = template(\n\t/* HTML */ `<span class=\"sonic-ticker\"><span class=\"sonic-ticker-tape\"></span></span>`,\n\tHTMLSpanElement,\n);\n\nconst fadePx = 12;\n\nconst holdMs = 2000;\n\nconst ratePxPerSecond = 40;\n\ninterface Running {\n\tanimation: Animation;\n\tfades: Array<Animation>;\n\tleg: TickerLeg;\n}\n\ninterface TapeDrag {\n\tfrom: number;\n\tisDragging: boolean;\n\toutside: ((event: PointerEvent) => boolean) | undefined;\n\tthresholdPx: number;\n\tx: number;\n}\n\nexport class SonicTicker extends SonicElement {\n\tstatic override readonly observedAttributes = ['disabled', 'paused'];\n\n\t// fallow-ignore-next-line code-duplication -- one accessor pair per reflected attribute\n\tget cancellable(): boolean {\n\t\treturn this.hasAttribute('cancellable');\n\t}\n\n\tset cancellable(isCancellable: boolean) {\n\t\tthis.reflect('cancellable', isCancellable);\n\t}\n\n\tget paused(): boolean {\n\t\treturn this.hasAttribute('paused');\n\t}\n\n\tset paused(isPaused: boolean) {\n\t\tthis.reflect('paused', isPaused);\n\t}\n\n\tget text(): string {\n\t\treturn this.#originals()\n\t\t\t.map((original) => original.textContent)\n\t\t\t.join('');\n\t}\n\n\tset text(text: string | undefined) {\n\t\tconst next = text ?? '';\n\n\t\t// A host that re-renders the same title would otherwise restart the tape\n\t\tif (this.#holds(next)) return;\n\n\t\tfor (const original of this.#originals()) original.remove();\n\t\tif (next !== '') this.prepend(next);\n\t}\n\n\tprotected override readonly control = renderTicker();\n\n\tprotected override readonly sheet = 'ticker.css';\n\n\tprotected override readonly sheetToken = '--_sonic-ticker-fade';\n\n\t#drag: undefined | { end: () => void };\n\n\t#fade = fadePx;\n\n\t#heading: TickerHeading = 1;\n\n\t#isClickSwallowed = false;\n\n\t#isFocusInside = false;\n\n\t#isHovered = false;\n\n\t#isOffScreen = false;\n\n\t#isPressed = false;\n\n\t#mark: ReturnType<typeof setTimeout> | undefined;\n\n\t#measured = '';\n\n\t#position = 0;\n\n\treadonly #reducedMotion = matchMedia('(prefers-reduced-motion: reduce)');\n\n\t#running: Running | undefined;\n\n\treadonly #tape = requireChild(this.control, '.sonic-ticker-tape', HTMLSpanElement);\n\n\t#travel: TickerTravel = { distance: 0, hold: holdMs, rate: ratePxPerSecond };\n\n\tattributeChangedCallback(name: string): void {\n\t\tif (name === 'disabled' && this.isBound()) {\n\t\t\tthis.#drag?.end();\n\t\t\tthis.#run(this.#tape, { from: 0, heading: 1 });\n\t\t}\n\n\t\tthis.render();\n\t}\n\n\tprotected connect(signal: AbortSignal): void {\n\t\tconst control = this.control;\n\t\tconst tape = this.#tape;\n\t\tconst measure = (): void => {\n\t\t\tthis.#measure(tape);\n\t\t};\n\t\tconst observer = new ResizeObserver(measure);\n\t\tconst drag = this.#bindDrag(tape, signal);\n\n\t\tthis.#drag = drag;\n\n\t\tthis.upgradeProperties('cancellable', 'paused', 'text');\n\t\tmirrorChildren(\n\t\t\tthis,\n\t\t\t{\n\t\t\t\tcanCopyLinks: true,\n\t\t\t\tcontrol,\n\t\t\t\tcopy: copyNode,\n\t\t\t\tplace: (copies) => {\n\t\t\t\t\tplaceChildren(tape, copies);\n\t\t\t\t\tdrag.end();\n\t\t\t\t\tthis.#measure(tape, { from: 0, heading: 1 });\n\t\t\t\t},\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t\tthis.render();\n\n\t\tobserver.observe(control);\n\t\tobserver.observe(tape);\n\t\tif ('fonts' in document) document.fonts.addEventListener('loadingdone', measure, { signal });\n\t\tthis.#bindFocus(tape, signal);\n\t\tthis.#bindPauses(signal);\n\t\tthis.#reducedMotion.addEventListener(\n\t\t\t'change',\n\t\t\t() => {\n\t\t\t\tthis.#run(tape);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tobserver.disconnect();\n\t\t\t\tthis.#stop();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\tprotected render(): void {\n\t\tif (!this.isBound()) return;\n\n\t\tthis.toggleState('paused', this.paused);\n\t\tthis.#syncPause();\n\t}\n\n\t#bindDrag(tape: HTMLElement, signal: AbortSignal): { end: () => void } {\n\t\tconst control = this.control;\n\n\t\tcontrol.addEventListener(\n\t\t\t'click',\n\t\t\t(event) => {\n\t\t\t\tif (!this.#isClickSwallowed) return;\n\n\t\t\t\tthis.#isClickSwallowed = false;\n\t\t\t\tevent.preventDefault();\n\t\t\t\tevent.stopPropagation();\n\t\t\t},\n\t\t\t{ capture: true, signal },\n\t\t);\n\t\t// In WebKit, dragging a link that wraps the ticker fires `dragstart` on the link, outside the control\n\t\tthis.getRootNode().addEventListener(\n\t\t\t'dragstart',\n\t\t\t(event) => {\n\t\t\t\tif (this.#isPressed) event.preventDefault();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\n\t\treturn bindDrag<TapeDrag>(\n\t\t\tcontrol,\n\t\t\t{\n\t\t\t\tgrab: (event) => {\n\t\t\t\t\tif (this.#travel.distance <= 0 || this.isDisabled()) return;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tfrom: 0,\n\t\t\t\t\t\tisDragging: false,\n\t\t\t\t\t\toutside: undefined,\n\t\t\t\t\t\tthresholdPx: dragThresholdPx(event.pointerType),\n\t\t\t\t\t\tx: event.clientX,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\tisCaptureLate: true,\n\t\t\t\tmove: (held, event) => {\n\t\t\t\t\tif (!held.isDragging) {\n\t\t\t\t\t\tif (Math.abs(event.clientX - held.x) < held.thresholdPx) return;\n\n\t\t\t\t\t\tconst { from, heading } = this.#where();\n\n\t\t\t\t\t\theld.isDragging = true;\n\t\t\t\t\t\theld.from = from;\n\t\t\t\t\t\theld.outside = this.cancellable\n\t\t\t\t\t\t\t? outsideCancelZone(control, '--_sonic-ticker-cancel-zone')\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\theld.x = event.clientX;\n\t\t\t\t\t\tcapturePointer(control, event.pointerId);\n\t\t\t\t\t\tthis.toggleState('dragging', true);\n\t\t\t\t\t\tthis.#stop();\n\t\t\t\t\t\tthis.#heading = heading;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst isOutside = held.outside?.(event) === true;\n\n\t\t\t\t\tthis.toggleState('cancelling', isOutside);\n\t\t\t\t\tthis.#place(tape, isOutside ? held.from : held.from - (event.clientX - held.x));\n\t\t\t\t},\n\t\t\t\trelease: (held) => {\n\t\t\t\t\tif (!held.isDragging) return;\n\n\t\t\t\t\t// Safari sends no click after a drag, so the flag is cleared on a timer or it would cancel the next real click\n\t\t\t\t\tthis.#isClickSwallowed = true;\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tthis.#isClickSwallowed = false;\n\t\t\t\t\t}, 0);\n\t\t\t\t\tthis.toggleState('dragging', false);\n\t\t\t\t\tthis.toggleState('cancelling', false);\n\t\t\t\t\tthis.#run(tape);\n\t\t\t\t},\n\t\t\t\ttoggle: (isPressed) => {\n\t\t\t\t\tthis.#isPressed = isPressed;\n\t\t\t\t\tthis.#syncPause();\n\t\t\t\t},\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t#bindFocus(tape: HTMLElement, signal: AbortSignal): void {\n\t\tconst control = this.control;\n\n\t\tcontrol.addEventListener(\n\t\t\t'focusout',\n\t\t\t(event) => {\n\t\t\t\tif (event.relatedTarget instanceof Node && control.contains(event.relatedTarget)) return;\n\n\t\t\t\tcontrol.scrollLeft = 0;\n\t\t\t\tthis.#isFocusInside = false;\n\t\t\t\tthis.#run(tape);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tcontrol.addEventListener(\n\t\t\t'focusin',\n\t\t\t(event) => {\n\t\t\t\tthis.#isFocusInside = true;\n\t\t\t\tthis.#run(tape);\n\t\t\t\tif (event.target instanceof Element) event.target.scrollIntoView({ block: 'nearest' });\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t}\n\n\t#bindPauses(signal: AbortSignal): void {\n\t\tconst control = this.control;\n\n\t\tfor (const type of ['pointerenter', 'pointerleave'] as const) {\n\t\t\tcontrol.addEventListener(\n\t\t\t\ttype,\n\t\t\t\t(event) => {\n\t\t\t\t\tif (event.pointerType !== 'mouse') return;\n\n\t\t\t\t\tthis.#isHovered = type === 'pointerenter';\n\t\t\t\t\tthis.#syncPause();\n\t\t\t\t},\n\t\t\t\t{ signal },\n\t\t\t);\n\t\t}\n\t\tfor (const type of ['focusin', 'focusout'] as const) {\n\t\t\tthis.getRootNode().addEventListener(\n\t\t\t\ttype,\n\t\t\t\t() => {\n\t\t\t\t\tthis.#syncPause();\n\t\t\t\t},\n\t\t\t\t{ signal },\n\t\t\t);\n\t\t}\n\n\t\tconst view = new IntersectionObserver((entries) => {\n\t\t\tthis.#isOffScreen = entries.at(-1)?.isIntersecting === false;\n\t\t\tthis.#syncPause();\n\t\t});\n\n\t\tview.observe(control);\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tview.disconnect();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\t#holds(text: string): boolean {\n\t\tconst [only, ...rest] = this.#originals();\n\t\tif (only === undefined) return text === '';\n\t\tif (rest.length > 0 || !(only instanceof Text)) return false;\n\n\t\treturn only.data === text;\n\t}\n\n\t#isPaused(): boolean {\n\t\treturn (\n\t\t\tthis.paused ||\n\t\t\tthis.#isHovered ||\n\t\t\tthis.#isPressed ||\n\t\t\tthis.#isOffScreen ||\n\t\t\tthis.control.closest(':focus-visible') !== null\n\t\t);\n\t}\n\n\t#measure(tape: HTMLElement, departure?: TickerDeparture): void {\n\t\tconst control = this.control;\n\t\tconst styles = getComputedStyle(control);\n\t\tconst box =\n\t\t\tcontrol.clientWidth -\n\t\t\treadPxProperty(styles, 'padding-left', 0) -\n\t\t\treadPxProperty(styles, 'padding-right', 0);\n\t\tconst travel = {\n\t\t\tdistance: Math.max(0, Math.round(tape.offsetWidth - box)),\n\t\t\thold: readMsProperty(styles, '--_sonic-ticker-hold', holdMs),\n\t\t\trate: readPxProperty(styles, '--_sonic-ticker-rate', ratePxPerSecond),\n\t\t};\n\t\tconst fade = readPxProperty(styles, '--_sonic-ticker-fade', fadePx);\n\t\tconst measured = [...Object.values(travel), fade].join(' ');\n\t\tif (!departure && measured === this.#measured) return;\n\n\t\tconst from = departure ?? this.#where();\n\n\t\tthis.#fade = fade;\n\t\tthis.#measured = measured;\n\t\tthis.#travel = travel;\n\t\tthis.toggleState('overflowing', travel.distance > 0);\n\t\tthis.#run(tape, from);\n\t}\n\n\t#originals(): Array<ChildNode> {\n\t\treturn [...this.childNodes].filter((child) => child !== this.control);\n\t}\n\n\t#place(tape: HTMLElement, position: number): void {\n\t\tconst { distance } = this.#travel;\n\n\t\tthis.#position = clamp(position, 0, distance);\n\t\ttape.style.translate = this.#position > 0 ? `${String(-this.#position)}px` : '';\n\t\twriteAttribute(this.control, 'data-sonic-clipped', clippedEnds(this.#position, distance));\n\t\tthis.#writeFades(this.#position);\n\t}\n\n\t#run(tape: HTMLElement, departure: TickerDeparture = this.#where()): void {\n\t\tconst canTravel =\n\t\t\t!this.#isFocusInside &&\n\t\t\t!this.#reducedMotion.matches &&\n\t\t\t!this.hasState('dragging') &&\n\t\t\t!this.isDisabled();\n\t\tconst leg = canTravel ? tickerLeg(this.#travel, departure) : undefined;\n\n\t\tthis.#stop();\n\t\tthis.#heading = departure.heading;\n\t\tif (leg) this.#start(tape, leg);\n\t\telse this.#place(tape, this.#isFocusInside ? 0 : departure.from);\n\t}\n\n\t#start(tape: HTMLElement, leg: TickerLeg): void {\n\t\tconst animation = tape.animate(\n\t\t\t{ translate: [`${String(-leg.from)}px`, `${String(-leg.to)}px`] },\n\t\t\t{ delay: leg.hold, duration: leg.duration, fill: 'both' },\n\t\t);\n\n\t\tanimation.addEventListener('finish', () => {\n\t\t\tthis.#run(tape, { from: leg.to, heading: leg.heading });\n\t\t});\n\t\tthis.#running = { animation, fades: [], leg };\n\t\ttape.style.translate = '';\n\t\twriteAttribute(\n\t\t\tthis.control,\n\t\t\t'data-sonic-clipped',\n\t\t\tclippedEnds(leg.from, this.#travel.distance),\n\t\t);\n\t\tthis.#syncPause();\n\t}\n\n\t#startFades(leg: TickerLeg, elapsed: number): Array<Animation> {\n\t\tconst fades = legFades(leg, this.#travel.distance, this.#fade);\n\n\t\treturn (['start', 'end'] as const).flatMap((end) => {\n\t\t\tconst { delay, duration, widths } = fades[end];\n\t\t\tif (duration <= 0 || delay + duration <= elapsed) return [];\n\n\t\t\treturn this.control.animate(\n\t\t\t\t{ [`--_sonic-ticker-fade-${end}`]: widths.map((width) => `${String(width)}px`) },\n\t\t\t\t{ delay: delay - elapsed, duration, fill: 'both' },\n\t\t\t);\n\t\t});\n\t}\n\n\t#stop(): void {\n\t\tconst running = this.#running;\n\n\t\tclearTimeout(this.#mark);\n\t\tif (!running) return;\n\n\t\tfor (const fade of running.fades) fade.cancel();\n\t\trunning.animation.cancel();\n\t\tthis.#running = undefined;\n\t}\n\n\t// Calling `play()` on a finished animation restarts it, so the fades are recreated on resume, not paused\n\t#syncPause(): void {\n\t\tconst running = this.#running;\n\t\tif (!running) return;\n\n\t\tconst { animation, leg } = running;\n\t\tconst elapsed = Number(animation.currentTime);\n\n\t\tclearTimeout(this.#mark);\n\t\tfor (const fade of running.fades) fade.cancel();\n\t\trunning.fades = [];\n\t\tthis.#writeFades(legPosition(leg, elapsed));\n\t\tif (elapsed >= leg.hold) writeAttribute(this.control, 'data-sonic-clipped', 'start end');\n\t\tif (this.#isPaused()) {\n\t\t\tanimation.pause();\n\t\t\treturn;\n\t\t}\n\t\tif (animation.playState === 'paused') animation.play();\n\t\trunning.fades = this.#startFades(leg, elapsed);\n\t\tif (elapsed >= leg.hold) return;\n\n\t\tthis.#mark = setTimeout(() => {\n\t\t\twriteAttribute(this.control, 'data-sonic-clipped', 'start end');\n\t\t}, leg.hold - elapsed);\n\t}\n\n\t#where(): TickerDeparture {\n\t\tconst running = this.#running;\n\t\tif (!running) return { from: this.#position, heading: this.#heading };\n\n\t\treturn legDeparture(running.leg, Number(running.animation.currentTime));\n\t}\n\n\t#writeFades(position: number): void {\n\t\tconst { style } = this.control;\n\n\t\tstyle.setProperty('--_sonic-ticker-fade-start', `${String(fadeWidth(position, this.#fade))}px`);\n\t\tstyle.setProperty(\n\t\t\t'--_sonic-ticker-fade-end',\n\t\t\t`${String(fadeWidth(this.#travel.distance - position, this.#fade))}px`,\n\t\t);\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -10,4 +10,5 @@ interface CrossfadeGains {
|
|
|
10
10
|
/** `position` runs from 0, all a, to 1, all b; `sharpness` from 0 to 1 shortens the overlap */
|
|
11
11
|
export declare function crossfadeGains(position: number, options?: CrossfadeOptions): CrossfadeGains;
|
|
12
12
|
//#endregion
|
|
13
|
+
export {};
|
|
13
14
|
//# sourceMappingURL=crossfade.d.ts.map
|
package/dist/styles/ticker.css
CHANGED
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
user-select: none;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
.sonic-ticker[data-sonic-overflowing] {
|
|
64
|
+
.sonic-ticker[data-sonic-overflowing]:not([disabled] > *) {
|
|
65
65
|
text-overflow: clip;
|
|
66
66
|
touch-action: var(--sonic-touch-action, pan-y);
|
|
67
67
|
-webkit-mask: linear-gradient(
|
|
@@ -80,11 +80,11 @@
|
|
|
80
80
|
);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
.sonic-ticker[data-sonic-overflowing] > .sonic-ticker-tape {
|
|
83
|
+
.sonic-ticker[data-sonic-overflowing]:not([disabled] > *) > .sonic-ticker-tape {
|
|
84
84
|
display: inline-block;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
.sonic-ticker[data-sonic-overflowing]:not(:any-link *) {
|
|
87
|
+
.sonic-ticker[data-sonic-overflowing]:not(:any-link *, [disabled] > *) {
|
|
88
88
|
cursor: grab;
|
|
89
89
|
}
|
|
90
90
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xsynaptic/sonic-ui",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.1",
|
|
4
4
|
"description": "Native custom elements for audio interfaces, skinned with CSS custom properties",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"custom-elements",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
],
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"publint": "^0.3.25",
|
|
82
|
-
"tsdown": "^0.23.
|
|
82
|
+
"tsdown": "^0.23.1",
|
|
83
83
|
"typescript": "^6.0.3"
|
|
84
84
|
},
|
|
85
85
|
"scripts": {
|