@profpowell/blink-wc 0.0.0-stage → 1.5.2
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/LICENSE +21 -0
- package/README.md +320 -2
- package/blink-wc.d.ts +113 -0
- package/custom-elements.json +277 -0
- package/dist/blink-wc.css +757 -0
- package/dist/blink-wc.js +435 -0
- package/dist/blink-wc.js.map +1 -0
- package/package.json +61 -4
package/dist/blink-wc.js
ADDED
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
var L = Object.defineProperty;
|
|
2
|
+
var R = (r, t, e) => t in r ? L(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e;
|
|
3
|
+
var C = (r, t, e) => R(r, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
const P = [
|
|
5
|
+
"wave",
|
|
6
|
+
"twinkle",
|
|
7
|
+
"sparkle",
|
|
8
|
+
"rainbow",
|
|
9
|
+
"chase",
|
|
10
|
+
"glitch",
|
|
11
|
+
"cascade",
|
|
12
|
+
"typewriter",
|
|
13
|
+
"zoom",
|
|
14
|
+
"flip3d",
|
|
15
|
+
"swing",
|
|
16
|
+
"shake",
|
|
17
|
+
"heartbeat",
|
|
18
|
+
"decode"
|
|
19
|
+
], N = ["extrude", "collapse", "outline", "morph", "depth", "revolve"], O = { morph: 4, revolve: 4 }, w = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%&*+=?<>/~^|", S = {
|
|
20
|
+
a: ".-",
|
|
21
|
+
b: "-...",
|
|
22
|
+
c: "-.-.",
|
|
23
|
+
d: "-..",
|
|
24
|
+
e: ".",
|
|
25
|
+
f: "..-.",
|
|
26
|
+
g: "--.",
|
|
27
|
+
h: "....",
|
|
28
|
+
i: "..",
|
|
29
|
+
j: ".---",
|
|
30
|
+
k: "-.-",
|
|
31
|
+
l: ".-..",
|
|
32
|
+
m: "--",
|
|
33
|
+
n: "-.",
|
|
34
|
+
o: "---",
|
|
35
|
+
p: ".--.",
|
|
36
|
+
q: "--.-",
|
|
37
|
+
r: ".-.",
|
|
38
|
+
s: "...",
|
|
39
|
+
t: "-",
|
|
40
|
+
u: "..-",
|
|
41
|
+
v: "...-",
|
|
42
|
+
w: ".--",
|
|
43
|
+
x: "-..-",
|
|
44
|
+
y: "-.--",
|
|
45
|
+
z: "--..",
|
|
46
|
+
0: "-----",
|
|
47
|
+
1: ".----",
|
|
48
|
+
2: "..---",
|
|
49
|
+
3: "...--",
|
|
50
|
+
4: "....-",
|
|
51
|
+
5: ".....",
|
|
52
|
+
6: "-....",
|
|
53
|
+
7: "--...",
|
|
54
|
+
8: "---..",
|
|
55
|
+
9: "----.",
|
|
56
|
+
".": ".-.-.-",
|
|
57
|
+
",": "--..--",
|
|
58
|
+
"?": "..--..",
|
|
59
|
+
"'": ".----.",
|
|
60
|
+
"!": "-.-.--",
|
|
61
|
+
"/": "-..-.",
|
|
62
|
+
"(": "-.--.",
|
|
63
|
+
")": "-.--.-",
|
|
64
|
+
"&": ".-...",
|
|
65
|
+
":": "---...",
|
|
66
|
+
"=": "-...-",
|
|
67
|
+
"+": ".-.-.",
|
|
68
|
+
"-": "-....-",
|
|
69
|
+
"@": ".--.-."
|
|
70
|
+
}, M = matchMedia("(prefers-reduced-motion: reduce)"), v = /* @__PURE__ */ new Set();
|
|
71
|
+
let y = null;
|
|
72
|
+
const D = () => M.matches || document.documentElement.hasAttribute("data-motion-reduced"), E = () => v.forEach((r) => r._update());
|
|
73
|
+
function W(r) {
|
|
74
|
+
v.add(r), !y && (M.addEventListener("change", E), y = new MutationObserver(E), y.observe(document.documentElement, {
|
|
75
|
+
attributes: !0,
|
|
76
|
+
attributeFilter: ["data-motion-reduced"]
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
function I(r) {
|
|
80
|
+
v.delete(r), !(v.size || !y) && (M.removeEventListener("change", E), y.disconnect(), y = null);
|
|
81
|
+
}
|
|
82
|
+
const k = /* @__PURE__ */ new Map();
|
|
83
|
+
function T(r, t) {
|
|
84
|
+
const e = `${r || ""}|${t}`;
|
|
85
|
+
return k.has(e) || k.set(e, new Intl.Segmenter(r, { granularity: t })), k.get(e);
|
|
86
|
+
}
|
|
87
|
+
const F = (r) => r.trim() === "";
|
|
88
|
+
function q(r, t) {
|
|
89
|
+
return [...T(t, "grapheme").segment(r)].map((e) => e.segment);
|
|
90
|
+
}
|
|
91
|
+
function B(r, t) {
|
|
92
|
+
const e = [];
|
|
93
|
+
for (const { segment: s, isWordLike: a } of T(t, "word").segment(r)) {
|
|
94
|
+
const m = F(s), l = e.length ? e[e.length - 1] : null, c = l != null && F(l);
|
|
95
|
+
l != null && (m && c || !m && !a && !c) ? e[e.length - 1] += s : e.push(s);
|
|
96
|
+
}
|
|
97
|
+
return e;
|
|
98
|
+
}
|
|
99
|
+
const H = "a[href], button, input, select, textarea, summary, [tabindex], [contenteditable]";
|
|
100
|
+
class x extends HTMLElement {
|
|
101
|
+
// ── Functional core: pure getters ──────────────────────────────────────
|
|
102
|
+
get rate() {
|
|
103
|
+
return this.getAttribute("rate") || "1s";
|
|
104
|
+
}
|
|
105
|
+
get behavior() {
|
|
106
|
+
const t = this.getAttribute("behavior");
|
|
107
|
+
return ["pulse", "flicker", "steps"].includes(t) ? t : "blink";
|
|
108
|
+
}
|
|
109
|
+
get minOpacity() {
|
|
110
|
+
const t = this.getAttribute("min-opacity");
|
|
111
|
+
return t == null || t === "" ? null : t;
|
|
112
|
+
}
|
|
113
|
+
get count() {
|
|
114
|
+
return this.getAttribute("count") || "infinite";
|
|
115
|
+
}
|
|
116
|
+
get steps() {
|
|
117
|
+
const t = parseInt(this.getAttribute("steps"), 10);
|
|
118
|
+
return Number.isFinite(t) && t >= 2 ? t : O[this.mode] || 2;
|
|
119
|
+
}
|
|
120
|
+
get stepDurations() {
|
|
121
|
+
return this.getAttribute("step-durations") || null;
|
|
122
|
+
}
|
|
123
|
+
get stepBy() {
|
|
124
|
+
const t = this.getAttribute("step-by");
|
|
125
|
+
return t === "letter" || t === "word" ? t : "element";
|
|
126
|
+
}
|
|
127
|
+
get playState() {
|
|
128
|
+
return this.getAttribute("play-state") || "running";
|
|
129
|
+
}
|
|
130
|
+
get mode() {
|
|
131
|
+
return this.getAttribute("mode") || "";
|
|
132
|
+
}
|
|
133
|
+
get unit() {
|
|
134
|
+
return this.getAttribute("unit") === "word" ? "word" : "letter";
|
|
135
|
+
}
|
|
136
|
+
// ── Imperative shell ───────────────────────────────────────────────────
|
|
137
|
+
connectedCallback() {
|
|
138
|
+
if (W(this), this._built) {
|
|
139
|
+
this._observe(), this._update();
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
this._build(), this._observe(), this._update(), this._built = !0, this._dispatch("blink-start");
|
|
143
|
+
}
|
|
144
|
+
// Moved with Node.moveBefore(): the browser skips disconnected/connected and
|
|
145
|
+
// keeps animation state, so there is nothing to tear down or rebuild. (Where
|
|
146
|
+
// moveBefore() is unsupported, a move falls back to the reconnect path above.)
|
|
147
|
+
connectedMoveCallback() {
|
|
148
|
+
}
|
|
149
|
+
disconnectedCallback() {
|
|
150
|
+
var t, e;
|
|
151
|
+
I(this), (t = this._intersectionObserver) == null || t.disconnect(), (e = this._content) == null || e.removeEventListener("animationiteration", this._onIteration), document.removeEventListener("visibilitychange", this._onVisibility), this._stopMorse(), this._stopSteps(), this._stopDecode();
|
|
152
|
+
}
|
|
153
|
+
attributeChangedCallback(t, e, s) {
|
|
154
|
+
e === s || !this._built || ((t === "mode" || t === "unit" || t === "step-by" || t === "behavior") && this._renderContent(), this._update(), t === "play-state" && this._dispatch(s === "paused" ? "blink-pause" : "blink-start"));
|
|
155
|
+
}
|
|
156
|
+
// ── Public API (legacy <blink> compat) ──────────────────────────────────
|
|
157
|
+
start() {
|
|
158
|
+
this.setAttribute("play-state", "running");
|
|
159
|
+
}
|
|
160
|
+
stop() {
|
|
161
|
+
this.setAttribute("play-state", "paused");
|
|
162
|
+
}
|
|
163
|
+
toggle() {
|
|
164
|
+
this.playState === "paused" ? this.start() : this.stop();
|
|
165
|
+
}
|
|
166
|
+
refresh() {
|
|
167
|
+
this._renderContent(), this._update();
|
|
168
|
+
}
|
|
169
|
+
// ── Private ────────────────────────────────────────────────────────────
|
|
170
|
+
_build() {
|
|
171
|
+
const t = [...this.childNodes];
|
|
172
|
+
this.textContent = "";
|
|
173
|
+
const e = document.createElement("span");
|
|
174
|
+
e.className = "blink-content", t.forEach((s) => e.appendChild(s)), this.appendChild(e), this._content = e, this._sourceHTML = e.innerHTML, this._sourceText = e.textContent.replace(/\s+/g, " ").trim(), this._renderContent();
|
|
175
|
+
}
|
|
176
|
+
// Restore authored markup, then split into units if the mode needs it. Per-unit
|
|
177
|
+
// motion modes split by `unit`; per-unit step sequences split by `step-by`.
|
|
178
|
+
_renderContent() {
|
|
179
|
+
if (this._sourceHTML == null) return;
|
|
180
|
+
this._content.innerHTML = this._sourceHTML;
|
|
181
|
+
const t = this._usesSteps() && this.stepBy !== "element";
|
|
182
|
+
if (P.includes(this.mode) || t) {
|
|
183
|
+
const e = t ? this.stepBy === "word" : this.unit === "word";
|
|
184
|
+
this._splitLetters(e), this.dataset.split = "";
|
|
185
|
+
} else
|
|
186
|
+
delete this.dataset.split;
|
|
187
|
+
this._syncSpeech();
|
|
188
|
+
}
|
|
189
|
+
// Per-unit spans make screen readers spell the text out letter by letter (and
|
|
190
|
+
// decode would expose its scrambled glyphs). When split, hide the animated
|
|
191
|
+
// spans and expose one visually-hidden copy of the original text instead.
|
|
192
|
+
_syncSpeech() {
|
|
193
|
+
var s;
|
|
194
|
+
const t = this.hasAttribute("data-split"), e = t && this._content.querySelector(H);
|
|
195
|
+
t && !e ? (this._speech || (this._speech = document.createElement("span"), this._speech.className = "blink-sr"), this._speech.textContent = this._sourceText, this._content.setAttribute("aria-hidden", "true"), this._speech.isConnected || this._content.after(this._speech)) : (this._content.removeAttribute("aria-hidden"), (s = this._speech) == null || s.remove());
|
|
196
|
+
}
|
|
197
|
+
// Wrap each unit in a <span class="blink-char"> with a stagger index, so CSS
|
|
198
|
+
// can animate units individually (wave, twinkle, …) and the step engine can
|
|
199
|
+
// advance each unit's data-step on its own staggered clock.
|
|
200
|
+
_splitLetters(t = this.unit === "word") {
|
|
201
|
+
var h;
|
|
202
|
+
const e = document.createTreeWalker(this._content, NodeFilter.SHOW_TEXT), s = [];
|
|
203
|
+
for (; e.nextNode(); ) s.push(e.currentNode);
|
|
204
|
+
const a = this.mode === "twinkle" || this.mode === "sparkle", m = this.mode === "decode", l = ((h = this.closest("[lang]")) == null ? void 0 : h.lang) || void 0;
|
|
205
|
+
let c = 0;
|
|
206
|
+
for (const _ of s) {
|
|
207
|
+
const u = document.createDocumentFragment(), d = t ? B(_.textContent, l) : q(_.textContent, l);
|
|
208
|
+
for (const p of d) {
|
|
209
|
+
if (p === "") continue;
|
|
210
|
+
const f = F(p), i = document.createElement("span");
|
|
211
|
+
i.className = "blink-char", i.style.setProperty("--i", c++), a && (i.style.setProperty("--rate", `${(0.4 + Math.random() * 1.6).toFixed(2)}s`), i.style.setProperty("--delay", `${Math.random().toFixed(2)}s`)), f ? (i.classList.add("blink-space"), i.textContent = " ") : (i.textContent = p, m && (i.dataset.ch = p)), u.appendChild(i);
|
|
212
|
+
}
|
|
213
|
+
_.replaceWith(u);
|
|
214
|
+
}
|
|
215
|
+
this._content.style.setProperty("--n", c);
|
|
216
|
+
}
|
|
217
|
+
// Whether motion should be suppressed: OS preference or VB's data-motion-reduced,
|
|
218
|
+
// unless this instance opts out with reduced-motion="ignore".
|
|
219
|
+
_reduceMotion() {
|
|
220
|
+
return this.getAttribute("reduced-motion") !== "ignore" && D();
|
|
221
|
+
}
|
|
222
|
+
// Whether playback is currently paused (state, off-screen, tab-hidden, or hover).
|
|
223
|
+
_isPaused() {
|
|
224
|
+
return this.hasAttribute("pause-on-hover") && this.matches(":hover, :focus-within") ? !0 : this.playState === "paused" || this.dataset.visible === "false" || this.dataset.tabVisible === "false";
|
|
225
|
+
}
|
|
226
|
+
_stopMorse() {
|
|
227
|
+
this._morseRAF && cancelAnimationFrame(this._morseRAF), this._morseRAF = null;
|
|
228
|
+
}
|
|
229
|
+
// morse mode: blink the text out as Morse code. CSS keys off data-lit to light
|
|
230
|
+
// the text; we also expose the dot/dash string via data-morse for a caption.
|
|
231
|
+
_syncMorse() {
|
|
232
|
+
var u;
|
|
233
|
+
if (this._stopMorse(), this.mode !== "morse") {
|
|
234
|
+
delete this.dataset.lit, delete this.dataset.morse;
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const t = (((u = this._content) == null ? void 0 : u.textContent) || "").trim();
|
|
238
|
+
if (this.dataset.morse = this._toMorse(t), this._reduceMotion()) {
|
|
239
|
+
this.dataset.lit = "true";
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const s = this._morseSegments(t);
|
|
243
|
+
if (s.length === 0) {
|
|
244
|
+
this.dataset.lit = "true";
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const a = parseFloat(getComputedStyle(this).getPropertyValue("--blink-dot")), m = Number.isFinite(a) && a > 0 ? a : 170, l = s.reduce((d, p) => d + p.dur, 0) + 7;
|
|
248
|
+
let c = 0, h = null;
|
|
249
|
+
const _ = (d) => {
|
|
250
|
+
this._morseRAF = requestAnimationFrame(_), h == null && (h = d);
|
|
251
|
+
const p = d - h;
|
|
252
|
+
if (h = d, this._isPaused()) return;
|
|
253
|
+
c += p;
|
|
254
|
+
const f = c / m % l;
|
|
255
|
+
let i = 0, b = !1;
|
|
256
|
+
for (const o of s) {
|
|
257
|
+
if (f < i + o.dur) {
|
|
258
|
+
b = o.lit;
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
i += o.dur;
|
|
262
|
+
}
|
|
263
|
+
const n = b ? "true" : "false";
|
|
264
|
+
this.dataset.lit !== n && (this.dataset.lit = n);
|
|
265
|
+
};
|
|
266
|
+
this.dataset.lit = "false", this._morseRAF = requestAnimationFrame(_);
|
|
267
|
+
}
|
|
268
|
+
// Build an on/off timeline (durations in Morse "units") for a string.
|
|
269
|
+
_morseSegments(t) {
|
|
270
|
+
const e = [], s = t.toLowerCase().split(/\s+/).filter(Boolean);
|
|
271
|
+
return s.forEach((a, m) => {
|
|
272
|
+
const l = [...a].filter((c) => S[c]);
|
|
273
|
+
l.forEach((c, h) => {
|
|
274
|
+
const _ = S[c];
|
|
275
|
+
[..._].forEach((u, d) => {
|
|
276
|
+
e.push({ lit: !0, dur: u === "-" ? 3 : 1 }), d < _.length - 1 && e.push({ lit: !1, dur: 1 });
|
|
277
|
+
}), h < l.length - 1 && e.push({ lit: !1, dur: 3 });
|
|
278
|
+
}), m < s.length - 1 && e.push({ lit: !1, dur: 7 });
|
|
279
|
+
}), e;
|
|
280
|
+
}
|
|
281
|
+
// Human-readable dot/dash string, words separated by " / ".
|
|
282
|
+
_toMorse(t) {
|
|
283
|
+
return t.toLowerCase().split(/\s+/).filter(Boolean).map(
|
|
284
|
+
(e) => [...e].map((s) => S[s] || "").filter(Boolean).join(" ")
|
|
285
|
+
).filter(Boolean).join(" / ");
|
|
286
|
+
}
|
|
287
|
+
_observe() {
|
|
288
|
+
this._intersectionObserver = new IntersectionObserver(
|
|
289
|
+
(t) => t.forEach((e) => {
|
|
290
|
+
this.dataset.visible = String(e.isIntersecting);
|
|
291
|
+
}),
|
|
292
|
+
{ rootMargin: "100px" }
|
|
293
|
+
), this._intersectionObserver.observe(this), this._onVisibility = () => {
|
|
294
|
+
this.dataset.tabVisible = String(!document.hidden);
|
|
295
|
+
}, document.addEventListener("visibilitychange", this._onVisibility), this.dataset.tabVisible = String(!document.hidden), this._onIteration = () => this._dispatch("blink-cycle"), this._content.addEventListener("animationiteration", this._onIteration);
|
|
296
|
+
}
|
|
297
|
+
_update() {
|
|
298
|
+
!this._built && !this._content || (this.dataset.behavior = this.behavior, this.dataset.state = this.playState, this.dataset.ready = "", this.style.setProperty("--blink-rate", this.rate), this.minOpacity != null ? this.style.setProperty("--blink-min-opacity", this.minOpacity) : this.style.removeProperty("--blink-min-opacity"), this.count !== "infinite" ? this.style.setProperty("--blink-count", this.count) : this.style.removeProperty("--blink-count"), this._syncMorse(), this._syncSteps(), this._syncDecode());
|
|
299
|
+
}
|
|
300
|
+
_stopDecode() {
|
|
301
|
+
this._decodeRAF && cancelAnimationFrame(this._decodeRAF), this._decodeRAF = null;
|
|
302
|
+
}
|
|
303
|
+
// decode mode: each unit flickers through random glyphs, then locks onto its
|
|
304
|
+
// real character (stored in data-ch), staggered left-to-right, then
|
|
305
|
+
// re-scrambles on a loop. Monospace keeps the width stable as glyphs change.
|
|
306
|
+
// Freezes when paused; shows the plain text under reduced motion.
|
|
307
|
+
_syncDecode() {
|
|
308
|
+
if (this._stopDecode(), this.mode !== "decode") return;
|
|
309
|
+
const t = [...this.querySelectorAll(".blink-char")].filter(
|
|
310
|
+
(i) => !i.classList.contains("blink-space") && i.dataset.ch != null
|
|
311
|
+
);
|
|
312
|
+
if (t.length === 0) return;
|
|
313
|
+
if (this._reduceMotion()) {
|
|
314
|
+
for (const i of t) i.textContent = i.dataset.ch;
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const s = () => w[Math.random() * w.length | 0], a = 650, m = 45, l = 1800, c = 55;
|
|
318
|
+
let h = 0;
|
|
319
|
+
const _ = t.map((i) => {
|
|
320
|
+
const b = Number(i.style.getPropertyValue("--i")) || 0, n = a + b * m;
|
|
321
|
+
return n > h && (h = n), { s: i, settleAt: n, target: i.dataset.ch };
|
|
322
|
+
});
|
|
323
|
+
let u = 0, d = null, p = 0;
|
|
324
|
+
const f = (i) => {
|
|
325
|
+
this._decodeRAF = requestAnimationFrame(f), d == null && (d = i);
|
|
326
|
+
const b = i - d;
|
|
327
|
+
if (d = i, this._isPaused()) return;
|
|
328
|
+
u += b;
|
|
329
|
+
const n = u - p >= c;
|
|
330
|
+
n && (p = u);
|
|
331
|
+
for (const o of _)
|
|
332
|
+
u >= o.settleAt ? o.s.textContent !== o.target && (o.s.textContent = o.target) : n && (o.s.textContent = s());
|
|
333
|
+
u > h + l && (u = 0, p = 0);
|
|
334
|
+
};
|
|
335
|
+
this._decodeRAF = requestAnimationFrame(f);
|
|
336
|
+
}
|
|
337
|
+
// Whether the multi-step engine should drive this element.
|
|
338
|
+
_usesSteps() {
|
|
339
|
+
return this.behavior === "steps" || N.includes(this.mode);
|
|
340
|
+
}
|
|
341
|
+
// Parse a CSS time (e.g. "1s", "800ms", or a bare number of seconds) to ms.
|
|
342
|
+
_parseTime(t) {
|
|
343
|
+
const e = String(t).trim();
|
|
344
|
+
let s;
|
|
345
|
+
return e.endsWith("ms") ? s = parseFloat(e) : (e.endsWith("s"), s = parseFloat(e) * 1e3), Number.isFinite(s) && s > 0 ? s : 1e3;
|
|
346
|
+
}
|
|
347
|
+
_stopSteps() {
|
|
348
|
+
this._stepRAF && cancelAnimationFrame(this._stepRAF), this._stepRAF = null;
|
|
349
|
+
}
|
|
350
|
+
// Parse `step-durations` into per-step weights, one per step. Accepts a
|
|
351
|
+
// space- or comma-separated list (e.g. "3 1 1" or "2,1"); the list is cycled
|
|
352
|
+
// or truncated to fit the step count. Absent/invalid → equal weights.
|
|
353
|
+
_stepWeights(t) {
|
|
354
|
+
const e = this.stepDurations;
|
|
355
|
+
if (!e) return Array(t).fill(1);
|
|
356
|
+
const s = e.split(/[\s,]+/).map(Number).filter((a) => Number.isFinite(a) && a > 0);
|
|
357
|
+
return s.length === 0 ? Array(t).fill(1) : Array.from({ length: t }, (a, m) => s[m % s.length]);
|
|
358
|
+
}
|
|
359
|
+
// The element(s) that carry data-step: the whole content for step-by="element",
|
|
360
|
+
// or each unit span for step-by="letter"/"word".
|
|
361
|
+
_stepTargets() {
|
|
362
|
+
return this.stepBy !== "element" && this.dataset.split != null ? [...this.querySelectorAll(".blink-char")] : this._content ? [this._content] : [];
|
|
363
|
+
}
|
|
364
|
+
// Clear any data-step left on the content or unit spans (when stepping stops).
|
|
365
|
+
_clearStepTargets() {
|
|
366
|
+
var t;
|
|
367
|
+
(t = this._content) == null || delete t.dataset.step, this.querySelectorAll(".blink-char[data-step]").forEach((e) => delete e.dataset.step);
|
|
368
|
+
}
|
|
369
|
+
// Multi-step engine: advance data-step="0..N-1" across one cycle (`rate`). Each
|
|
370
|
+
// step holds for a slice of the cycle — equal by default, or weighted by
|
|
371
|
+
// `step-durations`. CSS styles each step (colour, transform, outline, …) and
|
|
372
|
+
// can give each step its own transition timing (--blink-step-ease /
|
|
373
|
+
// --blink-step-timing); a plain blink is the 2-step case. With step-by="letter"
|
|
374
|
+
// (or "word") every unit runs the sequence offset by its index, so the states
|
|
375
|
+
// ripple across the text. Freezes when paused/off-screen/tab-hidden; rests at
|
|
376
|
+
// step 0 under reduced motion.
|
|
377
|
+
_syncSteps() {
|
|
378
|
+
if (this._stopSteps(), !this._usesSteps()) {
|
|
379
|
+
delete this.dataset.stepping, this._clearStepTargets();
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
this.dataset.stepping = "";
|
|
383
|
+
const t = this.steps, e = this._stepTargets();
|
|
384
|
+
if (e.length === 0) return;
|
|
385
|
+
if (this._reduceMotion()) {
|
|
386
|
+
for (const n of e) n.dataset.step = "0";
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const a = this._stepWeights(t), m = a.reduce((n, o) => n + o, 0), l = this._parseTime(this.rate), c = [];
|
|
390
|
+
let h = 0;
|
|
391
|
+
for (const n of a)
|
|
392
|
+
h += n, c.push(h / m * l);
|
|
393
|
+
const u = e.length > 1 ? (parseFloat(getComputedStyle(this).getPropertyValue("--blink-stagger")) || 0.08) * 1e3 : 0, d = (n) => {
|
|
394
|
+
let o = 0;
|
|
395
|
+
for (; o < t - 1 && n >= c[o]; ) o++;
|
|
396
|
+
return o;
|
|
397
|
+
}, p = new Array(e.length).fill(0);
|
|
398
|
+
e.forEach((n) => n.dataset.step = "0");
|
|
399
|
+
let f = 0, i = null;
|
|
400
|
+
const b = (n) => {
|
|
401
|
+
this._stepRAF = requestAnimationFrame(b), i == null && (i = n);
|
|
402
|
+
const o = n - i;
|
|
403
|
+
if (i = n, !this._isPaused()) {
|
|
404
|
+
f += o;
|
|
405
|
+
for (let g = 0; g < e.length; g++) {
|
|
406
|
+
const A = d((f + g * u) % l);
|
|
407
|
+
A !== p[g] && (e[g].dataset.step = String(A), g === 0 && A < p[g] && this._dispatch("blink-cycle"), p[g] = A);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
this._stepRAF = requestAnimationFrame(b);
|
|
412
|
+
}
|
|
413
|
+
_dispatch(t) {
|
|
414
|
+
this.dispatchEvent(new CustomEvent(t, { bubbles: !0 }));
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
C(x, "observedAttributes", [
|
|
418
|
+
"rate",
|
|
419
|
+
"behavior",
|
|
420
|
+
"min-opacity",
|
|
421
|
+
"count",
|
|
422
|
+
"steps",
|
|
423
|
+
"step-durations",
|
|
424
|
+
"step-by",
|
|
425
|
+
"play-state",
|
|
426
|
+
"pause-on-hover",
|
|
427
|
+
"reduced-motion",
|
|
428
|
+
"mode",
|
|
429
|
+
"unit"
|
|
430
|
+
]);
|
|
431
|
+
customElements.define("blink-wc", x);
|
|
432
|
+
export {
|
|
433
|
+
x as BlinkWc
|
|
434
|
+
};
|
|
435
|
+
//# sourceMappingURL=blink-wc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blink-wc.js","sources":["../src/blink-wc.js"],"sourcesContent":["/**\n * @class BlinkWc\n * @extends HTMLElement\n * @description Vanilla Breeze blink component. The deprecated <blink> element,\n * reborn for 2026 — light DOM, CSS-driven, themeable, accessible, and it\n * pauses when offscreen or tab-hidden. Blinking content is a real\n * accessibility hazard, so it stops entirely under prefers-reduced-motion\n * (unless you explicitly opt out) and is always pausable.\n *\n * @attr rate - CSS time for one blink cycle (default: 1s)\n * @attr behavior - blink | pulse | flicker (default: blink)\n * @attr min-opacity - opacity of the \"off\" phase, 0–1 (default per behavior)\n * @attr count - number of blinks, then stop, or `infinite` (default: infinite)\n * @attr pause-on-hover - boolean; also pauses on focus-within\n * @attr play-state - running | paused\n * @attr reduced-motion - respect | ignore (default: respect)\n * @attr mode - visual/motion preset. Surface themes: neon | crt | terminal |\n * warning | alert | police | vegas. Per-unit motion: wave | twinkle |\n * sparkle | rainbow | chase | glitch | cascade | typewriter. Special: morse.\n * @attr unit - letter | word (default: letter) — granularity for the motion modes\n *\n * @fires blink-start\n * @fires blink-pause\n * @fires blink-cycle - fires on each blink iteration\n */\n\n// Modes that split text into per-unit spans for letter/word-level effects.\nconst LETTER_MODES = [\n 'wave',\n 'twinkle',\n 'sparkle',\n 'rainbow',\n 'chase',\n 'glitch',\n 'cascade',\n 'typewriter',\n 'zoom',\n 'flip3d',\n 'swing',\n 'shake',\n 'heartbeat',\n 'decode',\n];\n\n// Modes driven by the multi-step engine: JS advances data-step=\"0..N-1\" across\n// the cycle and CSS styles each step. A plain blink is just the 2-step case.\nconst STEP_MODES = ['extrude', 'collapse', 'outline', 'morph', 'depth', 'revolve'];\n\n// Default step count per step-mode (overridable with the `steps` attribute).\nconst STEP_COUNTS = { morph: 4, revolve: 4 };\n\n// Glyphs the `decode` scramble cycles through before locking onto the text.\nconst DECODE_GLYPHS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%&*+=?<>/~^|';\n\n// International Morse code, plus digits and a little punctuation.\nconst MORSE = {\n a: '.-',\n b: '-...',\n c: '-.-.',\n d: '-..',\n e: '.',\n f: '..-.',\n g: '--.',\n h: '....',\n i: '..',\n j: '.---',\n k: '-.-',\n l: '.-..',\n m: '--',\n n: '-.',\n o: '---',\n p: '.--.',\n q: '--.-',\n r: '.-.',\n s: '...',\n t: '-',\n u: '..-',\n v: '...-',\n w: '.--',\n x: '-..-',\n y: '-.--',\n z: '--..',\n 0: '-----',\n 1: '.----',\n 2: '..---',\n 3: '...--',\n 4: '....-',\n 5: '.....',\n 6: '-....',\n 7: '--...',\n 8: '---..',\n 9: '----.',\n '.': '.-.-.-',\n ',': '--..--',\n '?': '..--..',\n \"'\": '.----.',\n '!': '-.-.--',\n '/': '-..-.',\n '(': '-.--.',\n ')': '-.--.-',\n '&': '.-...',\n ':': '---...',\n '=': '-...-',\n '+': '.-.-.',\n '-': '-....-',\n '@': '.--.-.',\n};\n\n// ── Reduced-motion watcher (shared by every instance) ──────────────────────\n// Motion is reduced when the OS asks for it OR when Vanilla Breeze's theme\n// picker has turned \"Motion Effects\" off, which sets :root[data-motion-reduced].\n// One media-query listener and one MutationObserver serve all instances, and\n// re-sync the JS-driven modes (morse, steps, decode) when either flips.\nconst REDUCED_MQ = matchMedia('(prefers-reduced-motion: reduce)');\nconst INSTANCES = new Set();\nlet rootObserver = null;\n\nconst systemReducesMotion = () =>\n REDUCED_MQ.matches || document.documentElement.hasAttribute('data-motion-reduced');\n\nconst resyncAll = () => INSTANCES.forEach((el) => el._update());\n\nfunction watchMotion(el) {\n INSTANCES.add(el);\n if (rootObserver) return;\n REDUCED_MQ.addEventListener('change', resyncAll);\n rootObserver = new MutationObserver(resyncAll);\n rootObserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['data-motion-reduced'],\n });\n}\n\nfunction unwatchMotion(el) {\n INSTANCES.delete(el);\n if (INSTANCES.size || !rootObserver) return;\n REDUCED_MQ.removeEventListener('change', resyncAll);\n rootObserver.disconnect();\n rootObserver = null;\n}\n\n// ── Text segmentation ──────────────────────────────────────────────────────\n// Split by user-perceived characters (grapheme clusters), not code points, so\n// emoji sequences (👩💻, flags) and combining accents stay whole. Word mode uses\n// the locale's word boundaries, which also handles languages without spaces.\nconst SEGMENTERS = new Map();\nfunction segmenter(locale, granularity) {\n const key = `${locale || ''}|${granularity}`;\n if (!SEGMENTERS.has(key)) SEGMENTERS.set(key, new Intl.Segmenter(locale, { granularity }));\n return SEGMENTERS.get(key);\n}\n\nconst isWhitespace = (s) => s.trim() === '';\n\n// Graphemes, one per unit; whitespace stays one unit per character.\nfunction splitGraphemes(text, locale) {\n return [...segmenter(locale, 'grapheme').segment(text)].map((s) => s.segment);\n}\n\n// Words plus whitespace runs. Trailing punctuation sticks to the word before\n// it, so \"hello, world\" splits as \"hello,\" \" \" \"world\".\nfunction splitWords(text, locale) {\n const tokens = [];\n for (const { segment, isWordLike } of segmenter(locale, 'word').segment(text)) {\n const ws = isWhitespace(segment);\n const prev = tokens.length ? tokens[tokens.length - 1] : null;\n const prevWs = prev != null && isWhitespace(prev);\n if (prev != null && ((ws && prevWs) || (!ws && !isWordLike && !prevWs))) {\n tokens[tokens.length - 1] += segment;\n } else {\n tokens.push(segment);\n }\n }\n return tokens;\n}\n\n// Content a screen-reader-only copy can't stand in for: hiding the animated\n// spans would hide these from assistive tech, so such content is left as is.\nconst INTERACTIVE =\n 'a[href], button, input, select, textarea, summary, [tabindex], [contenteditable]';\n\nclass BlinkWc extends HTMLElement {\n static observedAttributes = [\n 'rate',\n 'behavior',\n 'min-opacity',\n 'count',\n 'steps',\n 'step-durations',\n 'step-by',\n 'play-state',\n 'pause-on-hover',\n 'reduced-motion',\n 'mode',\n 'unit',\n ];\n\n // ── Functional core: pure getters ──────────────────────────────────────\n get rate() {\n return this.getAttribute('rate') || '1s';\n }\n get behavior() {\n const b = this.getAttribute('behavior');\n return ['pulse', 'flicker', 'steps'].includes(b) ? b : 'blink';\n }\n get minOpacity() {\n const v = this.getAttribute('min-opacity');\n return v == null || v === '' ? null : v;\n }\n get count() {\n return this.getAttribute('count') || 'infinite';\n }\n get steps() {\n const v = parseInt(this.getAttribute('steps'), 10);\n if (Number.isFinite(v) && v >= 2) return v;\n return STEP_COUNTS[this.mode] || 2;\n }\n get stepDurations() {\n return this.getAttribute('step-durations') || null;\n }\n get stepBy() {\n const v = this.getAttribute('step-by');\n return v === 'letter' || v === 'word' ? v : 'element';\n }\n get playState() {\n return this.getAttribute('play-state') || 'running';\n }\n get mode() {\n return this.getAttribute('mode') || '';\n }\n get unit() {\n return this.getAttribute('unit') === 'word' ? 'word' : 'letter';\n }\n\n // ── Imperative shell ───────────────────────────────────────────────────\n connectedCallback() {\n watchMotion(this);\n if (this._built) {\n // Re-attached (e.g. moved in the DOM): disconnectedCallback tore down the\n // observers and stopped the JS drivers, so bring them back.\n this._observe();\n this._update();\n return;\n }\n this._build();\n this._observe();\n this._update();\n this._built = true;\n this._dispatch('blink-start');\n }\n\n // Moved with Node.moveBefore(): the browser skips disconnected/connected and\n // keeps animation state, so there is nothing to tear down or rebuild. (Where\n // moveBefore() is unsupported, a move falls back to the reconnect path above.)\n connectedMoveCallback() {}\n\n disconnectedCallback() {\n unwatchMotion(this);\n this._intersectionObserver?.disconnect();\n this._content?.removeEventListener('animationiteration', this._onIteration);\n document.removeEventListener('visibilitychange', this._onVisibility);\n this._stopMorse();\n this._stopSteps();\n this._stopDecode();\n }\n\n attributeChangedCallback(name, oldValue, newValue) {\n if (oldValue === newValue || !this._built) return;\n if (name === 'mode' || name === 'unit' || name === 'step-by' || name === 'behavior') {\n this._renderContent();\n }\n this._update();\n if (name === 'play-state') {\n this._dispatch(newValue === 'paused' ? 'blink-pause' : 'blink-start');\n }\n }\n\n // ── Public API (legacy <blink> compat) ──────────────────────────────────\n start() {\n this.setAttribute('play-state', 'running');\n }\n stop() {\n this.setAttribute('play-state', 'paused');\n }\n toggle() {\n this.playState === 'paused' ? this.start() : this.stop();\n }\n refresh() {\n this._renderContent();\n this._update();\n }\n\n // ── Private ────────────────────────────────────────────────────────────\n _build() {\n const items = [...this.childNodes];\n this.textContent = '';\n\n const content = document.createElement('span');\n content.className = 'blink-content';\n items.forEach((n) => content.appendChild(n));\n this.appendChild(content);\n\n this._content = content;\n // Snapshot the authored markup so we can re-render when `mode` changes.\n this._sourceHTML = content.innerHTML;\n this._sourceText = content.textContent.replace(/\\s+/g, ' ').trim();\n this._renderContent();\n }\n\n // Restore authored markup, then split into units if the mode needs it. Per-unit\n // motion modes split by `unit`; per-unit step sequences split by `step-by`.\n _renderContent() {\n if (this._sourceHTML == null) return;\n this._content.innerHTML = this._sourceHTML;\n const perUnitSteps = this._usesSteps() && this.stepBy !== 'element';\n if (LETTER_MODES.includes(this.mode) || perUnitSteps) {\n const byWord = perUnitSteps ? this.stepBy === 'word' : this.unit === 'word';\n this._splitLetters(byWord);\n this.dataset.split = '';\n } else {\n delete this.dataset.split;\n }\n this._syncSpeech();\n }\n\n // Per-unit spans make screen readers spell the text out letter by letter (and\n // decode would expose its scrambled glyphs). When split, hide the animated\n // spans and expose one visually-hidden copy of the original text instead.\n _syncSpeech() {\n const split = this.hasAttribute('data-split');\n const interactive = split && this._content.querySelector(INTERACTIVE);\n if (split && !interactive) {\n if (!this._speech) {\n this._speech = document.createElement('span');\n this._speech.className = 'blink-sr';\n }\n this._speech.textContent = this._sourceText;\n this._content.setAttribute('aria-hidden', 'true');\n if (!this._speech.isConnected) this._content.after(this._speech);\n } else {\n this._content.removeAttribute('aria-hidden');\n this._speech?.remove();\n }\n }\n\n // Wrap each unit in a <span class=\"blink-char\"> with a stagger index, so CSS\n // can animate units individually (wave, twinkle, …) and the step engine can\n // advance each unit's data-step on its own staggered clock.\n _splitLetters(byWord = this.unit === 'word') {\n const walker = document.createTreeWalker(this._content, NodeFilter.SHOW_TEXT);\n const textNodes = [];\n while (walker.nextNode()) textNodes.push(walker.currentNode);\n\n // Per-unit randomized clocks: each unit blinks on its own timer.\n const twinkle = this.mode === 'twinkle' || this.mode === 'sparkle';\n const decode = this.mode === 'decode';\n const locale = this.closest('[lang]')?.lang || undefined;\n let i = 0;\n for (const node of textNodes) {\n const frag = document.createDocumentFragment();\n const tokens = byWord\n ? splitWords(node.textContent, locale)\n : splitGraphemes(node.textContent, locale);\n for (const ch of tokens) {\n if (ch === '') continue;\n const space = isWhitespace(ch);\n const span = document.createElement('span');\n span.className = 'blink-char';\n span.style.setProperty('--i', i++);\n if (twinkle) {\n span.style.setProperty('--rate', `${(0.4 + Math.random() * 1.6).toFixed(2)}s`);\n span.style.setProperty('--delay', `${Math.random().toFixed(2)}s`);\n }\n if (space) {\n span.classList.add('blink-space');\n span.textContent = ' ';\n } else {\n span.textContent = ch;\n // decode: remember the real glyph so the scramble loop can settle on it\n if (decode) span.dataset.ch = ch;\n }\n frag.appendChild(span);\n }\n node.replaceWith(frag);\n }\n this._content.style.setProperty('--n', i);\n }\n\n // Whether motion should be suppressed: OS preference or VB's data-motion-reduced,\n // unless this instance opts out with reduced-motion=\"ignore\".\n _reduceMotion() {\n return this.getAttribute('reduced-motion') !== 'ignore' && systemReducesMotion();\n }\n\n // Whether playback is currently paused (state, off-screen, tab-hidden, or hover).\n _isPaused() {\n if (this.hasAttribute('pause-on-hover') && this.matches(':hover, :focus-within')) return true;\n return (\n this.playState === 'paused' ||\n this.dataset.visible === 'false' ||\n this.dataset.tabVisible === 'false'\n );\n }\n\n _stopMorse() {\n if (this._morseRAF) cancelAnimationFrame(this._morseRAF);\n this._morseRAF = null;\n }\n\n // morse mode: blink the text out as Morse code. CSS keys off data-lit to light\n // the text; we also expose the dot/dash string via data-morse for a caption.\n _syncMorse() {\n this._stopMorse();\n if (this.mode !== 'morse') {\n delete this.dataset.lit;\n delete this.dataset.morse;\n return;\n }\n\n const text = (this._content?.textContent || '').trim();\n this.dataset.morse = this._toMorse(text);\n\n // Respect reduced motion: leave the text fully lit, no blinking.\n const reduce = this._reduceMotion();\n if (reduce) {\n this.dataset.lit = 'true';\n return;\n }\n\n const segments = this._morseSegments(text);\n if (segments.length === 0) {\n this.dataset.lit = 'true';\n return;\n }\n\n // Read the dot unit (ms) from a CSS var so it can be themed; default 170ms.\n const dotRaw = parseFloat(getComputedStyle(this).getPropertyValue('--blink-dot'));\n const DOT = Number.isFinite(dotRaw) && dotRaw > 0 ? dotRaw : 170;\n const totalUnits = segments.reduce((a, s) => a + s.dur, 0) + 7; // trailing word gap\n\n let elapsed = 0;\n let lastT = null;\n const tick = (t) => {\n this._morseRAF = requestAnimationFrame(tick);\n if (lastT == null) lastT = t;\n const dt = t - lastT;\n lastT = t;\n if (this._isPaused()) return; // freeze the timeline while paused\n elapsed += dt;\n const cycle = (elapsed / DOT) % totalUnits;\n let acc = 0;\n let lit = false;\n for (const s of segments) {\n if (cycle < acc + s.dur) {\n lit = s.lit;\n break;\n }\n acc += s.dur;\n }\n const next = lit ? 'true' : 'false';\n if (this.dataset.lit !== next) this.dataset.lit = next;\n };\n this.dataset.lit = 'false';\n this._morseRAF = requestAnimationFrame(tick);\n }\n\n // Build an on/off timeline (durations in Morse \"units\") for a string.\n _morseSegments(text) {\n const segments = [];\n const words = text.toLowerCase().split(/\\s+/).filter(Boolean);\n words.forEach((word, wi) => {\n const chars = [...word].filter((c) => MORSE[c]);\n chars.forEach((c, ci) => {\n const symbols = MORSE[c];\n [...symbols].forEach((sym, si) => {\n segments.push({ lit: true, dur: sym === '-' ? 3 : 1 });\n if (si < symbols.length - 1) segments.push({ lit: false, dur: 1 });\n });\n if (ci < chars.length - 1) segments.push({ lit: false, dur: 3 }); // inter-char gap\n });\n if (wi < words.length - 1) segments.push({ lit: false, dur: 7 }); // inter-word gap\n });\n return segments;\n }\n\n // Human-readable dot/dash string, words separated by \" / \".\n _toMorse(text) {\n return text\n .toLowerCase()\n .split(/\\s+/)\n .filter(Boolean)\n .map((word) =>\n [...word]\n .map((c) => MORSE[c] || '')\n .filter(Boolean)\n .join(' ')\n )\n .filter(Boolean)\n .join(' / ');\n }\n\n _observe() {\n this._intersectionObserver = new IntersectionObserver(\n (entries) =>\n entries.forEach((e) => {\n this.dataset.visible = String(e.isIntersecting);\n }),\n { rootMargin: '100px' }\n );\n this._intersectionObserver.observe(this);\n\n this._onVisibility = () => {\n this.dataset.tabVisible = String(!document.hidden);\n };\n document.addEventListener('visibilitychange', this._onVisibility);\n this.dataset.tabVisible = String(!document.hidden);\n\n this._onIteration = () => this._dispatch('blink-cycle');\n this._content.addEventListener('animationiteration', this._onIteration);\n }\n\n _update() {\n if (!this._built && !this._content) return;\n\n // Reflect state to data-* hooks the CSS keys off.\n this.dataset.behavior = this.behavior;\n this.dataset.state = this.playState;\n this.dataset.ready = '';\n\n this.style.setProperty('--blink-rate', this.rate);\n if (this.minOpacity != null) {\n this.style.setProperty('--blink-min-opacity', this.minOpacity);\n } else {\n this.style.removeProperty('--blink-min-opacity');\n }\n if (this.count !== 'infinite') {\n this.style.setProperty('--blink-count', this.count);\n } else {\n this.style.removeProperty('--blink-count');\n }\n\n this._syncMorse();\n this._syncSteps();\n this._syncDecode();\n }\n\n _stopDecode() {\n if (this._decodeRAF) cancelAnimationFrame(this._decodeRAF);\n this._decodeRAF = null;\n }\n\n // decode mode: each unit flickers through random glyphs, then locks onto its\n // real character (stored in data-ch), staggered left-to-right, then\n // re-scrambles on a loop. Monospace keeps the width stable as glyphs change.\n // Freezes when paused; shows the plain text under reduced motion.\n _syncDecode() {\n this._stopDecode();\n if (this.mode !== 'decode') return;\n\n const units = [...this.querySelectorAll('.blink-char')].filter(\n (s) => !s.classList.contains('blink-space') && s.dataset.ch != null\n );\n if (units.length === 0) return;\n\n const reduce = this._reduceMotion();\n if (reduce) {\n for (const s of units) s.textContent = s.dataset.ch;\n return;\n }\n\n const randGlyph = () => DECODE_GLYPHS[(Math.random() * DECODE_GLYPHS.length) | 0];\n\n const SCRAMBLE_MS = 650;\n const STAGGER_MS = 45;\n const HOLD_MS = 1800;\n const FLIP_MS = 55;\n let maxSettle = 0;\n const items = units.map((s) => {\n const i = Number(s.style.getPropertyValue('--i')) || 0;\n const settleAt = SCRAMBLE_MS + i * STAGGER_MS;\n if (settleAt > maxSettle) maxSettle = settleAt;\n return { s, settleAt, target: s.dataset.ch };\n });\n\n let elapsed = 0;\n let lastT = null;\n let lastFlip = 0;\n const tick = (t) => {\n this._decodeRAF = requestAnimationFrame(tick);\n if (lastT == null) lastT = t;\n const dt = t - lastT;\n lastT = t;\n if (this._isPaused()) return; // freeze the timeline while paused\n elapsed += dt;\n const flip = elapsed - lastFlip >= FLIP_MS;\n if (flip) lastFlip = elapsed;\n for (const it of items) {\n if (elapsed >= it.settleAt) {\n if (it.s.textContent !== it.target) it.s.textContent = it.target;\n } else if (flip) {\n it.s.textContent = randGlyph();\n }\n }\n if (elapsed > maxSettle + HOLD_MS) {\n elapsed = 0;\n lastFlip = 0;\n }\n };\n this._decodeRAF = requestAnimationFrame(tick);\n }\n\n // Whether the multi-step engine should drive this element.\n _usesSteps() {\n return this.behavior === 'steps' || STEP_MODES.includes(this.mode);\n }\n\n // Parse a CSS time (e.g. \"1s\", \"800ms\", or a bare number of seconds) to ms.\n _parseTime(value) {\n const t = String(value).trim();\n let ms;\n if (t.endsWith('ms')) ms = parseFloat(t);\n else if (t.endsWith('s')) ms = parseFloat(t) * 1000;\n else ms = parseFloat(t) * 1000;\n return Number.isFinite(ms) && ms > 0 ? ms : 1000;\n }\n\n _stopSteps() {\n if (this._stepRAF) cancelAnimationFrame(this._stepRAF);\n this._stepRAF = null;\n }\n\n // Parse `step-durations` into per-step weights, one per step. Accepts a\n // space- or comma-separated list (e.g. \"3 1 1\" or \"2,1\"); the list is cycled\n // or truncated to fit the step count. Absent/invalid → equal weights.\n _stepWeights(n) {\n const raw = this.stepDurations;\n if (!raw) return Array(n).fill(1);\n const parts = raw\n .split(/[\\s,]+/)\n .map(Number)\n .filter((v) => Number.isFinite(v) && v > 0);\n if (parts.length === 0) return Array(n).fill(1);\n return Array.from({ length: n }, (_, i) => parts[i % parts.length]);\n }\n\n // The element(s) that carry data-step: the whole content for step-by=\"element\",\n // or each unit span for step-by=\"letter\"/\"word\".\n _stepTargets() {\n if (this.stepBy !== 'element' && this.dataset.split != null) {\n return [...this.querySelectorAll('.blink-char')];\n }\n return this._content ? [this._content] : [];\n }\n\n // Clear any data-step left on the content or unit spans (when stepping stops).\n _clearStepTargets() {\n delete this._content?.dataset.step;\n this.querySelectorAll('.blink-char[data-step]').forEach((el) => delete el.dataset.step);\n }\n\n // Multi-step engine: advance data-step=\"0..N-1\" across one cycle (`rate`). Each\n // step holds for a slice of the cycle — equal by default, or weighted by\n // `step-durations`. CSS styles each step (colour, transform, outline, …) and\n // can give each step its own transition timing (--blink-step-ease /\n // --blink-step-timing); a plain blink is the 2-step case. With step-by=\"letter\"\n // (or \"word\") every unit runs the sequence offset by its index, so the states\n // ripple across the text. Freezes when paused/off-screen/tab-hidden; rests at\n // step 0 under reduced motion.\n _syncSteps() {\n this._stopSteps();\n if (!this._usesSteps()) {\n delete this.dataset.stepping;\n this._clearStepTargets();\n return;\n }\n this.dataset.stepping = '';\n\n const n = this.steps;\n const targets = this._stepTargets();\n if (targets.length === 0) return;\n\n const reduce = this._reduceMotion();\n if (reduce) {\n for (const el of targets) el.dataset.step = '0';\n return;\n }\n\n // Build cumulative time boundaries (ms) for each step from its weight.\n const weights = this._stepWeights(n);\n const total = weights.reduce((a, b) => a + b, 0);\n const cycleMs = this._parseTime(this.rate);\n const bounds = [];\n let acc = 0;\n for (const w of weights) {\n acc += w;\n bounds.push((acc / total) * cycleMs);\n }\n\n // Per-unit stepping offsets each unit's phase by a stagger so the states\n // travel across the text. Read --blink-stagger (seconds) for the step.\n const perUnit = targets.length > 1;\n const staggerMs = perUnit\n ? (parseFloat(getComputedStyle(this).getPropertyValue('--blink-stagger')) || 0.08) * 1000\n : 0;\n\n const stepAt = (pos) => {\n let idx = 0;\n while (idx < n - 1 && pos >= bounds[idx]) idx++;\n return idx;\n };\n\n const prev = new Array(targets.length).fill(0);\n targets.forEach((el) => (el.dataset.step = '0'));\n let elapsed = 0;\n let lastT = null;\n const tick = (t) => {\n this._stepRAF = requestAnimationFrame(tick);\n if (lastT == null) lastT = t;\n const dt = t - lastT;\n lastT = t;\n if (this._isPaused()) return; // freeze the timeline while paused\n elapsed += dt;\n for (let k = 0; k < targets.length; k++) {\n const idx = stepAt((elapsed + k * staggerMs) % cycleMs);\n if (idx !== prev[k]) {\n targets[k].dataset.step = String(idx);\n if (k === 0 && idx < prev[k]) this._dispatch('blink-cycle'); // wrapped to start\n prev[k] = idx;\n }\n }\n };\n this._stepRAF = requestAnimationFrame(tick);\n }\n\n _dispatch(name) {\n this.dispatchEvent(new CustomEvent(name, { bubbles: true }));\n }\n}\n\ncustomElements.define('blink-wc', BlinkWc);\n\nexport { BlinkWc };\n"],"names":["LETTER_MODES","STEP_MODES","STEP_COUNTS","DECODE_GLYPHS","MORSE","REDUCED_MQ","INSTANCES","rootObserver","systemReducesMotion","resyncAll","el","watchMotion","unwatchMotion","SEGMENTERS","segmenter","locale","granularity","key","isWhitespace","s","splitGraphemes","text","splitWords","tokens","segment","isWordLike","ws","prev","prevWs","INTERACTIVE","BlinkWc","b","v","_a","_b","name","oldValue","newValue","items","content","n","perUnitSteps","byWord","split","interactive","walker","textNodes","twinkle","decode","i","node","frag","ch","space","span","segments","dotRaw","DOT","totalUnits","a","elapsed","lastT","tick","t","dt","cycle","acc","lit","next","words","word","wi","chars","ci","symbols","sym","si","c","entries","units","randGlyph","SCRAMBLE_MS","STAGGER_MS","HOLD_MS","FLIP_MS","maxSettle","settleAt","lastFlip","flip","it","value","ms","raw","parts","_","targets","weights","total","cycleMs","bounds","w","staggerMs","stepAt","pos","idx","k","__publicField"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,63 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@profpowell/blink-wc",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
}
|
|
3
|
+
"version": "1.5.2",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"description": "A vanilla JavaScript web component: the <blink> tag reborn for 2026 — accessible, themeable, CSS-driven, and Vanilla Breeze aware",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "dist/blink-wc.js",
|
|
10
|
+
"module": "dist/blink-wc.js",
|
|
11
|
+
"types": "blink-wc.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./blink-wc.d.ts",
|
|
15
|
+
"import": "./dist/blink-wc.js"
|
|
16
|
+
},
|
|
17
|
+
"./style.css": "./dist/blink-wc.css",
|
|
18
|
+
"./blink-wc.css": "./dist/blink-wc.css"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"blink-wc.d.ts",
|
|
23
|
+
"custom-elements.json"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"dev": "vite",
|
|
27
|
+
"build": "vite build && cp src/blink-wc.css dist/blink-wc.css && cp dist/blink-wc.js dist/blink-wc.js.map docs/ && cp src/blink-wc.css docs/blink-wc.css",
|
|
28
|
+
"preview": "vite preview",
|
|
29
|
+
"test": "playwright test",
|
|
30
|
+
"test:ui": "playwright test --ui",
|
|
31
|
+
"lint": "eslint src/",
|
|
32
|
+
"format": "prettier --write .",
|
|
33
|
+
"analyze": "cem analyze",
|
|
34
|
+
"prepublishOnly": "npm run build"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"web-component",
|
|
38
|
+
"custom-element",
|
|
39
|
+
"blink",
|
|
40
|
+
"marquee",
|
|
41
|
+
"vanilla-breeze",
|
|
42
|
+
"retro",
|
|
43
|
+
"animation"
|
|
44
|
+
],
|
|
45
|
+
"author": "ProfPowell",
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@custom-elements-manifest/analyzer": "^0.10.3",
|
|
49
|
+
"@playwright/test": "^1.48.0",
|
|
50
|
+
"eslint": "^9.12.0",
|
|
51
|
+
"prettier": "^3.3.3",
|
|
52
|
+
"vite": "^5.4.8"
|
|
53
|
+
},
|
|
54
|
+
"customElements": "custom-elements.json",
|
|
55
|
+
"repository": {
|
|
56
|
+
"type": "git",
|
|
57
|
+
"url": "git+https://github.com/ProfPowell/blink-wc.git"
|
|
58
|
+
},
|
|
59
|
+
"homepage": "https://profpowell.github.io/blink-wc/",
|
|
60
|
+
"bugs": {
|
|
61
|
+
"url": "https://github.com/ProfPowell/blink-wc/issues"
|
|
62
|
+
}
|
|
63
|
+
}
|