new-js-clock 1.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,684 @@
1
+ /**
2
+ * new-js-clock v1.0.0
3
+ * A modern TypeScript clock library with countdown support - jQuery-free rewrite of JS-Clock
4
+ *
5
+ * @author tcpweb
6
+ * @license MIT
7
+ * @repository https://github.com/thiago-cavalcanti/new-js-clock.git
8
+ */
9
+ "use strict";
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+
28
+ // src/index.ts
29
+ var index_exports = {};
30
+ __export(index_exports, {
31
+ createClock: () => createClock,
32
+ default: () => index_default
33
+ });
34
+ module.exports = __toCommonJS(index_exports);
35
+
36
+ // src/internal/globalTicker.ts
37
+ var activeClocks = /* @__PURE__ */ new Set();
38
+ var globalTimeoutId = null;
39
+ var globalAnimationFrameId = null;
40
+ var isGlobalPageVisible = true;
41
+ function getGlobalTimeoutDelay(now) {
42
+ let nextDelay = Infinity;
43
+ for (const clock of activeClocks) {
44
+ const delay = clock._getTimeoutDelay(now);
45
+ if (Number.isFinite(delay) && delay >= 0 && delay < nextDelay) {
46
+ nextDelay = delay;
47
+ }
48
+ }
49
+ if (!Number.isFinite(nextDelay)) {
50
+ return 1e3;
51
+ }
52
+ return Math.max(nextDelay, 0);
53
+ }
54
+ function handleGlobalVisibilityChange() {
55
+ isGlobalPageVisible = !document.hidden;
56
+ if (!isGlobalPageVisible) {
57
+ if (globalAnimationFrameId !== null) {
58
+ window.cancelAnimationFrame(globalAnimationFrameId);
59
+ globalAnimationFrameId = null;
60
+ }
61
+ if (globalTimeoutId === null) {
62
+ globalTimeoutId = window.setTimeout(globalTick, getGlobalTimeoutDelay(Date.now()));
63
+ }
64
+ } else {
65
+ window.clearTimeout(globalTimeoutId);
66
+ globalTimeoutId = null;
67
+ const now = Date.now();
68
+ for (const clock of activeClocks) {
69
+ if (clock._isSystemDriven()) {
70
+ clock._tick(now);
71
+ }
72
+ }
73
+ const requestsRaf = Array.from(activeClocks).some((c) => c._requestsAnimationFrame());
74
+ if (requestsRaf) {
75
+ window.cancelAnimationFrame(globalAnimationFrameId);
76
+ globalAnimationFrameId = window.requestAnimationFrame(globalTick);
77
+ } else {
78
+ globalTimeoutId = window.setTimeout(globalTick, getGlobalTimeoutDelay(now));
79
+ }
80
+ }
81
+ }
82
+ function ensureVisibilityListener() {
83
+ document.addEventListener("visibilitychange", handleGlobalVisibilityChange);
84
+ }
85
+ function detachVisibilityListener() {
86
+ if (typeof document !== "undefined") {
87
+ document.removeEventListener("visibilitychange", handleGlobalVisibilityChange);
88
+ }
89
+ }
90
+ function stopGlobalTicker() {
91
+ if (globalTimeoutId !== null) {
92
+ window.clearTimeout(globalTimeoutId);
93
+ globalTimeoutId = null;
94
+ }
95
+ if (globalAnimationFrameId !== null) {
96
+ window.cancelAnimationFrame(globalAnimationFrameId);
97
+ globalAnimationFrameId = null;
98
+ }
99
+ }
100
+ function startGlobalTicker() {
101
+ const requestsRaf = Array.from(activeClocks).some((c) => c._requestsAnimationFrame());
102
+ if (requestsRaf && isGlobalPageVisible) {
103
+ if (globalTimeoutId !== null) {
104
+ window.clearTimeout(globalTimeoutId);
105
+ globalTimeoutId = null;
106
+ }
107
+ if (globalAnimationFrameId === null) {
108
+ globalAnimationFrameId = window.requestAnimationFrame(globalTick);
109
+ }
110
+ } else {
111
+ if (globalAnimationFrameId !== null) {
112
+ window.cancelAnimationFrame(globalAnimationFrameId);
113
+ globalAnimationFrameId = null;
114
+ }
115
+ if (globalTimeoutId === null) {
116
+ globalTimeoutId = window.setTimeout(globalTick, getGlobalTimeoutDelay(Date.now()));
117
+ }
118
+ }
119
+ }
120
+ function globalTick(timestamp) {
121
+ if (activeClocks.size === 0) {
122
+ stopGlobalTicker();
123
+ return;
124
+ }
125
+ const now = Date.now();
126
+ const requestsRaf = Array.from(activeClocks).some((c) => c._requestsAnimationFrame());
127
+ for (const clock of activeClocks) {
128
+ clock._tick(now, timestamp);
129
+ }
130
+ if (requestsRaf && isGlobalPageVisible) {
131
+ globalAnimationFrameId = window.requestAnimationFrame(globalTick);
132
+ } else {
133
+ globalTimeoutId = window.setTimeout(globalTick, getGlobalTimeoutDelay(now));
134
+ }
135
+ }
136
+ function addClock(clock) {
137
+ activeClocks.add(clock);
138
+ if (clock._requestsAnimationFrame()) {
139
+ ensureVisibilityListener();
140
+ }
141
+ startGlobalTicker();
142
+ }
143
+ function removeClock(clock) {
144
+ activeClocks.delete(clock);
145
+ if (activeClocks.size === 0) {
146
+ stopGlobalTicker();
147
+ detachVisibilityListener();
148
+ return;
149
+ }
150
+ const hasRafClock = Array.from(activeClocks).some((c) => c._requestsAnimationFrame());
151
+ if (!hasRafClock) {
152
+ detachVisibilityListener();
153
+ }
154
+ startGlobalTicker();
155
+ }
156
+
157
+ // src/index.ts
158
+ function validateTimeString(timeString) {
159
+ const pattern = /^(([01][0-9])|(2[0-3])):[0-5][0-9]:[0-5][0-9](:[0-9][0-9])?$/;
160
+ return pattern.test(timeString);
161
+ }
162
+ function isValidTimezone(timezone) {
163
+ try {
164
+ Intl.DateTimeFormat(void 0, { timeZone: timezone });
165
+ return true;
166
+ } catch {
167
+ return false;
168
+ }
169
+ }
170
+ function parseTimeString(timeString) {
171
+ const parts = timeString.split(":");
172
+ return {
173
+ hours: parseInt(parts[0], 10),
174
+ minutes: parseInt(parts[1], 10),
175
+ seconds: parseInt(parts[2], 10),
176
+ centiseconds: parts[3] ? parseInt(parts[3], 10) : 0
177
+ };
178
+ }
179
+ function padZero(num) {
180
+ return num < 10 ? `0${num}` : num.toString();
181
+ }
182
+ function to12Hour(hours) {
183
+ const period = hours >= 12 ? "PM" : "AM";
184
+ const convertedHours = hours % 12 || 12;
185
+ return { hours: convertedHours, period };
186
+ }
187
+ function formatTimeString(components, showCenti, showHour, showMinute, use12Hour) {
188
+ const parts = [];
189
+ let period = "";
190
+ if (showHour) {
191
+ let displayHours = components.hours;
192
+ if (use12Hour) {
193
+ const converted = to12Hour(components.hours);
194
+ displayHours = converted.hours;
195
+ period = converted.period;
196
+ }
197
+ parts.push(padZero(displayHours));
198
+ }
199
+ if (showMinute) {
200
+ parts.push(padZero(components.minutes));
201
+ }
202
+ parts.push(padZero(components.seconds));
203
+ if (showCenti) {
204
+ parts.push(padZero(components.centiseconds));
205
+ }
206
+ let timeString = parts.join(":");
207
+ if (period) {
208
+ timeString += " " + period;
209
+ }
210
+ return timeString;
211
+ }
212
+ function isHTMLelement(value) {
213
+ return typeof HTMLElement !== "undefined" && value instanceof HTMLElement;
214
+ }
215
+ function createClock(element, initialTime, options = {}) {
216
+ if (!isHTMLelement(element)) {
217
+ throw new TypeError("Invalid element: must be an HTMLElement");
218
+ }
219
+ if (options === null || typeof options !== "object" || Array.isArray(options)) {
220
+ throw new TypeError("Invalid options: must be an object");
221
+ }
222
+ if (options.countdown !== void 0 && typeof options.countdown !== "boolean") {
223
+ throw new TypeError("Invalid countdown option: must be a boolean");
224
+ }
225
+ if (options.showCenti !== void 0 && typeof options.showCenti !== "boolean") {
226
+ throw new TypeError("Invalid showCenti option: must be a boolean");
227
+ }
228
+ if (options.showHour !== void 0 && typeof options.showHour !== "boolean") {
229
+ throw new TypeError("Invalid showHour option: must be a boolean");
230
+ }
231
+ if (options.showMinute !== void 0 && typeof options.showMinute !== "boolean") {
232
+ throw new TypeError("Invalid showMinute option: must be a boolean");
233
+ }
234
+ if (options.callback !== void 0 && typeof options.callback !== "function") {
235
+ throw new TypeError("Invalid callback: must be a function");
236
+ }
237
+ if (options.use12Hour !== void 0 && typeof options.use12Hour !== "boolean") {
238
+ throw new TypeError("Invalid use12Hour option: must be a boolean");
239
+ }
240
+ if (options.timezoneOffset !== void 0 && typeof options.timezoneOffset !== "number") {
241
+ throw new TypeError("Invalid timezoneOffset option: must be a number");
242
+ }
243
+ if (options.timezoneOffset !== void 0 && (!Number.isFinite(options.timezoneOffset) || options.timezoneOffset < -12 || options.timezoneOffset > 14)) {
244
+ throw new RangeError("Invalid timezoneOffset: must be between -12 and +14");
245
+ }
246
+ if (options.timezone !== void 0 && typeof options.timezone !== "string") {
247
+ throw new TypeError("Invalid timezone option: must be a string");
248
+ }
249
+ if (options.timezone !== void 0 && !isValidTimezone(options.timezone)) {
250
+ throw new RangeError(`Invalid timezone: "${options.timezone}" is not a valid IANA timezone name`);
251
+ }
252
+ if (options.timezone !== void 0 && options.timezoneOffset !== void 0) {
253
+ throw new Error("Cannot use both timezone and timezoneOffset options; choose one");
254
+ }
255
+ if (options.stopwatch !== void 0 && typeof options.stopwatch !== "boolean") {
256
+ throw new TypeError("Invalid stopwatch option: must be a boolean");
257
+ }
258
+ if (options.lap !== void 0 && typeof options.lap !== "boolean") {
259
+ throw new TypeError("Invalid lap option: must be a boolean");
260
+ }
261
+ if (options.lapWord !== void 0 && typeof options.lapWord !== "string") {
262
+ throw new TypeError("Invalid lapWord option: must be a string");
263
+ }
264
+ if (options.lapMode !== void 0 && !["splits", "laps", "both"].includes(options.lapMode)) {
265
+ throw new TypeError('Invalid lapMode option: must be "splits", "laps", or "both"');
266
+ }
267
+ if (options.useAnimationFrame !== void 0 && typeof options.useAnimationFrame !== "boolean") {
268
+ throw new TypeError("Invalid useAnimationFrame option: must be a boolean");
269
+ }
270
+ if (options.lap === true && options.stopwatch !== true) {
271
+ throw new Error("Lap mode requires stopwatch mode to be enabled");
272
+ }
273
+ if (options.lapMode !== void 0 && options.lap !== true) {
274
+ throw new Error("lapMode requires lap mode to be enabled");
275
+ }
276
+ let time = { hours: 0, minutes: 0, seconds: 0, centiseconds: 0 };
277
+ let isStopped = false;
278
+ let isDestroyed = false;
279
+ let lapRecords = [];
280
+ let lastLapPerfTime = performance.now();
281
+ let customClockStartTimeMs = Date.now();
282
+ let customClockElapsedMs = 0;
283
+ let initialTimeMs = 0;
284
+ let lastTimestamp = 0;
285
+ let accumulatedTime = 0;
286
+ const useAnimationFrame = options.useAnimationFrame ?? false;
287
+ const showCenti = options.showCenti ?? false;
288
+ const showHour = options.showHour ?? true;
289
+ const showMinute = options.showMinute ?? true;
290
+ const isCountdown = options.countdown ?? false;
291
+ const isStopwatch = options.stopwatch ?? false;
292
+ const useLap = options.lap ?? false;
293
+ const lapMode = options.lapMode ?? "both";
294
+ const lapWord = options.lapWord ?? (lapMode === "splits" ? "Split" : "Lap");
295
+ const callback = options.callback;
296
+ const use12Hour = options.use12Hour ?? false;
297
+ const timezoneOffset = options.timezoneOffset;
298
+ const timezone = options.timezone;
299
+ const isSystemDrivenClock = !isCountdown && !isStopwatch && !initialTime;
300
+ if (isCountdown && !initialTime) {
301
+ throw new Error("Initial time required for countdown mode");
302
+ }
303
+ if (isStopwatch && (timezone !== void 0 || timezoneOffset !== void 0)) {
304
+ throw new Error("Stopwatch mode cannot be combined with timezone options");
305
+ }
306
+ if (initialTime) {
307
+ if (!validateTimeString(initialTime)) {
308
+ throw new Error("Invalid time string format: must be HH:MM:SS or HH:MM:SS:CC with leading zeros");
309
+ }
310
+ time = parseTimeString(initialTime);
311
+ initialTimeMs = time.hours * 36e5 + time.minutes * 6e4 + time.seconds * 1e3 + time.centiseconds * 10;
312
+ } else if (isStopwatch) {
313
+ time = { hours: 0, minutes: 0, seconds: 0, centiseconds: 0 };
314
+ initialTimeMs = 0;
315
+ }
316
+ function updateDisplay() {
317
+ const timeString = formatTimeString(time, showCenti, showHour, showMinute, use12Hour);
318
+ if (element.textContent !== timeString) {
319
+ element.textContent = timeString;
320
+ }
321
+ }
322
+ function syncWithSystemTime(nowTime) {
323
+ const now = nowTime ? new Date(nowTime) : /* @__PURE__ */ new Date();
324
+ if (timezone !== void 0) {
325
+ const formatter = new Intl.DateTimeFormat("en-US", {
326
+ timeZone: timezone,
327
+ hour: "2-digit",
328
+ minute: "2-digit",
329
+ second: "2-digit",
330
+ hour12: false
331
+ });
332
+ const parts = formatter.formatToParts(now);
333
+ const getPart = (type) => {
334
+ const part = parts.find((p) => p.type === type);
335
+ return part ? parseInt(part.value, 10) : 0;
336
+ };
337
+ const normalizedHour = getPart("hour") % 24;
338
+ time = {
339
+ hours: normalizedHour,
340
+ minutes: getPart("minute"),
341
+ seconds: getPart("second"),
342
+ centiseconds: showCenti ? Math.floor(now.getMilliseconds() / 10) : 0
343
+ };
344
+ } else if (timezoneOffset !== void 0) {
345
+ const offsetMs = timezoneOffset * 60 * 60 * 1e3;
346
+ const adjustedTime = new Date(now.getTime() + offsetMs);
347
+ time = {
348
+ hours: adjustedTime.getUTCHours(),
349
+ minutes: adjustedTime.getUTCMinutes(),
350
+ seconds: adjustedTime.getUTCSeconds(),
351
+ centiseconds: showCenti ? Math.floor(adjustedTime.getUTCMilliseconds() / 10) : 0
352
+ };
353
+ } else {
354
+ time = {
355
+ hours: now.getHours(),
356
+ minutes: now.getMinutes(),
357
+ seconds: now.getSeconds(),
358
+ centiseconds: showCenti ? Math.floor(now.getMilliseconds() / 10) : 0
359
+ };
360
+ }
361
+ }
362
+ function syncCustomTimeAnchor(now) {
363
+ const currentElapsedMs = customClockElapsedMs + (now - customClockStartTimeMs);
364
+ const intervalMs = showCenti ? 10 : 1e3;
365
+ const elapsedIntervals = Math.floor(currentElapsedMs / intervalMs);
366
+ const effectiveElapsedMs = elapsedIntervals * intervalMs;
367
+ if (isCountdown) {
368
+ const remainingRawMs = initialTimeMs - currentElapsedMs;
369
+ if (remainingRawMs <= 0) {
370
+ completeCountdown(true);
371
+ return;
372
+ }
373
+ const currentMs = initialTimeMs - effectiveElapsedMs;
374
+ const totalCs = Math.floor(currentMs / 10);
375
+ time = {
376
+ hours: Math.floor(totalCs / 36e4) % 24,
377
+ minutes: Math.floor(totalCs % 36e4 / 6e3),
378
+ seconds: Math.floor(totalCs % 6e3 / 100),
379
+ centiseconds: totalCs % 100
380
+ };
381
+ } else {
382
+ const currentMs = initialTimeMs + effectiveElapsedMs;
383
+ const totalCs = Math.floor(currentMs / 10);
384
+ time = {
385
+ hours: Math.floor(totalCs / 36e4) % 24,
386
+ minutes: Math.floor(totalCs % 36e4 / 6e3),
387
+ seconds: Math.floor(totalCs % 6e3 / 100),
388
+ centiseconds: totalCs % 100
389
+ };
390
+ }
391
+ }
392
+ function _getTimeoutDelay(now) {
393
+ if (showCenti) {
394
+ return 10;
395
+ }
396
+ if (isSystemDrivenClock) {
397
+ return 1e3 - now % 1e3;
398
+ }
399
+ const elapsedMs = customClockElapsedMs + (now - customClockStartTimeMs);
400
+ const elapsedRemainder = elapsedMs % 1e3;
401
+ const msToNextSecond = elapsedRemainder === 0 ? 1e3 : 1e3 - elapsedRemainder;
402
+ if (isCountdown) {
403
+ const remainingMs = initialTimeMs - elapsedMs;
404
+ if (remainingMs <= 0) {
405
+ return 0;
406
+ }
407
+ if (remainingMs < 1e3) {
408
+ return remainingMs;
409
+ }
410
+ return Math.min(msToNextSecond, remainingMs);
411
+ }
412
+ return msToNextSecond;
413
+ }
414
+ function setTimeToZero() {
415
+ time = { hours: 0, minutes: 0, seconds: 0, centiseconds: 0 };
416
+ }
417
+ function completeCountdown(invokeCallback) {
418
+ stopClock();
419
+ customClockElapsedMs = initialTimeMs;
420
+ customClockStartTimeMs = Date.now();
421
+ setTimeToZero();
422
+ if (invokeCallback && callback) {
423
+ callback();
424
+ }
425
+ }
426
+ function finalizeZeroCountdown(invokeCallback) {
427
+ if (!isCountdown || initialTimeMs !== 0) {
428
+ return false;
429
+ }
430
+ completeCountdown(invokeCallback);
431
+ updateDisplay();
432
+ return true;
433
+ }
434
+ function _tick(now, timestamp) {
435
+ if (isStopped || isDestroyed) return;
436
+ if (isSystemDrivenClock) {
437
+ syncWithSystemTime(now);
438
+ updateDisplay();
439
+ return;
440
+ }
441
+ if (useAnimationFrame && timestamp !== void 0) {
442
+ if (lastTimestamp === 0) {
443
+ lastTimestamp = timestamp;
444
+ }
445
+ const delta = timestamp - lastTimestamp;
446
+ lastTimestamp = timestamp;
447
+ accumulatedTime += delta;
448
+ const tickInterval = showCenti ? 10 : 1e3;
449
+ let shouldUpdate = false;
450
+ while (accumulatedTime >= tickInterval) {
451
+ accumulatedTime -= tickInterval;
452
+ shouldUpdate = true;
453
+ }
454
+ if (shouldUpdate) {
455
+ syncCustomTimeAnchor(now);
456
+ updateDisplay();
457
+ }
458
+ } else {
459
+ syncCustomTimeAnchor(now);
460
+ updateDisplay();
461
+ }
462
+ }
463
+ const internalInstance = {
464
+ getTime,
465
+ setTime,
466
+ stopClock,
467
+ startClock,
468
+ toggleClock,
469
+ destroy,
470
+ isRunning,
471
+ reset,
472
+ lap,
473
+ getLaps,
474
+ getSplitTimes,
475
+ getLapTimes,
476
+ getLapRecords,
477
+ clearLaps,
478
+ bestLap,
479
+ worstLap,
480
+ _tick,
481
+ _requestsAnimationFrame: () => useAnimationFrame,
482
+ _isSystemDriven: () => isSystemDrivenClock,
483
+ _getTimeoutDelay
484
+ };
485
+ function startSystemClock() {
486
+ syncWithSystemTime();
487
+ updateDisplay();
488
+ addClock(internalInstance);
489
+ }
490
+ function startCustomClock() {
491
+ customClockStartTimeMs = Date.now();
492
+ updateDisplay();
493
+ addClock(internalInstance);
494
+ }
495
+ function stopClock() {
496
+ if (!isStopped && !isSystemDrivenClock) {
497
+ customClockElapsedMs += Date.now() - customClockStartTimeMs;
498
+ }
499
+ isStopped = true;
500
+ removeClock(internalInstance);
501
+ }
502
+ function startClock() {
503
+ if (isDestroyed || !isStopped) return;
504
+ isStopped = false;
505
+ if (!isSystemDrivenClock) {
506
+ customClockStartTimeMs = Date.now();
507
+ } else {
508
+ syncWithSystemTime();
509
+ }
510
+ updateDisplay();
511
+ addClock(internalInstance);
512
+ }
513
+ function toggleClock() {
514
+ if (isStopped) {
515
+ startClock();
516
+ } else {
517
+ stopClock();
518
+ }
519
+ }
520
+ function getTime() {
521
+ return formatTimeString(time, showCenti, showHour, showMinute, use12Hour);
522
+ }
523
+ function isRunning() {
524
+ return !isStopped && !isDestroyed;
525
+ }
526
+ function destroy() {
527
+ isDestroyed = true;
528
+ stopClock();
529
+ element.textContent = "";
530
+ }
531
+ function setTime(timeString) {
532
+ if (isDestroyed) return;
533
+ if (!validateTimeString(timeString)) {
534
+ throw new Error("Invalid time string format: must be HH:MM:SS or HH:MM:SS:CC with leading zeros");
535
+ }
536
+ time = parseTimeString(timeString);
537
+ initialTimeMs = time.hours * 36e5 + time.minutes * 6e4 + time.seconds * 1e3 + time.centiseconds * 10;
538
+ customClockElapsedMs = 0;
539
+ customClockStartTimeMs = Date.now();
540
+ if (finalizeZeroCountdown(true)) {
541
+ return;
542
+ }
543
+ updateDisplay();
544
+ }
545
+ function reset() {
546
+ if (isDestroyed) return;
547
+ if (isStopwatch) {
548
+ time = { hours: 0, minutes: 0, seconds: 0, centiseconds: 0 };
549
+ initialTimeMs = 0;
550
+ customClockElapsedMs = 0;
551
+ customClockStartTimeMs = Date.now();
552
+ lapRecords = [];
553
+ lastLapPerfTime = performance.now();
554
+ } else if (initialTime) {
555
+ time = parseTimeString(initialTime);
556
+ initialTimeMs = time.hours * 36e5 + time.minutes * 6e4 + time.seconds * 1e3 + time.centiseconds * 10;
557
+ customClockElapsedMs = 0;
558
+ customClockStartTimeMs = Date.now();
559
+ } else {
560
+ syncWithSystemTime();
561
+ }
562
+ if (finalizeZeroCountdown(true)) {
563
+ return;
564
+ }
565
+ isStopped = false;
566
+ updateDisplay();
567
+ addClock(internalInstance);
568
+ }
569
+ function lap() {
570
+ if (isDestroyed) return "";
571
+ assertLapModeEnabled();
572
+ const now = performance.now();
573
+ const preciseElapsedMs = now - lastLapPerfTime;
574
+ lastLapPerfTime = now;
575
+ const splitTime = formatTimeString(time, showCenti, showHour, showMinute, use12Hour);
576
+ const lapNumber = lapRecords.length + 1;
577
+ const totalCs = Math.round(preciseElapsedMs / 10);
578
+ const lapDiff = {
579
+ hours: Math.floor(totalCs / 36e4),
580
+ minutes: Math.floor(totalCs % 36e4 / 6e3),
581
+ seconds: Math.floor(totalCs % 6e3 / 100),
582
+ centiseconds: totalCs % 100
583
+ };
584
+ const lapTime = formatTimeString(lapDiff, showCenti, showHour, showMinute, use12Hour);
585
+ const timestamp = Date.now();
586
+ const record = {
587
+ lapNumber,
588
+ lapTime,
589
+ splitTime,
590
+ preciseElapsedMs,
591
+ timestamp
592
+ };
593
+ lapRecords.push(record);
594
+ if (lapMode === "splits") {
595
+ return lapWord ? `${lapWord} ${lapNumber}: ${splitTime}` : `${lapNumber}: ${splitTime}`;
596
+ } else if (lapMode === "laps") {
597
+ return lapWord ? `${lapWord} ${lapNumber}: ${lapTime}` : `${lapNumber}: ${lapTime}`;
598
+ } else {
599
+ return lapWord ? `${lapWord} ${lapNumber}: ${lapTime} (${splitTime})` : `${lapNumber}: ${lapTime} (${splitTime})`;
600
+ }
601
+ }
602
+ function getLaps() {
603
+ if (isDestroyed) return [];
604
+ assertLapModeEnabled();
605
+ return lapRecords.map((record) => {
606
+ if (lapMode === "splits") {
607
+ return lapWord ? `${lapWord} ${record.lapNumber}: ${record.splitTime}` : `${record.lapNumber}: ${record.splitTime}`;
608
+ } else if (lapMode === "laps") {
609
+ return lapWord ? `${lapWord} ${record.lapNumber}: ${record.lapTime}` : `${record.lapNumber}: ${record.lapTime}`;
610
+ } else {
611
+ return lapWord ? `${lapWord} ${record.lapNumber}: ${record.lapTime} (${record.splitTime})` : `${record.lapNumber}: ${record.lapTime} (${record.splitTime})`;
612
+ }
613
+ });
614
+ }
615
+ function getSplitTimes() {
616
+ if (isDestroyed) return [];
617
+ assertLapModeEnabled();
618
+ if (lapMode === "laps") {
619
+ throw new Error('Split times are only available when lapMode is "splits" or "both"');
620
+ }
621
+ return lapRecords.map(
622
+ (record) => lapWord ? `${lapWord} ${record.lapNumber}: ${record.splitTime}` : `${record.lapNumber}: ${record.splitTime}`
623
+ );
624
+ }
625
+ function getLapTimes() {
626
+ if (isDestroyed) return [];
627
+ assertLapModeEnabled();
628
+ if (lapMode === "splits") {
629
+ throw new Error('Lap times are only available when lapMode is "laps" or "both"');
630
+ }
631
+ return lapRecords.map(
632
+ (record) => lapWord ? `${lapWord} ${record.lapNumber}: ${record.lapTime}` : `${record.lapNumber}: ${record.lapTime}`
633
+ );
634
+ }
635
+ function getLapRecords() {
636
+ if (isDestroyed) return [];
637
+ assertLapModeEnabled();
638
+ return [...lapRecords];
639
+ }
640
+ function bestLap() {
641
+ if (isDestroyed) return null;
642
+ assertLapModeEnabled();
643
+ if (lapMode === "splits") {
644
+ throw new Error('bestLap() is only available when lapMode is "laps" or "both"');
645
+ }
646
+ if (lapRecords.length === 0) return null;
647
+ return lapRecords.reduce(
648
+ (best, record) => record.preciseElapsedMs < best.preciseElapsedMs ? record : best
649
+ );
650
+ }
651
+ function worstLap() {
652
+ if (isDestroyed) return null;
653
+ assertLapModeEnabled();
654
+ if (lapMode === "splits") {
655
+ throw new Error('worstLap() is only available when lapMode is "laps" or "both"');
656
+ }
657
+ if (lapRecords.length === 0) return null;
658
+ return lapRecords.reduce(
659
+ (worst, record) => record.preciseElapsedMs > worst.preciseElapsedMs ? record : worst
660
+ );
661
+ }
662
+ function clearLaps() {
663
+ if (isDestroyed) return;
664
+ assertLapModeEnabled();
665
+ lapRecords = [];
666
+ lastLapPerfTime = performance.now();
667
+ }
668
+ function assertLapModeEnabled() {
669
+ if (!useLap) {
670
+ throw new Error("Lap mode is not enabled");
671
+ }
672
+ }
673
+ if (finalizeZeroCountdown(true)) {
674
+ } else if (isStopwatch) {
675
+ startCustomClock();
676
+ } else if (initialTime) {
677
+ startCustomClock();
678
+ } else {
679
+ startSystemClock();
680
+ }
681
+ return internalInstance;
682
+ }
683
+ var index_default = createClock;
684
+ //# sourceMappingURL=index.cjs.map