zero-hour 1.3.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,604 @@
1
+ //#region src/zero-hour.css?inline
2
+ var zero_hour_default = ":host{width:100%;display:block;overflow:hidden;container-type:inline-size}.zh{box-sizing:border-box;align-items:stretch;gap:0;display:flex;position:relative}.zh__group{flex:1 1 0;grid-template-rows:auto;grid-template-columns:1fr 1fr;gap:0;width:100%;min-width:0;display:grid}.zh__sep{flex:0 0 var(--zh-sep-width,4%);width:var(--zh-sep-width,4%);background-image:var(--zh-sep-url);background-position:50%;background-repeat:no-repeat;background-size:contain}.zh__digit{aspect-ratio:var(--zh-digit-aspect,9 / 12);width:100%;position:relative;overflow:hidden}.zh__digit-track{flex-direction:column;width:100%;height:100%;display:flex;transform:translateY(0)}.zh--mode-scroll .zh__digit-track{transition:transform var(--zh-scroll-duration,.375s) var(--zh-scroll-timing,cubic-bezier(.445, .05, .55, .95))}.zh__digit-face{background-image:var(--zh-digits-url);background-repeat:no-repeat;background-size:calc(var(--zh-digits-frames,10) * 100%) 100%;background-position:calc(var(--zh-sheet-index,0) * 100% / (var(--zh-digits-frames,10) - 1)) 0;flex:0 0 100%;width:100%;height:100%}.zh__a11y{clip:rect(0 0 0 0);white-space:nowrap;clip-path:inset(50%);width:1px;height:1px;position:absolute;overflow:hidden}\n";
3
+
4
+ //#endregion
5
+ //#region src/index.ts
6
+ const zeroHourCssText = zero_hour_default;
7
+ function digitToSheetIndex(d) {
8
+ const n = d.charCodeAt(0) - 48;
9
+ if (n >= 0 && n <= 9) return n;
10
+ return 0;
11
+ }
12
+ function clampNonNegative(n) {
13
+ return n < 0 ? 0 : n;
14
+ }
15
+ const DEFAULT_UNITS = {
16
+ showDays: true,
17
+ showHours: true,
18
+ showMinutes: true,
19
+ showSeconds: true
20
+ };
21
+ const ZERO_TIME = {
22
+ hours: 0,
23
+ minutes: 0,
24
+ seconds: 0
25
+ };
26
+ function supportsAdoptedStyleSheets(root) {
27
+ return "adoptedStyleSheets" in root;
28
+ }
29
+ function makeConstructableSheet(cssText) {
30
+ try {
31
+ const sheet = new CSSStyleSheet();
32
+ sheet.replaceSync(cssText);
33
+ return sheet;
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+ const DEFAULT_STYLESHEET = makeConstructableSheet(zero_hour_default);
39
+ function msToDhms(ms) {
40
+ const totalSec = Math.floor(ms / 1e3);
41
+ const s = totalSec % 60;
42
+ const m = Math.floor(totalSec / 60) % 60;
43
+ const hTotal = Math.floor(totalSec / 3600);
44
+ return {
45
+ d: Math.floor(hTotal / 24),
46
+ h: hTotal % 24,
47
+ m,
48
+ s,
49
+ totalSec
50
+ };
51
+ }
52
+ function pad2(n) {
53
+ return String(n).padStart(2, "0");
54
+ }
55
+ function toDigitChars(n, minDigits) {
56
+ return [...String(n).padStart(minDigits, "0")];
57
+ }
58
+ function hasBoolAttr(el, name, defaultValue) {
59
+ if (!el.hasAttribute(name)) return defaultValue;
60
+ const raw = el.getAttribute(name);
61
+ if (raw == null || raw === "") return true;
62
+ return raw !== "false";
63
+ }
64
+ function parseYmdDate(raw) {
65
+ if (raw == null) return null;
66
+ const trimmed = raw.trim();
67
+ if (!trimmed) return null;
68
+ const m = trimmed.match(/^(\d{4})-(\d{2})-(\d{2})$/);
69
+ if (!m) return null;
70
+ const year = Number(m[1]);
71
+ const month = Number(m[2]);
72
+ const day = Number(m[3]);
73
+ if (!Number.isFinite(year) || !Number.isFinite(month) || !Number.isFinite(day)) return null;
74
+ return {
75
+ year,
76
+ month,
77
+ day
78
+ };
79
+ }
80
+ function parseHmsTime(raw) {
81
+ if (raw == null) return { ...ZERO_TIME };
82
+ const trimmed = raw.trim();
83
+ if (!trimmed) return { ...ZERO_TIME };
84
+ const parts = trimmed.split(":");
85
+ const h = Number(parts[0] ?? "0");
86
+ const m = Number(parts[1] ?? "0");
87
+ const s = Number(parts[2] ?? "0");
88
+ return {
89
+ hours: Number.isFinite(h) ? h : 0,
90
+ minutes: Number.isFinite(m) ? m : 0,
91
+ seconds: Number.isFinite(s) ? s : 0
92
+ };
93
+ }
94
+ function parseHmsTimeStrict(raw) {
95
+ if (raw == null) return null;
96
+ const trimmed = raw.trim();
97
+ if (!trimmed) return null;
98
+ const m = trimmed.match(/^(\d{1,2}):(\d{2})(?::(\d{2}))?$/);
99
+ if (!m) return null;
100
+ const hours = Number(m[1]);
101
+ const minutes = Number(m[2]);
102
+ const seconds = Number(m[3] ?? "0");
103
+ if (!Number.isFinite(hours) || !Number.isFinite(minutes) || !Number.isFinite(seconds)) return null;
104
+ if (hours < 0 || hours > 23) return null;
105
+ if (minutes < 0 || minutes > 59) return null;
106
+ if (seconds < 0 || seconds > 59) return null;
107
+ return {
108
+ hours,
109
+ minutes,
110
+ seconds
111
+ };
112
+ }
113
+ function parseUtcOffsetMinutes(raw) {
114
+ if (raw == null) return null;
115
+ let trimmed = raw.trim();
116
+ if (!trimmed) return null;
117
+ if (/^utc/i.test(trimmed)) trimmed = trimmed.slice(3);
118
+ let sign = 1;
119
+ if (trimmed[0] === "+") trimmed = trimmed.slice(1);
120
+ else if (trimmed[0] === "-") {
121
+ sign = -1;
122
+ trimmed = trimmed.slice(1);
123
+ }
124
+ if (!trimmed) return null;
125
+ const [hStr, mStr = "0"] = trimmed.split(":");
126
+ const h = Number(hStr);
127
+ const m = Number(mStr);
128
+ if (!Number.isFinite(h) || !Number.isFinite(m)) return null;
129
+ const totalMinutes = h * 60 + m;
130
+ return sign * totalMinutes;
131
+ }
132
+ function readZeroHourQueryOverrides() {
133
+ if (typeof window === "undefined") return null;
134
+ if (!("location" in window)) return null;
135
+ const search = window.location?.search ?? "";
136
+ if (!search) return null;
137
+ const sp = new URLSearchParams(search);
138
+ const overrides = {};
139
+ const date = sp.get("date")?.trim();
140
+ if (date) overrides.date = date;
141
+ const time = sp.get("time")?.trim();
142
+ if (time) overrides.time = time;
143
+ const utc = sp.get("utc")?.trim();
144
+ if (utc) overrides.utc = utc;
145
+ const units = sp.get("units")?.trim();
146
+ if (units) overrides.units = units;
147
+ return Object.keys(overrides).length ? overrides : null;
148
+ }
149
+ function parseUnitsPattern(raw) {
150
+ const pattern = (raw ?? "").trim().toLowerCase();
151
+ if (!pattern) return DEFAULT_UNITS;
152
+ const parts = pattern.split(":").map((p) => p.trim()).filter(Boolean);
153
+ if (!parts.length) return DEFAULT_UNITS;
154
+ const set = new Set(parts);
155
+ const showDays = set.has("d");
156
+ const showHours = set.has("h");
157
+ const showMinutes = set.has("m");
158
+ const showSeconds = set.has("s");
159
+ if (!showDays && !showHours && !showMinutes && !showSeconds) return DEFAULT_UNITS;
160
+ return {
161
+ showDays,
162
+ showHours,
163
+ showMinutes,
164
+ showSeconds
165
+ };
166
+ }
167
+ var ZeroHour = class ZeroHour extends HTMLElement {
168
+ static defaultStylesheet = DEFAULT_STYLESHEET;
169
+ static observedAttributes = [
170
+ "digits-url",
171
+ "separator-url",
172
+ "autostart",
173
+ "date",
174
+ "time",
175
+ "utc",
176
+ "units",
177
+ "mode"
178
+ ];
179
+ shadow = this.attachShadow({ mode: "open" });
180
+ digitsUrl = null;
181
+ separatorUrl = null;
182
+ autostart = true;
183
+ durationMs = 0;
184
+ targetEpochMs = null;
185
+ startEpochMs = null;
186
+ nextTickTimeout = null;
187
+ doneFired = false;
188
+ rootEl;
189
+ daysEl;
190
+ hoursEl;
191
+ minutesEl;
192
+ secondsEl;
193
+ a11yEl;
194
+ sep0El;
195
+ sep1El;
196
+ sep2El;
197
+ styleEl = null;
198
+ showDays = true;
199
+ showHours = true;
200
+ showMinutes = true;
201
+ showSeconds = true;
202
+ mode = "static";
203
+ hasDigitsRendered = false;
204
+ connectedCallback() {
205
+ this.render();
206
+ this.readAttributes();
207
+ if (this.autostart) this.start();
208
+ else this.renderStaticInitial();
209
+ }
210
+ disconnectedCallback() {
211
+ this.stop();
212
+ }
213
+ attributeChangedCallback(name, oldValue, newValue) {
214
+ if (!this.isConnected) return;
215
+ const wasRunning = this.isRunning();
216
+ this.readAttributes();
217
+ this.doneFired = false;
218
+ if (wasRunning && this.autostart) this.start();
219
+ else this.renderStaticInitial();
220
+ }
221
+ start() {
222
+ this.stop();
223
+ if (!this.digitsUrl) return;
224
+ this.durationMs = this.targetEpochMs != null ? this.targetEpochMs - Date.now() : 0;
225
+ this.startEpochMs = Date.now();
226
+ this.tick();
227
+ this.scheduleNextSecondBoundary();
228
+ }
229
+ stop() {
230
+ if (this.nextTickTimeout != null) {
231
+ window.clearTimeout(this.nextTickTimeout);
232
+ this.nextTickTimeout = null;
233
+ }
234
+ this.startEpochMs = null;
235
+ }
236
+ reset() {
237
+ this.doneFired = false;
238
+ if (this.autostart) this.start();
239
+ else this.renderStaticInitial();
240
+ }
241
+ isRunning() {
242
+ return this.startEpochMs != null && this.nextTickTimeout != null;
243
+ }
244
+ isDone() {
245
+ if (!this.digitsUrl) return false;
246
+ if (this.targetEpochMs == null) return false;
247
+ return Date.now() >= this.targetEpochMs;
248
+ }
249
+ readAttributes() {
250
+ if (!this.rootEl) this.render();
251
+ const query = readZeroHourQueryOverrides();
252
+ this.digitsUrl = this.getAttribute("digits-url");
253
+ this.separatorUrl = this.getAttribute("separator-url");
254
+ this.autostart = hasBoolAttr(this, "autostart", true);
255
+ const modeRaw = (this.getAttribute("mode") ?? "").trim().toLowerCase();
256
+ this.mode = modeRaw === "scroll" ? "scroll" : "static";
257
+ const units = parseUnitsPattern(query?.units ?? this.getAttribute("units"));
258
+ this.showDays = units.showDays;
259
+ this.showHours = units.showHours;
260
+ this.showMinutes = units.showMinutes;
261
+ this.showSeconds = units.showSeconds;
262
+ const dateFromAttr = parseYmdDate(this.getAttribute("date"));
263
+ const date = parseYmdDate(query?.date ?? null) ?? dateFromAttr;
264
+ const timeFromAttr = parseHmsTime(this.getAttribute("time"));
265
+ const time = parseHmsTimeStrict(query?.time ?? null) ?? timeFromAttr;
266
+ const offsetMinutesFromAttr = parseUtcOffsetMinutes(this.getAttribute("utc"));
267
+ const offsetMinutes = parseUtcOffsetMinutes(query?.utc ?? null) ?? offsetMinutesFromAttr ?? 0;
268
+ if (!date) this.targetEpochMs = null;
269
+ else {
270
+ const utcMs = Date.UTC(date.year, date.month - 1, date.day, time.hours, time.minutes, time.seconds);
271
+ this.targetEpochMs = utcMs - offsetMinutes * 60 * 1e3;
272
+ }
273
+ this.durationMs = 0;
274
+ if (!this.digitsUrl) {
275
+ this.setTextFallback("—:—:—:—");
276
+ return;
277
+ }
278
+ this.rootEl.style.setProperty("--zh-digits-url", `url("${this.digitsUrl}")`);
279
+ if (this.separatorUrl) this.rootEl.style.setProperty("--zh-sep-url", `url("${this.separatorUrl}")`);
280
+ else this.rootEl.style.removeProperty("--zh-sep-url");
281
+ this.applyUnitsVisibility();
282
+ this.rootEl.classList.toggle("zh--mode-scroll", this.mode === "scroll");
283
+ }
284
+ renderStaticInitial() {
285
+ if (this.targetEpochMs != null) {
286
+ const now = Date.now();
287
+ const { d, h, m, s } = msToDhms(clampNonNegative(this.targetEpochMs - now));
288
+ this.setDigits({
289
+ d,
290
+ h,
291
+ m,
292
+ s
293
+ }, false);
294
+ } else this.setDigits({
295
+ d: 0,
296
+ h: 0,
297
+ m: 0,
298
+ s: 0
299
+ }, false);
300
+ }
301
+ render() {
302
+ this.applyStyles(null);
303
+ this.rootEl = document.createElement("div");
304
+ this.rootEl.className = "zh";
305
+ this.daysEl = document.createElement("div");
306
+ this.daysEl.className = "zh__group";
307
+ this.hoursEl = document.createElement("div");
308
+ this.hoursEl.className = "zh__group";
309
+ this.minutesEl = document.createElement("div");
310
+ this.minutesEl.className = "zh__group";
311
+ this.secondsEl = document.createElement("div");
312
+ this.secondsEl.className = "zh__group";
313
+ this.sep0El = document.createElement("span");
314
+ this.sep0El.className = "zh__sep";
315
+ this.sep1El = document.createElement("span");
316
+ this.sep1El.className = "zh__sep";
317
+ this.sep2El = document.createElement("span");
318
+ this.sep2El.className = "zh__sep";
319
+ this.a11yEl = document.createElement("span");
320
+ this.a11yEl.className = "zh__a11y";
321
+ this.a11yEl.setAttribute("aria-live", "polite");
322
+ this.rootEl.append(this.daysEl, this.sep0El, this.hoursEl, this.sep1El, this.minutesEl, this.sep2El, this.secondsEl, this.a11yEl);
323
+ this.shadow.innerHTML = "";
324
+ if (this.styleEl) this.shadow.append(this.styleEl);
325
+ this.shadow.append(this.rootEl);
326
+ this.setDigits({
327
+ d: 0,
328
+ h: 0,
329
+ m: 0,
330
+ s: 0
331
+ }, false);
332
+ this.hasDigitsRendered = false;
333
+ }
334
+ setTextFallback(text) {
335
+ this.a11yEl.textContent = text;
336
+ }
337
+ applyUnitsVisibility() {
338
+ if (!this.rootEl) return;
339
+ this.daysEl.style.display = this.showDays ? "" : "none";
340
+ this.hoursEl.style.display = this.showHours ? "" : "none";
341
+ this.minutesEl.style.display = this.showMinutes ? "" : "none";
342
+ this.secondsEl.style.display = this.showSeconds ? "" : "none";
343
+ if (!!!this.separatorUrl) {
344
+ this.sep0El.style.display = "none";
345
+ this.sep1El.style.display = "none";
346
+ this.sep2El.style.display = "none";
347
+ return;
348
+ }
349
+ const groupVisible = [
350
+ this.showDays,
351
+ this.showHours,
352
+ this.showMinutes,
353
+ this.showSeconds
354
+ ];
355
+ const visibleIndexes = [];
356
+ for (let i = 0; i < groupVisible.length; i++) if (groupVisible[i]) visibleIndexes.push(i);
357
+ this.rootEl.style.setProperty("--zh-groups", String(visibleIndexes.length));
358
+ const sepUsed = [
359
+ false,
360
+ false,
361
+ false
362
+ ];
363
+ if (visibleIndexes.length >= 2) for (let i = 0; i < visibleIndexes.length - 1; i++) {
364
+ const rightIdx = visibleIndexes[i + 1];
365
+ const sepIndex = Math.min(2, Math.max(0, rightIdx - 1));
366
+ sepUsed[sepIndex] = true;
367
+ }
368
+ this.sep0El.style.display = sepUsed[0] ? "" : "none";
369
+ this.sep1El.style.display = sepUsed[1] ? "" : "none";
370
+ this.sep2El.style.display = sepUsed[2] ? "" : "none";
371
+ }
372
+ setDigits({ d, h, m, s }, animate = true) {
373
+ let shouldAnimate = animate;
374
+ if (!this.hasDigitsRendered) shouldAnimate = false;
375
+ const daysChars = toDigitChars(Math.min(d, 99), 2);
376
+ const hoursChars = toDigitChars(h, 2);
377
+ const minChars = [...pad2(m)];
378
+ const secChars = [...pad2(s)];
379
+ this.syncDigitGroup(this.daysEl, daysChars, shouldAnimate);
380
+ this.syncDigitGroup(this.hoursEl, hoursChars, shouldAnimate);
381
+ this.syncDigitGroup(this.minutesEl, minChars, shouldAnimate);
382
+ this.syncDigitGroup(this.secondsEl, secChars, shouldAnimate);
383
+ const parts = [];
384
+ if (this.showDays) parts.push(daysChars.join(""));
385
+ if (this.showHours) parts.push(hoursChars.join(""));
386
+ if (this.showMinutes) parts.push(minChars.join(""));
387
+ if (this.showSeconds) parts.push(secChars.join(""));
388
+ this.a11yEl.textContent = parts.length ? parts.join(":") : "—";
389
+ this.hasDigitsRendered = true;
390
+ }
391
+ syncDigitGroup(groupEl, chars, animate) {
392
+ while (groupEl.children.length < chars.length) {
393
+ const idx = groupEl.children.length;
394
+ groupEl.appendChild(this.createDigitSlot(chars[idx]));
395
+ }
396
+ while (groupEl.children.length > chars.length) {
397
+ const last = groupEl.lastElementChild;
398
+ if (!last) break;
399
+ groupEl.removeChild(last);
400
+ }
401
+ for (let i = 0; i < chars.length; i++) {
402
+ const el = groupEl.children[i];
403
+ this.syncDigitSlot(el, chars[i], animate);
404
+ }
405
+ }
406
+ createDigitSlot(char) {
407
+ const digit = document.createElement("span");
408
+ digit.className = "zh__digit";
409
+ const track = document.createElement("span");
410
+ track.className = "zh__digit-track";
411
+ const face = this.createDigitFace(char);
412
+ face.classList.add("zh__digit-face--current");
413
+ track.append(face);
414
+ digit.append(track);
415
+ return digit;
416
+ }
417
+ createDigitFace(char) {
418
+ const face = document.createElement("span");
419
+ face.className = "zh__digit-face";
420
+ this.setFaceDigit(face, char);
421
+ return face;
422
+ }
423
+ setFaceDigit(face, char) {
424
+ face.dataset.zhDigit = char;
425
+ const idx = digitToSheetIndex(char);
426
+ face.style.setProperty("--zh-sheet-index", String(idx));
427
+ }
428
+ ensureDigitTrack(slot) {
429
+ let track = slot.querySelector(".zh__digit-track");
430
+ if (!track) {
431
+ track = document.createElement("span");
432
+ track.className = "zh__digit-track";
433
+ slot.innerHTML = "";
434
+ slot.append(track);
435
+ }
436
+ return track;
437
+ }
438
+ getOrCreateCurrentFace(track, fallbackChar) {
439
+ let current = track.querySelector(".zh__digit-face--current");
440
+ if (!current) {
441
+ current = track.querySelector(".zh__digit-face") ?? this.createDigitFace(fallbackChar);
442
+ current.classList.add("zh__digit-face--current");
443
+ this.setFaceDigit(current, current.dataset.zhDigit ?? fallbackChar);
444
+ track.innerHTML = "";
445
+ track.append(current);
446
+ } else {
447
+ const faces = Array.from(track.children);
448
+ for (const face of faces) if (face !== current) track.removeChild(face);
449
+ }
450
+ return current;
451
+ }
452
+ cleanupTrack(track, faceToKeep) {
453
+ if (!track.contains(faceToKeep)) return;
454
+ const faces = Array.from(track.children);
455
+ for (const face of faces) if (face !== faceToKeep) track.removeChild(face);
456
+ faceToKeep.classList.remove("zh__digit-face--next");
457
+ faceToKeep.classList.add("zh__digit-face--current");
458
+ track.style.transition = this.mode === "scroll" ? "" : "none";
459
+ track.style.transform = "translateY(0)";
460
+ }
461
+ parseTransitionMs(el) {
462
+ const style = window.getComputedStyle(el);
463
+ const durations = style.transitionDuration.split(",").map((v) => v.trim());
464
+ const delays = style.transitionDelay.split(",").map((v) => v.trim());
465
+ const toMs = (val) => {
466
+ if (!val) return 0;
467
+ if (val.endsWith("ms")) return Number.parseFloat(val);
468
+ if (val.endsWith("s")) return Number.parseFloat(val) * 1e3;
469
+ return Number.parseFloat(val) || 0;
470
+ };
471
+ return (durations[0] ? toMs(durations[0]) : 0) + (delays[0] ? toMs(delays[0]) : 0);
472
+ }
473
+ animateDigitChange(track, currentFace, newChar) {
474
+ const nextFace = this.createDigitFace(newChar);
475
+ nextFace.classList.add("zh__digit-face--next");
476
+ track.innerHTML = "";
477
+ track.append(nextFace, currentFace);
478
+ track.style.transition = "none";
479
+ track.style.transform = "translateY(-100%)";
480
+ track.offsetHeight;
481
+ track.style.transition = "";
482
+ track.style.transform = "translateY(0)";
483
+ const cleanup = () => {
484
+ track.removeEventListener("transitionend", cleanup);
485
+ if (!track.contains(nextFace)) return;
486
+ this.cleanupTrack(track, nextFace);
487
+ };
488
+ track.addEventListener("transitionend", cleanup, { once: true });
489
+ const guardMs = this.parseTransitionMs(track) + 150;
490
+ window.setTimeout(cleanup, guardMs || 800);
491
+ }
492
+ syncDigitSlot(slot, char, animate) {
493
+ const track = this.ensureDigitTrack(slot);
494
+ const currentFace = this.getOrCreateCurrentFace(track, char);
495
+ const currentChar = currentFace.dataset.zhDigit ?? char;
496
+ this.setFaceDigit(currentFace, currentChar);
497
+ if (currentChar === char || !animate || this.mode !== "scroll") {
498
+ if (currentChar !== char) this.setFaceDigit(currentFace, char);
499
+ this.cleanupTrack(track, currentFace);
500
+ return;
501
+ }
502
+ this.animateDigitChange(track, currentFace, char);
503
+ }
504
+ tick() {
505
+ if (!this.digitsUrl) return;
506
+ const durationMs = clampNonNegative(this.durationMs);
507
+ if (durationMs === 0) {
508
+ this.setDigits({
509
+ d: 0,
510
+ h: 0,
511
+ m: 0,
512
+ s: 0
513
+ });
514
+ this.fireDoneOnce();
515
+ this.stop();
516
+ return;
517
+ }
518
+ const start = this.startEpochMs ?? Date.now();
519
+ const { d, h, m, s, totalSec } = msToDhms(clampNonNegative(durationMs - clampNonNegative(Date.now() - start)));
520
+ this.setDigits({
521
+ d,
522
+ h,
523
+ m,
524
+ s
525
+ });
526
+ if (totalSec === 0) {
527
+ this.fireDoneOnce();
528
+ this.stop();
529
+ }
530
+ }
531
+ fireDoneOnce() {
532
+ if (this.doneFired) return;
533
+ this.doneFired = true;
534
+ this.dispatchEvent(new CustomEvent("done"));
535
+ }
536
+ scheduleNextSecondBoundary() {
537
+ const msToNextSecond = 1e3 - Date.now() % 1e3;
538
+ this.nextTickTimeout = window.setTimeout(() => {
539
+ this.tick();
540
+ if (this.isRunning()) this.scheduleNextSecondBoundary();
541
+ }, msToNextSecond);
542
+ }
543
+ adoptStylesheet(sheet) {
544
+ this.applyStyles(sheet);
545
+ }
546
+ adoptStyles(styles) {
547
+ this.applyStyles(styles);
548
+ }
549
+ applyStyles(styles) {
550
+ if (typeof styles === "string") {
551
+ if (supportsAdoptedStyleSheets(this.shadow)) {
552
+ const sheet = makeConstructableSheet(styles);
553
+ if (sheet) {
554
+ this.shadow.adoptedStyleSheets = [sheet];
555
+ this.styleEl = null;
556
+ return;
557
+ }
558
+ }
559
+ if (!this.styleEl) this.styleEl = document.createElement("style");
560
+ this.styleEl.textContent = styles;
561
+ return;
562
+ }
563
+ if (styles && supportsAdoptedStyleSheets(this.shadow)) {
564
+ this.shadow.adoptedStyleSheets = [styles];
565
+ this.styleEl = null;
566
+ return;
567
+ }
568
+ if (ZeroHour.defaultStylesheet && supportsAdoptedStyleSheets(this.shadow)) {
569
+ this.shadow.adoptedStyleSheets = [ZeroHour.defaultStylesheet];
570
+ this.styleEl = null;
571
+ return;
572
+ }
573
+ if (!this.styleEl) this.styleEl = document.createElement("style");
574
+ this.styleEl.textContent = zero_hour_default;
575
+ }
576
+ };
577
+ if (!customElements.get("countdown-timer")) customElements.define("countdown-timer", ZeroHour);
578
+ function initCountdownTimers(options = {}) {
579
+ const { selector = "countdown-timer", onDone, stylesheet } = options;
580
+ const elements = Array.from(document.querySelectorAll(selector));
581
+ if (onDone) {
582
+ const notified = /* @__PURE__ */ new WeakSet();
583
+ const notifyOnce = (el) => {
584
+ if (notified.has(el)) return;
585
+ notified.add(el);
586
+ onDone(el);
587
+ };
588
+ elements.forEach((el) => {
589
+ el.addEventListener("done", () => notifyOnce(el));
590
+ const zh = el;
591
+ if (typeof zh.isDone === "function" && zh.isDone()) notifyOnce(el);
592
+ });
593
+ }
594
+ if (stylesheet) elements.forEach((el) => {
595
+ const zh = el;
596
+ if (typeof stylesheet === "string") zh.adoptStyles(stylesheet);
597
+ else zh.adoptStylesheet(stylesheet);
598
+ });
599
+ return elements;
600
+ }
601
+
602
+ //#endregion
603
+ export { initCountdownTimers, zeroHourCssText };
604
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["DEFAULT_CSS_TEXT"],"sources":["../src/index.ts"],"sourcesContent":["import './zero-hour.css';\nimport DEFAULT_CSS_TEXT from './zero-hour.css?inline';\n\nexport const zeroHourCssText: string = DEFAULT_CSS_TEXT;\n\nfunction digitToSheetIndex(d: string): number {\n const n = d.charCodeAt(0) - 48;\n\n if (n >= 0 && n <= 9) return n;\n\n return 0;\n}\n\nfunction clampNonNegative(n: number): number {\n return n < 0 ? 0 : n;\n}\n\ntype Dhms = { d: number; h: number; m: number; s: number; totalSec: number };\n\nconst DEFAULT_UNITS = {\n showDays: true,\n showHours: true,\n showMinutes: true,\n showSeconds: true,\n} as const;\n\nconst ZERO_TIME = { hours: 0, minutes: 0, seconds: 0 } as const;\n\ntype StylesInput = CSSStyleSheet | string | null | undefined;\n\nfunction supportsAdoptedStyleSheets(root: ShadowRoot): boolean {\n return 'adoptedStyleSheets' in root;\n}\n\nfunction makeConstructableSheet(cssText: string): CSSStyleSheet | null {\n try {\n const sheet = new CSSStyleSheet();\n\n sheet.replaceSync(cssText);\n\n return sheet;\n } catch {\n return null;\n }\n}\n\nconst DEFAULT_STYLESHEET = makeConstructableSheet(DEFAULT_CSS_TEXT);\n\nfunction msToDhms(ms: number): Dhms {\n const totalSec = Math.floor(ms / 1000);\n const s = totalSec % 60;\n const m = Math.floor(totalSec / 60) % 60;\n const hTotal = Math.floor(totalSec / 3600);\n const d = Math.floor(hTotal / 24);\n const h = hTotal % 24;\n\n return { d, h, m, s, totalSec };\n}\n\nfunction pad2(n: number): string {\n return String(n).padStart(2, '0');\n}\n\nfunction toDigitChars(n: number, minDigits: number): string[] {\n const str = String(n).padStart(minDigits, '0');\n\n return [...str];\n}\n\nfunction hasBoolAttr(el: HTMLElement, name: string, defaultValue: boolean): boolean {\n if (!el.hasAttribute(name)) return defaultValue;\n\n const raw = el.getAttribute(name);\n\n if (raw == null || raw === '') return true;\n\n return raw !== 'false';\n}\n\nfunction parseYmdDate(raw: string | null): { year: number; month: number; day: number } | null {\n if (raw == null) return null;\n\n const trimmed = raw.trim();\n\n if (!trimmed) return null;\n\n const m = trimmed.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);\n\n if (!m) return null;\n\n const year = Number(m[1]);\n const month = Number(m[2]);\n const day = Number(m[3]);\n\n if (!Number.isFinite(year) || !Number.isFinite(month) || !Number.isFinite(day)) return null;\n\n return { year, month, day };\n}\n\nfunction parseHmsTime(raw: string | null): {\n hours: number;\n minutes: number;\n seconds: number;\n} {\n if (raw == null) return { ...ZERO_TIME };\n\n const trimmed = raw.trim();\n\n if (!trimmed) return { ...ZERO_TIME };\n\n const parts = trimmed.split(':');\n const h = Number(parts[0] ?? '0');\n const m = Number(parts[1] ?? '0');\n const s = Number(parts[2] ?? '0');\n\n return {\n hours: Number.isFinite(h) ? h : 0,\n minutes: Number.isFinite(m) ? m : 0,\n seconds: Number.isFinite(s) ? s : 0,\n };\n}\n\nfunction parseHmsTimeStrict(\n raw: string | null,\n): { hours: number; minutes: number; seconds: number } | null {\n if (raw == null) return null;\n\n const trimmed = raw.trim();\n\n if (!trimmed) return null;\n\n const m = trimmed.match(/^(\\d{1,2}):(\\d{2})(?::(\\d{2}))?$/);\n\n if (!m) return null;\n\n const hours = Number(m[1]);\n const minutes = Number(m[2]);\n const seconds = Number(m[3] ?? '0');\n\n if (!Number.isFinite(hours) || !Number.isFinite(minutes) || !Number.isFinite(seconds))\n return null;\n\n if (hours < 0 || hours > 23) return null;\n if (minutes < 0 || minutes > 59) return null;\n if (seconds < 0 || seconds > 59) return null;\n\n return { hours, minutes, seconds };\n}\n\nfunction parseUtcOffsetMinutes(raw: string | null): number | null {\n if (raw == null) return null;\n\n let trimmed = raw.trim();\n\n if (!trimmed) return null;\n\n if (/^utc/i.test(trimmed)) {\n trimmed = trimmed.slice(3);\n }\n\n let sign = 1;\n\n if (trimmed[0] === '+') {\n trimmed = trimmed.slice(1);\n } else if (trimmed[0] === '-') {\n sign = -1;\n trimmed = trimmed.slice(1);\n }\n\n if (!trimmed) return null;\n\n const [hStr, mStr = '0'] = trimmed.split(':');\n const h = Number(hStr);\n const m = Number(mStr);\n\n if (!Number.isFinite(h) || !Number.isFinite(m)) return null;\n\n const totalMinutes = h * 60 + m;\n\n return sign * totalMinutes;\n}\n\ntype ZeroHourQueryOverrides = {\n date?: string;\n time?: string;\n utc?: string;\n units?: string;\n};\n\nfunction readZeroHourQueryOverrides(): ZeroHourQueryOverrides | null {\n if (typeof window === 'undefined') return null;\n if (!('location' in window)) return null;\n\n const search = window.location?.search ?? '';\n\n if (!search) return null;\n\n const sp = new URLSearchParams(search);\n const overrides: ZeroHourQueryOverrides = {};\n\n const date = sp.get('date')?.trim();\n\n if (date) overrides.date = date;\n\n const time = sp.get('time')?.trim();\n\n if (time) overrides.time = time;\n\n const utc = sp.get('utc')?.trim();\n\n if (utc) overrides.utc = utc;\n\n const units = sp.get('units')?.trim();\n\n if (units) overrides.units = units;\n\n return Object.keys(overrides).length ? overrides : null;\n}\n\nfunction parseUnitsPattern(raw: string | null): {\n showDays: boolean;\n showHours: boolean;\n showMinutes: boolean;\n showSeconds: boolean;\n} {\n const pattern = (raw ?? '').trim().toLowerCase();\n\n if (!pattern) {\n return DEFAULT_UNITS;\n }\n\n const parts = pattern\n .split(':')\n .map((p) => p.trim())\n .filter(Boolean);\n\n if (!parts.length) {\n return DEFAULT_UNITS;\n }\n\n const set = new Set(parts);\n\n const showDays = set.has('d');\n const showHours = set.has('h');\n const showMinutes = set.has('m');\n const showSeconds = set.has('s');\n\n if (!showDays && !showHours && !showMinutes && !showSeconds) {\n return DEFAULT_UNITS;\n }\n\n return { showDays, showHours, showMinutes, showSeconds };\n}\n\nclass ZeroHour extends HTMLElement {\n static defaultStylesheet: CSSStyleSheet | null = DEFAULT_STYLESHEET;\n\n static observedAttributes = [\n 'digits-url',\n 'separator-url',\n 'autostart',\n 'date',\n 'time',\n 'utc',\n 'units',\n 'mode',\n ];\n\n private readonly shadow = this.attachShadow({ mode: 'open' });\n\n private digitsUrl: string | null = null;\n private separatorUrl: string | null = null;\n private autostart = true;\n\n private durationMs = 0;\n\n private targetEpochMs: number | null = null;\n\n private startEpochMs: number | null = null;\n private nextTickTimeout: number | null = null;\n private doneFired = false;\n\n private rootEl!: HTMLElement;\n private daysEl!: HTMLElement;\n private hoursEl!: HTMLElement;\n private minutesEl!: HTMLElement;\n private secondsEl!: HTMLElement;\n private a11yEl!: HTMLElement;\n private sep0El!: HTMLElement;\n private sep1El!: HTMLElement;\n private sep2El!: HTMLElement;\n private styleEl: HTMLStyleElement | null = null;\n\n private showDays = true;\n private showHours = true;\n private showMinutes = true;\n private showSeconds = true;\n private mode: 'static' | 'scroll' = 'static';\n private hasDigitsRendered = false;\n\n connectedCallback(): void {\n this.render();\n this.readAttributes();\n\n if (this.autostart) this.start();\n else this.renderStaticInitial();\n }\n\n disconnectedCallback(): void {\n this.stop();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n void name;\n void oldValue;\n void newValue;\n\n if (!this.isConnected) return;\n\n const wasRunning = this.isRunning();\n\n this.readAttributes();\n this.doneFired = false;\n\n if (wasRunning && this.autostart) this.start();\n else this.renderStaticInitial();\n }\n\n public start(): void {\n this.stop();\n\n if (!this.digitsUrl) return;\n\n this.durationMs = this.targetEpochMs != null ? this.targetEpochMs - Date.now() : 0;\n\n this.startEpochMs = Date.now();\n\n this.tick();\n this.scheduleNextSecondBoundary();\n }\n\n public stop(): void {\n if (this.nextTickTimeout != null) {\n window.clearTimeout(this.nextTickTimeout);\n\n this.nextTickTimeout = null;\n }\n\n this.startEpochMs = null;\n }\n\n public reset(): void {\n this.doneFired = false;\n\n if (this.autostart) this.start();\n else this.renderStaticInitial();\n }\n\n public isRunning(): boolean {\n return this.startEpochMs != null && this.nextTickTimeout != null;\n }\n\n public isDone(): boolean {\n if (!this.digitsUrl) return false;\n if (this.targetEpochMs == null) return false;\n\n return Date.now() >= this.targetEpochMs;\n }\n\n private readAttributes(): void {\n if (!this.rootEl) this.render();\n\n const query = readZeroHourQueryOverrides();\n\n this.digitsUrl = this.getAttribute('digits-url');\n this.separatorUrl = this.getAttribute('separator-url');\n this.autostart = hasBoolAttr(this, 'autostart', true);\n\n const modeRaw = (this.getAttribute('mode') ?? '').trim().toLowerCase();\n\n this.mode = modeRaw === 'scroll' ? 'scroll' : 'static';\n\n const units = parseUnitsPattern(query?.units ?? this.getAttribute('units'));\n\n this.showDays = units.showDays;\n this.showHours = units.showHours;\n this.showMinutes = units.showMinutes;\n this.showSeconds = units.showSeconds;\n\n const dateFromAttr = parseYmdDate(this.getAttribute('date'));\n const dateFromQuery = parseYmdDate(query?.date ?? null);\n const date = dateFromQuery ?? dateFromAttr;\n\n const timeFromAttr = parseHmsTime(this.getAttribute('time'));\n const timeFromQuery = parseHmsTimeStrict(query?.time ?? null);\n const time = timeFromQuery ?? timeFromAttr;\n\n const offsetMinutesFromAttr = parseUtcOffsetMinutes(this.getAttribute('utc'));\n const offsetMinutesFromQuery = parseUtcOffsetMinutes(query?.utc ?? null);\n const offsetMinutes = offsetMinutesFromQuery ?? offsetMinutesFromAttr ?? 0;\n\n if (!date) {\n this.targetEpochMs = null;\n } else {\n const utcMs = Date.UTC(\n date.year,\n date.month - 1,\n date.day,\n time.hours,\n time.minutes,\n time.seconds,\n );\n\n this.targetEpochMs = utcMs - offsetMinutes * 60 * 1000;\n }\n\n this.durationMs = 0;\n\n if (!this.digitsUrl) {\n this.setTextFallback('—:—:—:—');\n\n return;\n }\n\n this.rootEl.style.setProperty('--zh-digits-url', `url(\"${this.digitsUrl}\")`);\n\n if (this.separatorUrl) {\n this.rootEl.style.setProperty('--zh-sep-url', `url(\"${this.separatorUrl}\")`);\n } else {\n this.rootEl.style.removeProperty('--zh-sep-url');\n }\n\n this.applyUnitsVisibility();\n this.rootEl.classList.toggle('zh--mode-scroll', this.mode === 'scroll');\n }\n\n private renderStaticInitial(): void {\n if (this.targetEpochMs != null) {\n const now = Date.now();\n const diffMs = clampNonNegative(this.targetEpochMs - now);\n const { d, h, m, s } = msToDhms(diffMs);\n\n this.setDigits({ d, h, m, s }, false);\n } else {\n this.setDigits({ d: 0, h: 0, m: 0, s: 0 }, false);\n }\n }\n\n private render(): void {\n this.applyStyles(null);\n\n this.rootEl = document.createElement('div');\n this.rootEl.className = 'zh';\n\n this.daysEl = document.createElement('div');\n this.daysEl.className = 'zh__group';\n this.hoursEl = document.createElement('div');\n this.hoursEl.className = 'zh__group';\n this.minutesEl = document.createElement('div');\n this.minutesEl.className = 'zh__group';\n this.secondsEl = document.createElement('div');\n this.secondsEl.className = 'zh__group';\n\n this.sep0El = document.createElement('span');\n this.sep0El.className = 'zh__sep';\n\n this.sep1El = document.createElement('span');\n this.sep1El.className = 'zh__sep';\n\n this.sep2El = document.createElement('span');\n this.sep2El.className = 'zh__sep';\n\n this.a11yEl = document.createElement('span');\n this.a11yEl.className = 'zh__a11y';\n this.a11yEl.setAttribute('aria-live', 'polite');\n\n this.rootEl.append(\n this.daysEl,\n this.sep0El,\n this.hoursEl,\n this.sep1El,\n this.minutesEl,\n this.sep2El,\n this.secondsEl,\n this.a11yEl,\n );\n\n this.shadow.innerHTML = '';\n\n if (this.styleEl) this.shadow.append(this.styleEl);\n\n this.shadow.append(this.rootEl);\n\n this.setDigits({ d: 0, h: 0, m: 0, s: 0 }, false);\n this.hasDigitsRendered = false;\n }\n\n private setTextFallback(text: string): void {\n this.a11yEl.textContent = text;\n }\n\n private applyUnitsVisibility(): void {\n if (!this.rootEl) return;\n\n this.daysEl.style.display = this.showDays ? '' : 'none';\n this.hoursEl.style.display = this.showHours ? '' : 'none';\n this.minutesEl.style.display = this.showMinutes ? '' : 'none';\n this.secondsEl.style.display = this.showSeconds ? '' : 'none';\n\n const hasSeparator = !!this.separatorUrl;\n\n if (!hasSeparator) {\n this.sep0El.style.display = 'none';\n this.sep1El.style.display = 'none';\n this.sep2El.style.display = 'none';\n\n return;\n }\n\n const groupVisible = [this.showDays, this.showHours, this.showMinutes, this.showSeconds];\n const visibleIndexes: number[] = [];\n\n for (let i = 0; i < groupVisible.length; i++) {\n if (groupVisible[i]) visibleIndexes.push(i);\n }\n\n this.rootEl.style.setProperty('--zh-groups', String(visibleIndexes.length));\n\n const sepUsed = [false, false, false];\n\n if (visibleIndexes.length >= 2) {\n for (let i = 0; i < visibleIndexes.length - 1; i++) {\n const rightIdx = visibleIndexes[i + 1];\n const sepIndex = Math.min(2, Math.max(0, rightIdx - 1));\n\n sepUsed[sepIndex] = true;\n }\n }\n\n this.sep0El.style.display = sepUsed[0] ? '' : 'none';\n this.sep1El.style.display = sepUsed[1] ? '' : 'none';\n this.sep2El.style.display = sepUsed[2] ? '' : 'none';\n }\n\n private setDigits(\n { d, h, m, s }: { d: number; h: number; m: number; s: number },\n animate = true,\n ): void {\n let shouldAnimate = animate;\n\n if (!this.hasDigitsRendered) shouldAnimate = false;\n\n const daysChars = toDigitChars(Math.min(d, 99), 2);\n const hoursChars = toDigitChars(h, 2);\n const minChars = [...pad2(m)];\n const secChars = [...pad2(s)];\n\n this.syncDigitGroup(this.daysEl, daysChars, shouldAnimate);\n this.syncDigitGroup(this.hoursEl, hoursChars, shouldAnimate);\n this.syncDigitGroup(this.minutesEl, minChars, shouldAnimate);\n this.syncDigitGroup(this.secondsEl, secChars, shouldAnimate);\n\n const parts: string[] = [];\n\n if (this.showDays) parts.push(daysChars.join(''));\n if (this.showHours) parts.push(hoursChars.join(''));\n if (this.showMinutes) parts.push(minChars.join(''));\n if (this.showSeconds) parts.push(secChars.join(''));\n\n this.a11yEl.textContent = parts.length ? parts.join(':') : '—';\n this.hasDigitsRendered = true;\n }\n\n private syncDigitGroup(groupEl: HTMLElement, chars: string[], animate: boolean): void {\n while (groupEl.children.length < chars.length) {\n const idx = groupEl.children.length;\n\n groupEl.appendChild(this.createDigitSlot(chars[idx]));\n }\n\n while (groupEl.children.length > chars.length) {\n const last = groupEl.lastElementChild;\n\n if (!last) break;\n\n groupEl.removeChild(last);\n }\n\n for (let i = 0; i < chars.length; i++) {\n const el = groupEl.children[i] as HTMLElement;\n\n this.syncDigitSlot(el, chars[i], animate);\n }\n }\n\n private createDigitSlot(char: string): HTMLElement {\n const digit = document.createElement('span');\n\n digit.className = 'zh__digit';\n\n const track = document.createElement('span');\n\n track.className = 'zh__digit-track';\n\n const face = this.createDigitFace(char);\n\n face.classList.add('zh__digit-face--current');\n\n track.append(face);\n digit.append(track);\n\n return digit;\n }\n\n private createDigitFace(char: string): HTMLElement {\n const face = document.createElement('span');\n\n face.className = 'zh__digit-face';\n\n this.setFaceDigit(face, char);\n\n return face;\n }\n\n private setFaceDigit(face: HTMLElement, char: string): void {\n face.dataset.zhDigit = char;\n\n const idx = digitToSheetIndex(char);\n\n face.style.setProperty('--zh-sheet-index', String(idx));\n }\n\n private ensureDigitTrack(slot: HTMLElement): HTMLElement {\n let track = slot.querySelector<HTMLElement>('.zh__digit-track');\n\n if (!track) {\n track = document.createElement('span');\n track.className = 'zh__digit-track';\n slot.innerHTML = '';\n slot.append(track);\n }\n\n return track;\n }\n\n private getOrCreateCurrentFace(track: HTMLElement, fallbackChar: string): HTMLElement {\n let current = track.querySelector<HTMLElement>('.zh__digit-face--current');\n\n if (!current) {\n const existing = track.querySelector<HTMLElement>('.zh__digit-face');\n\n current = existing ?? this.createDigitFace(fallbackChar);\n current.classList.add('zh__digit-face--current');\n\n this.setFaceDigit(current, current.dataset.zhDigit ?? fallbackChar);\n\n track.innerHTML = '';\n track.append(current);\n } else {\n const faces = Array.from(track.children);\n\n for (const face of faces) {\n if (face !== current) track.removeChild(face);\n }\n }\n\n return current;\n }\n\n private cleanupTrack(track: HTMLElement, faceToKeep: HTMLElement): void {\n if (!track.contains(faceToKeep)) return;\n\n const faces = Array.from(track.children);\n\n for (const face of faces) {\n if (face !== faceToKeep) track.removeChild(face);\n }\n\n faceToKeep.classList.remove('zh__digit-face--next');\n faceToKeep.classList.add('zh__digit-face--current');\n\n track.style.transition = this.mode === 'scroll' ? '' : 'none';\n track.style.transform = 'translateY(0)';\n }\n\n private parseTransitionMs(el: HTMLElement): number {\n const style = window.getComputedStyle(el);\n const durations = style.transitionDuration.split(',').map((v) => v.trim());\n const delays = style.transitionDelay.split(',').map((v) => v.trim());\n\n const toMs = (val: string): number => {\n if (!val) return 0;\n if (val.endsWith('ms')) return Number.parseFloat(val);\n if (val.endsWith('s')) return Number.parseFloat(val) * 1000;\n\n return Number.parseFloat(val) || 0;\n };\n\n const d = durations[0] ? toMs(durations[0]) : 0;\n const delay = delays[0] ? toMs(delays[0]) : 0;\n\n return d + delay;\n }\n\n private animateDigitChange(track: HTMLElement, currentFace: HTMLElement, newChar: string): void {\n const nextFace = this.createDigitFace(newChar);\n\n nextFace.classList.add('zh__digit-face--next');\n\n track.innerHTML = '';\n track.append(nextFace, currentFace);\n\n track.style.transition = 'none';\n track.style.transform = 'translateY(-100%)';\n\n void track.offsetHeight;\n\n track.style.transition = '';\n track.style.transform = 'translateY(0)';\n\n const cleanup = () => {\n track.removeEventListener('transitionend', cleanup);\n\n if (!track.contains(nextFace)) return;\n\n this.cleanupTrack(track, nextFace);\n };\n\n track.addEventListener('transitionend', cleanup, { once: true });\n\n const guardMs = this.parseTransitionMs(track) + 150;\n\n window.setTimeout(cleanup, guardMs || 800);\n }\n\n private syncDigitSlot(slot: HTMLElement, char: string, animate: boolean): void {\n const track = this.ensureDigitTrack(slot);\n const currentFace = this.getOrCreateCurrentFace(track, char);\n const currentChar = currentFace.dataset.zhDigit ?? char;\n\n this.setFaceDigit(currentFace, currentChar);\n\n if (currentChar === char || !animate || this.mode !== 'scroll') {\n if (currentChar !== char) this.setFaceDigit(currentFace, char);\n\n this.cleanupTrack(track, currentFace);\n\n return;\n }\n\n this.animateDigitChange(track, currentFace, char);\n }\n\n private tick(): void {\n if (!this.digitsUrl) return;\n\n const durationMs = clampNonNegative(this.durationMs);\n\n if (durationMs === 0) {\n this.setDigits({ d: 0, h: 0, m: 0, s: 0 });\n this.fireDoneOnce();\n this.stop();\n\n return;\n }\n\n const start = this.startEpochMs ?? Date.now();\n const elapsedMs = clampNonNegative(Date.now() - start);\n const shownMs = clampNonNegative(durationMs - elapsedMs);\n\n const { d, h, m, s, totalSec } = msToDhms(shownMs);\n\n this.setDigits({ d, h, m, s });\n\n const isDone = totalSec === 0;\n\n if (isDone) {\n this.fireDoneOnce();\n this.stop();\n }\n }\n\n private fireDoneOnce(): void {\n if (this.doneFired) return;\n\n this.doneFired = true;\n\n this.dispatchEvent(new CustomEvent('done'));\n }\n\n private scheduleNextSecondBoundary(): void {\n const now = Date.now();\n const msToNextSecond = 1000 - (now % 1000);\n\n this.nextTickTimeout = window.setTimeout(() => {\n this.tick();\n\n if (this.isRunning()) this.scheduleNextSecondBoundary();\n }, msToNextSecond);\n }\n\n public adoptStylesheet(sheet: CSSStyleSheet): void {\n this.applyStyles(sheet);\n }\n\n public adoptStyles(styles: StylesInput): void {\n this.applyStyles(styles);\n }\n\n private applyStyles(styles: StylesInput): void {\n if (typeof styles === 'string') {\n if (supportsAdoptedStyleSheets(this.shadow)) {\n const sheet = makeConstructableSheet(styles);\n\n if (sheet) {\n this.shadow.adoptedStyleSheets = [sheet];\n this.styleEl = null;\n\n return;\n }\n }\n\n if (!this.styleEl) this.styleEl = document.createElement('style');\n\n this.styleEl.textContent = styles;\n\n return;\n }\n\n if (styles && supportsAdoptedStyleSheets(this.shadow)) {\n this.shadow.adoptedStyleSheets = [styles];\n this.styleEl = null;\n\n return;\n }\n\n if (ZeroHour.defaultStylesheet && supportsAdoptedStyleSheets(this.shadow)) {\n this.shadow.adoptedStyleSheets = [ZeroHour.defaultStylesheet];\n this.styleEl = null;\n\n return;\n }\n\n if (!this.styleEl) this.styleEl = document.createElement('style');\n\n this.styleEl.textContent = DEFAULT_CSS_TEXT;\n }\n}\n\nif (!customElements.get('countdown-timer')) {\n customElements.define('countdown-timer', ZeroHour);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'countdown-timer': ZeroHour;\n }\n}\n\nexport function initCountdownTimers(\n options: {\n selector?: string;\n onDone?: (el: HTMLElement) => void;\n stylesheet?: CSSStyleSheet | string | null;\n } = {},\n): HTMLElement[] {\n const { selector = 'countdown-timer', onDone, stylesheet } = options;\n const elements = Array.from(document.querySelectorAll<HTMLElement>(selector));\n\n if (onDone) {\n const notified = new WeakSet<HTMLElement>();\n const notifyOnce = (el: HTMLElement) => {\n if (notified.has(el)) return;\n\n notified.add(el);\n\n onDone(el);\n };\n\n elements.forEach((el) => {\n el.addEventListener('done', () => notifyOnce(el));\n\n const zh = el as unknown as ZeroHour;\n\n if (typeof (zh as unknown as { isDone?: unknown }).isDone === 'function' && zh.isDone()) {\n notifyOnce(el);\n }\n });\n }\n\n if (stylesheet) {\n elements.forEach((el) => {\n const zh = el as unknown as ZeroHour;\n\n if (typeof stylesheet === 'string') zh.adoptStyles(stylesheet);\n else zh.adoptStylesheet(stylesheet);\n });\n }\n\n return elements;\n}\n"],"mappings":"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"}