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