@wcstack/timer 1.12.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.
@@ -0,0 +1,522 @@
1
+ const _config = {
2
+ autoTrigger: true,
3
+ triggerAttribute: "data-timertarget",
4
+ tagNames: {
5
+ timer: "wcs-timer",
6
+ },
7
+ };
8
+ function deepFreeze(obj) {
9
+ if (obj === null || typeof obj !== "object")
10
+ return obj;
11
+ Object.freeze(obj);
12
+ for (const key of Object.keys(obj)) {
13
+ deepFreeze(obj[key]);
14
+ }
15
+ return obj;
16
+ }
17
+ function deepClone(obj) {
18
+ if (obj === null || typeof obj !== "object")
19
+ return obj;
20
+ const clone = {};
21
+ for (const key of Object.keys(obj)) {
22
+ clone[key] = deepClone(obj[key]);
23
+ }
24
+ return clone;
25
+ }
26
+ let frozenConfig = null;
27
+ // Internal-only live handle to the mutable config. NOT part of the public API
28
+ // (deliberately absent from exports.ts) — it is exported solely so sibling
29
+ // modules in this package can read current settings cheaply. External consumers
30
+ // must use getConfig() (returns a deep-frozen snapshot) / setConfig(). Mutating
31
+ // this object directly bypasses the frozenConfig cache and is unsupported.
32
+ const config = _config;
33
+ function getConfig() {
34
+ if (!frozenConfig) {
35
+ frozenConfig = deepFreeze(deepClone(_config));
36
+ }
37
+ return frozenConfig;
38
+ }
39
+ function setConfig(partialConfig) {
40
+ if (typeof partialConfig.autoTrigger === "boolean") {
41
+ _config.autoTrigger = partialConfig.autoTrigger;
42
+ }
43
+ if (typeof partialConfig.triggerAttribute === "string") {
44
+ _config.triggerAttribute = partialConfig.triggerAttribute;
45
+ }
46
+ if (partialConfig.tagNames) {
47
+ Object.assign(_config.tagNames, partialConfig.tagNames);
48
+ }
49
+ frozenConfig = null;
50
+ }
51
+
52
+ /**
53
+ * Headless timer primitive. A thin, framework-agnostic wrapper around
54
+ * `setInterval` exposed through the wc-bindable protocol: it streams `tick`
55
+ * (a monotonically increasing counter), `elapsed` (running time in ms) and a
56
+ * `running` flag, and is driven by the `start` / `stop` / `reset` / `pause` /
57
+ * `resume` commands.
58
+ *
59
+ * `tick` and `elapsed` are both surfaced via the single `wcs-timer:tick` event
60
+ * (read through getters, mirroring how FetchCore exposes value/status from one
61
+ * `wcs-fetch:response` event), so an observer that binds either property is
62
+ * notified on every fire.
63
+ */
64
+ class TimerCore extends EventTarget {
65
+ static wcBindable = {
66
+ protocol: "wc-bindable",
67
+ version: 1,
68
+ properties: [
69
+ { name: "tick", event: "wcs-timer:tick", getter: (e) => e.detail.count },
70
+ { name: "elapsed", event: "wcs-timer:tick", getter: (e) => e.detail.elapsed },
71
+ { name: "running", event: "wcs-timer:running-changed" },
72
+ ],
73
+ commands: [
74
+ { name: "start" },
75
+ { name: "stop" },
76
+ { name: "reset" },
77
+ { name: "pause" },
78
+ { name: "resume" },
79
+ ],
80
+ };
81
+ _target;
82
+ _timerId = null;
83
+ _tick = 0;
84
+ _running = false;
85
+ _paused = false;
86
+ // `_tick` value captured at the start of the current run. `repeat` counts ticks
87
+ // *per run*, so the stop condition compares against this baseline rather than the
88
+ // cumulative `_tick` (which only resets on reset()). Without it, re-starting a
89
+ // completed bounded timer would stop after a single tick.
90
+ _runStartTick = 0;
91
+ // Timer configuration (captured on start, reused by pause/resume).
92
+ // `_immediate` is intentionally NOT a field: it is per-run intent consumed
93
+ // entirely within start() (fire once, then schedule), so it lives as a local
94
+ // there rather than lingering as instance state no other method reads.
95
+ _interval = 1000;
96
+ _repeat = 0; // 0 = unlimited
97
+ // Elapsed-time bookkeeping. `_accumulatedElapsed` holds the time folded from
98
+ // already-finished running segments; `_segmentStart` is the timestamp the
99
+ // current running segment began (null when not running). The live elapsed is
100
+ // the sum of the two — see _currentElapsed().
101
+ _accumulatedElapsed = 0;
102
+ _segmentStart = null;
103
+ constructor(target) {
104
+ super();
105
+ this._target = target ?? this;
106
+ }
107
+ get tick() {
108
+ return this._tick;
109
+ }
110
+ get elapsed() {
111
+ return this._currentElapsed();
112
+ }
113
+ get running() {
114
+ return this._running;
115
+ }
116
+ // --- State setters with event dispatch ---
117
+ _dispatchTick() {
118
+ this._target.dispatchEvent(new CustomEvent("wcs-timer:tick", {
119
+ detail: { count: this._tick, elapsed: this._currentElapsed() },
120
+ bubbles: true,
121
+ }));
122
+ }
123
+ _setRunning(running) {
124
+ if (this._running === running)
125
+ return;
126
+ this._running = running;
127
+ this._target.dispatchEvent(new CustomEvent("wcs-timer:running-changed", {
128
+ detail: running,
129
+ bubbles: true,
130
+ }));
131
+ }
132
+ // --- Public API ---
133
+ start(options = {}) {
134
+ // Idempotent while running: a redundant start() must not stack a second
135
+ // setInterval (which would leak and double the tick rate). Reconfiguring an
136
+ // active timer is done via stop() + start().
137
+ if (this._running)
138
+ return;
139
+ // start() begins a fresh running segment, so clear any lingering pause from a
140
+ // prior pause()-without-resume(). Without this, the timer would run while
141
+ // _paused stayed true, leaving pause() a no-op and letting resume() overwrite
142
+ // the live timer handle (leak + double fire).
143
+ this._paused = false;
144
+ // `interval` is persistent configuration: a non-positive / non-finite value
145
+ // (or an omitted option) keeps the previous interval (default 1000ms). The
146
+ // guard rejects values that would turn setInterval into a hot loop and make
147
+ // resume()'s `accumulated % interval` arithmetic produce NaN. The Shell already
148
+ // falls back to 1000 for invalid attributes; this is the backstop for direct
149
+ // Core API callers.
150
+ if (typeof options.interval === "number" && Number.isFinite(options.interval) && options.interval > 0) {
151
+ this._interval = options.interval;
152
+ }
153
+ // `repeat` / `immediate` are per-run intent, NOT persistent configuration:
154
+ // every start() re-establishes them from the options, defaulting to
155
+ // "unlimited" / "no immediate fire" when omitted. This keeps a bare start()
156
+ // after a bounded or one-shot run from silently inheriting the old bounds.
157
+ // `repeat` is a field (pause/resume/_fire read it across the run); `immediate`
158
+ // is consumed here and now, so it stays a local.
159
+ this._repeat = (typeof options.repeat === "number" && options.repeat > 0) ? options.repeat : 0;
160
+ const immediate = options.immediate === true;
161
+ this._setRunning(true);
162
+ this._segmentStart = Date.now();
163
+ // Baseline this run's per-run repeat counting (set after _setRunning so a
164
+ // re-start of a completed bounded timer fires the full N ticks again).
165
+ this._runStartTick = this._tick;
166
+ // Fire immediately on start when requested. _fire() may stop the timer (when
167
+ // repeat is reached), so re-check _running before scheduling the interval.
168
+ if (immediate) {
169
+ this._fire();
170
+ }
171
+ if (this._running) {
172
+ this._timerId = setInterval(this._fire, this._interval);
173
+ }
174
+ }
175
+ // Swap the tick period of a live timer in place, WITHOUT re-running start().
176
+ // Unlike stop() + start(), this leaves the per-run repeat progress in flight
177
+ // (`_repeat` and its `_runStartTick` baseline) untouched, so a bounded
178
+ // `repeat="N"` run is not re-baselined to fire N more times. It also never goes
179
+ // through start()'s `immediate` path, so an `immediate` timer does not fire an
180
+ // extra tick. Only re-arms the steady interval; pause()/resume() and reset() are
181
+ // unaffected. No-op when not running (interval is then plain config, captured on
182
+ // the next start) or when the new period is non-positive / non-finite (which
183
+ // would turn setInterval into a hot loop and break resume()'s modulo arithmetic).
184
+ changeInterval(interval) {
185
+ if (!this._running)
186
+ return;
187
+ if (!(typeof interval === "number" && Number.isFinite(interval) && interval > 0))
188
+ return;
189
+ if (interval === this._interval)
190
+ return;
191
+ this._interval = interval;
192
+ // Re-arm the steady ticking at the new period. The current period's progress
193
+ // is intentionally discarded (the next tick is a full new interval away),
194
+ // matching the boundary reset of the previous stop()+start() behaviour.
195
+ this._clearTimer();
196
+ this._timerId = setInterval(this._fire, this._interval);
197
+ }
198
+ stop() {
199
+ this._clearTimer();
200
+ this._foldElapsed();
201
+ this._paused = false;
202
+ this._setRunning(false);
203
+ }
204
+ reset() {
205
+ this._clearTimer();
206
+ this._paused = false;
207
+ this._tick = 0;
208
+ this._accumulatedElapsed = 0;
209
+ this._segmentStart = null;
210
+ this._setRunning(false);
211
+ // Notify observers that the counter/elapsed have returned to zero.
212
+ this._dispatchTick();
213
+ }
214
+ pause() {
215
+ // Pause only a live timer; a no-op otherwise so it composes safely with the
216
+ // declarative lifecycle. Unlike stop(), it records `_paused` so resume() can
217
+ // tell an intentional pause from a full stop.
218
+ if (!this._running || this._paused)
219
+ return;
220
+ this._clearTimer();
221
+ this._foldElapsed();
222
+ this._paused = true;
223
+ this._setRunning(false);
224
+ }
225
+ resume() {
226
+ if (!this._paused)
227
+ return;
228
+ this._paused = false;
229
+ this._setRunning(true);
230
+ this._segmentStart = Date.now();
231
+ // Invariant: `_interval` is fixed at start() and stays constant for the whole
232
+ // pause/resume cycle — changeInterval() only mutates it while *running* (never
233
+ // while paused), so the remainder arithmetic below can safely assume the same
234
+ // period was in effect across the paused segment. Consequence for the Shell:
235
+ // because the live interval-attribute path (attributeChangedCallback ->
236
+ // changeInterval) is gated on `running`, an `interval` change made *while
237
+ // paused* is silently not applied here; it is picked up only on the next
238
+ // start() as plain config. This is by design — see README "Commands".
239
+ // Resume seamlessly: a tick fires every `interval` ms of *running* time, so
240
+ // honour the partial period consumed before the pause. Wait only the
241
+ // remainder to the next boundary, then fall back to the steady interval.
242
+ // (`accumulated % interval === 0` — paused exactly on a boundary — yields a
243
+ // full interval, which is correct: the next tick is a whole period away.)
244
+ const remainder = this._interval - (this._accumulatedElapsed % this._interval);
245
+ this._timerId = setTimeout(this._onResumeBoundary, remainder);
246
+ }
247
+ // --- Internal ---
248
+ _onResumeBoundary = () => {
249
+ this._timerId = null;
250
+ this._fire();
251
+ // _fire() may have auto-stopped the timer (repeat reached); only re-arm the
252
+ // steady interval while still running.
253
+ if (this._running) {
254
+ this._timerId = setInterval(this._fire, this._interval);
255
+ }
256
+ };
257
+ _fire = () => {
258
+ this._tick++;
259
+ this._dispatchTick();
260
+ // Auto-stop once this run has fired the requested number of ticks (repeat=0
261
+ // runs forever). Counted per-run via `_runStartTick`, so a re-start after a
262
+ // completed bounded run fires N ticks again. `once` is expressed by the Shell
263
+ // as repeat=1.
264
+ if (this._repeat > 0 && (this._tick - this._runStartTick) >= this._repeat) {
265
+ this._clearTimer();
266
+ this._foldElapsed();
267
+ this._setRunning(false);
268
+ }
269
+ };
270
+ _clearTimer() {
271
+ if (this._timerId !== null) {
272
+ // `_timerId` may hold a setInterval handle (steady ticking) or a setTimeout
273
+ // handle (the resume remainder). Clear both — per the HTML spec timers
274
+ // share one list and clearTimeout/clearInterval each remove the entry
275
+ // regardless of which call created it.
276
+ clearTimeout(this._timerId);
277
+ clearInterval(this._timerId);
278
+ this._timerId = null;
279
+ }
280
+ }
281
+ _foldElapsed() {
282
+ if (this._segmentStart !== null) {
283
+ this._accumulatedElapsed += Date.now() - this._segmentStart;
284
+ this._segmentStart = null;
285
+ }
286
+ }
287
+ _currentElapsed() {
288
+ return this._accumulatedElapsed +
289
+ (this._segmentStart !== null ? Date.now() - this._segmentStart : 0);
290
+ }
291
+ }
292
+
293
+ let registered = false;
294
+ function handleClick(event) {
295
+ const target = event.target;
296
+ if (!(target instanceof Element))
297
+ return;
298
+ const triggerElement = target.closest(`[${config.triggerAttribute}]`);
299
+ if (!triggerElement)
300
+ return;
301
+ const timerId = triggerElement.getAttribute(config.triggerAttribute);
302
+ if (!timerId)
303
+ return;
304
+ // Resolve the registered constructor at call time instead of importing Timer
305
+ // as a value. The value import created a components/Timer.ts ⇄ autoTrigger.ts
306
+ // cycle (Timer.connectedCallback() calls registerAutoTrigger()). instanceof
307
+ // against the customElements registry keeps the exact same identity guarantee
308
+ // — only the registered <wcs-timer> class matches — without the import cycle.
309
+ const TimerCtor = customElements.get(config.tagNames.timer);
310
+ const timerElement = document.getElementById(timerId);
311
+ if (!TimerCtor || !(timerElement instanceof TimerCtor))
312
+ return;
313
+ // Suppress the element's default action so a timer can start without
314
+ // navigating. Intentional: do not attach data-timertarget to an element whose
315
+ // default action you also want (real <a href> link, form-submit button) — it
316
+ // will be cancelled. See README "Optional DOM Triggering".
317
+ event.preventDefault();
318
+ timerElement.start();
319
+ }
320
+ function registerAutoTrigger() {
321
+ if (registered)
322
+ return;
323
+ registered = true;
324
+ document.addEventListener("click", handleClick);
325
+ }
326
+
327
+ class Timer extends HTMLElement {
328
+ static hasConnectedCallbackPromise = false;
329
+ static wcBindable = {
330
+ ...TimerCore.wcBindable,
331
+ properties: [
332
+ ...TimerCore.wcBindable.properties,
333
+ { name: "trigger", event: "wcs-timer:trigger-changed" },
334
+ ],
335
+ // Shell-level settable surface. `attribute` is a purely descriptive hint
336
+ // (per SPEC-extensions.md the binding core does not act on it) naming the
337
+ // mirrored HTML attribute, matching <wcs-geo> / <wcs-debounce>. `trigger` is a
338
+ // momentary command-property with no backing attribute, so it carries no hint
339
+ // (same as those packages). `start` / `stop` / `reset` / `pause` / `resume`
340
+ // commands are inherited from the Core above.
341
+ inputs: [
342
+ { name: "interval", attribute: "interval" },
343
+ { name: "once", attribute: "once" },
344
+ { name: "repeat", attribute: "repeat" },
345
+ { name: "immediate", attribute: "immediate" },
346
+ { name: "manual", attribute: "manual" },
347
+ { name: "trigger" },
348
+ ],
349
+ };
350
+ static get observedAttributes() { return ["interval"]; }
351
+ _core;
352
+ _trigger = false;
353
+ constructor() {
354
+ super();
355
+ this._core = new TimerCore(this);
356
+ }
357
+ // --- Attribute accessors ---
358
+ get interval() {
359
+ const attr = this.getAttribute("interval");
360
+ if (attr === null || attr.trim() === "")
361
+ return 1000;
362
+ // Strict parse via Number() (unlike parseInt, "100px" -> NaN, not 100),
363
+ // matching <wcs-geo> / <wcs-debounce>. Fall back to the 1000ms default for any
364
+ // invalid period — not only NaN but also 0 / negative values, which would
365
+ // otherwise reach setInterval as a hot loop and break resume()'s modulo
366
+ // arithmetic in the Core.
367
+ const parsed = Number(attr);
368
+ return (Number.isFinite(parsed) && parsed > 0) ? parsed : 1000;
369
+ }
370
+ set interval(value) {
371
+ this.setAttribute("interval", String(value));
372
+ }
373
+ get once() {
374
+ return this.hasAttribute("once");
375
+ }
376
+ set once(value) {
377
+ if (value) {
378
+ this.setAttribute("once", "");
379
+ }
380
+ else {
381
+ this.removeAttribute("once");
382
+ }
383
+ }
384
+ get repeat() {
385
+ const attr = this.getAttribute("repeat");
386
+ if (attr === null || attr.trim() === "")
387
+ return 0;
388
+ // Strict parse via Number() ("3px" -> NaN, not 3), matching <wcs-geo> /
389
+ // <wcs-debounce>. Normalise any non-positive / non-numeric value to 0
390
+ // (= unlimited), mirroring the `interval` getter. Without this a negative
391
+ // `repeat="-3"` would leak through to start(); harmless today (Core treats
392
+ // `_repeat <= 0` as unlimited) but the asymmetry is a trap.
393
+ const parsed = Number(attr);
394
+ return (Number.isFinite(parsed) && parsed > 0) ? parsed : 0;
395
+ }
396
+ set repeat(value) {
397
+ this.setAttribute("repeat", String(value));
398
+ }
399
+ get immediate() {
400
+ return this.hasAttribute("immediate");
401
+ }
402
+ set immediate(value) {
403
+ if (value) {
404
+ this.setAttribute("immediate", "");
405
+ }
406
+ else {
407
+ this.removeAttribute("immediate");
408
+ }
409
+ }
410
+ get manual() {
411
+ return this.hasAttribute("manual");
412
+ }
413
+ set manual(value) {
414
+ if (value) {
415
+ this.setAttribute("manual", "");
416
+ }
417
+ else {
418
+ this.removeAttribute("manual");
419
+ }
420
+ }
421
+ // --- Core delegated getters ---
422
+ get tick() {
423
+ return this._core.tick;
424
+ }
425
+ get elapsed() {
426
+ return this._core.elapsed;
427
+ }
428
+ get running() {
429
+ return this._core.running;
430
+ }
431
+ // --- Command property ---
432
+ get trigger() {
433
+ return this._trigger;
434
+ }
435
+ set trigger(value) {
436
+ // Momentary command-property: a false→true write starts the timer. Mirrors
437
+ // the trigger flag on <wcs-fetch> / <wcs-ws>. Prefer the command-token
438
+ // protocol (`command.start: $command.tick`) for state-driven starts; this
439
+ // exists mainly for the DOM click trigger and simple boolean bindings.
440
+ const v = !!value;
441
+ if (v) {
442
+ this._trigger = true;
443
+ this.start();
444
+ this._trigger = false;
445
+ // The `trigger-changed` event reports the momentary flag returning to
446
+ // false, i.e. that the trigger property *changed* — it is deliberately not
447
+ // gated on whether start() actually began a new run. This keeps the
448
+ // wcBindable `trigger` property's change-notification semantics consistent
449
+ // (every false→true write produces exactly one change-back event), even
450
+ // when start() was a no-op because the timer was already running.
451
+ this.dispatchEvent(new CustomEvent("wcs-timer:trigger-changed", {
452
+ detail: false,
453
+ bubbles: true,
454
+ }));
455
+ }
456
+ }
457
+ // --- Commands ---
458
+ start() {
459
+ // `once` is sugar for "fire exactly one tick": map it to repeat=1, but let an
460
+ // explicit repeat attribute win when both are present.
461
+ const repeat = this.repeat > 0 ? this.repeat : (this.once ? 1 : 0);
462
+ this._core.start({
463
+ interval: this.interval,
464
+ repeat,
465
+ immediate: this.immediate,
466
+ });
467
+ }
468
+ stop() {
469
+ this._core.stop();
470
+ }
471
+ reset() {
472
+ this._core.reset();
473
+ }
474
+ pause() {
475
+ this._core.pause();
476
+ }
477
+ resume() {
478
+ this._core.resume();
479
+ }
480
+ // --- Lifecycle ---
481
+ attributeChangedCallback(name, oldValue, newValue) {
482
+ // Live interval changes swap the underlying setInterval period in place.
483
+ // `tick` / `elapsed` and the per-run `repeat` progress are preserved — we
484
+ // deliberately do NOT stop()+start(), which would re-run start() and
485
+ // re-evaluate per-run options (re-firing `immediate` and re-baselining
486
+ // `repeat`). `running` alone gates this: swapping the period is orthogonal to
487
+ // *how* the timer was started, so a `manual` timer the user has explicitly
488
+ // started gets live period changes too. A non-running timer needs no swap —
489
+ // its next start() picks up the new attribute as plain config.
490
+ if (name === "interval" && oldValue !== newValue && this.isConnected && this.running) {
491
+ this._core.changeInterval(this.interval);
492
+ }
493
+ }
494
+ connectedCallback() {
495
+ this.style.display = "none";
496
+ if (config.autoTrigger) {
497
+ registerAutoTrigger();
498
+ }
499
+ if (!this.manual) {
500
+ this.start();
501
+ }
502
+ }
503
+ disconnectedCallback() {
504
+ this._core.stop();
505
+ }
506
+ }
507
+
508
+ function registerComponents() {
509
+ if (!customElements.get(config.tagNames.timer)) {
510
+ customElements.define(config.tagNames.timer, Timer);
511
+ }
512
+ }
513
+
514
+ function bootstrapTimer(userConfig) {
515
+ if (userConfig) {
516
+ setConfig(userConfig);
517
+ }
518
+ registerComponents();
519
+ }
520
+
521
+ export { TimerCore, Timer as WcsTimer, bootstrapTimer, getConfig };
522
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../src/config.ts","../src/core/TimerCore.ts","../src/autoTrigger.ts","../src/components/Timer.ts","../src/registerComponents.ts","../src/bootstrapTimer.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n autoTrigger: boolean;\n triggerAttribute: string;\n tagNames: {\n timer: string;\n };\n}\n\nconst _config: IInternalConfig = {\n autoTrigger: true,\n triggerAttribute: \"data-timertarget\",\n tagNames: {\n timer: \"wcs-timer\",\n },\n};\n\nfunction deepFreeze<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n Object.freeze(obj);\n for (const key of Object.keys(obj)) {\n deepFreeze((obj as Record<string, unknown>)[key]);\n }\n return obj;\n}\n\nfunction deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n const clone: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n clone[key] = deepClone((obj as Record<string, unknown>)[key]);\n }\n return clone as T;\n}\n\nlet frozenConfig: IConfig | null = null;\n\n// Internal-only live handle to the mutable config. NOT part of the public API\n// (deliberately absent from exports.ts) — it is exported solely so sibling\n// modules in this package can read current settings cheaply. External consumers\n// must use getConfig() (returns a deep-frozen snapshot) / setConfig(). Mutating\n// this object directly bypasses the frozenConfig cache and is unsupported.\nexport const config: IConfig = _config as IConfig;\n\nexport function getConfig(): IConfig {\n if (!frozenConfig) {\n frozenConfig = deepFreeze(deepClone(_config));\n }\n return frozenConfig;\n}\n\nexport function setConfig(partialConfig: IWritableConfig): void {\n if (typeof partialConfig.autoTrigger === \"boolean\") {\n _config.autoTrigger = partialConfig.autoTrigger;\n }\n if (typeof partialConfig.triggerAttribute === \"string\") {\n _config.triggerAttribute = partialConfig.triggerAttribute;\n }\n if (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n frozenConfig = null;\n}\n","import { IWcBindable } from \"../types.js\";\n\nexport interface TimerStartOptions {\n interval?: number;\n repeat?: number;\n immediate?: boolean;\n}\n\n/**\n * Headless timer primitive. A thin, framework-agnostic wrapper around\n * `setInterval` exposed through the wc-bindable protocol: it streams `tick`\n * (a monotonically increasing counter), `elapsed` (running time in ms) and a\n * `running` flag, and is driven by the `start` / `stop` / `reset` / `pause` /\n * `resume` commands.\n *\n * `tick` and `elapsed` are both surfaced via the single `wcs-timer:tick` event\n * (read through getters, mirroring how FetchCore exposes value/status from one\n * `wcs-fetch:response` event), so an observer that binds either property is\n * notified on every fire.\n */\nexport class TimerCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"tick\", event: \"wcs-timer:tick\", getter: (e: Event) => (e as CustomEvent).detail.count },\n { name: \"elapsed\", event: \"wcs-timer:tick\", getter: (e: Event) => (e as CustomEvent).detail.elapsed },\n { name: \"running\", event: \"wcs-timer:running-changed\" },\n ],\n commands: [\n { name: \"start\" },\n { name: \"stop\" },\n { name: \"reset\" },\n { name: \"pause\" },\n { name: \"resume\" },\n ],\n };\n\n private _target: EventTarget;\n private _timerId: ReturnType<typeof setInterval> | null = null;\n\n private _tick: number = 0;\n private _running: boolean = false;\n private _paused: boolean = false;\n\n // `_tick` value captured at the start of the current run. `repeat` counts ticks\n // *per run*, so the stop condition compares against this baseline rather than the\n // cumulative `_tick` (which only resets on reset()). Without it, re-starting a\n // completed bounded timer would stop after a single tick.\n private _runStartTick: number = 0;\n\n // Timer configuration (captured on start, reused by pause/resume).\n // `_immediate` is intentionally NOT a field: it is per-run intent consumed\n // entirely within start() (fire once, then schedule), so it lives as a local\n // there rather than lingering as instance state no other method reads.\n private _interval: number = 1000;\n private _repeat: number = 0; // 0 = unlimited\n\n // Elapsed-time bookkeeping. `_accumulatedElapsed` holds the time folded from\n // already-finished running segments; `_segmentStart` is the timestamp the\n // current running segment began (null when not running). The live elapsed is\n // the sum of the two — see _currentElapsed().\n private _accumulatedElapsed: number = 0;\n private _segmentStart: number | null = null;\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get tick(): number {\n return this._tick;\n }\n\n get elapsed(): number {\n return this._currentElapsed();\n }\n\n get running(): boolean {\n return this._running;\n }\n\n // --- State setters with event dispatch ---\n\n private _dispatchTick(): void {\n this._target.dispatchEvent(new CustomEvent(\"wcs-timer:tick\", {\n detail: { count: this._tick, elapsed: this._currentElapsed() },\n bubbles: true,\n }));\n }\n\n private _setRunning(running: boolean): void {\n if (this._running === running) return;\n this._running = running;\n this._target.dispatchEvent(new CustomEvent(\"wcs-timer:running-changed\", {\n detail: running,\n bubbles: true,\n }));\n }\n\n // --- Public API ---\n\n start(options: TimerStartOptions = {}): void {\n // Idempotent while running: a redundant start() must not stack a second\n // setInterval (which would leak and double the tick rate). Reconfiguring an\n // active timer is done via stop() + start().\n if (this._running) return;\n\n // start() begins a fresh running segment, so clear any lingering pause from a\n // prior pause()-without-resume(). Without this, the timer would run while\n // _paused stayed true, leaving pause() a no-op and letting resume() overwrite\n // the live timer handle (leak + double fire).\n this._paused = false;\n\n // `interval` is persistent configuration: a non-positive / non-finite value\n // (or an omitted option) keeps the previous interval (default 1000ms). The\n // guard rejects values that would turn setInterval into a hot loop and make\n // resume()'s `accumulated % interval` arithmetic produce NaN. The Shell already\n // falls back to 1000 for invalid attributes; this is the backstop for direct\n // Core API callers.\n if (typeof options.interval === \"number\" && Number.isFinite(options.interval) && options.interval > 0) {\n this._interval = options.interval;\n }\n\n // `repeat` / `immediate` are per-run intent, NOT persistent configuration:\n // every start() re-establishes them from the options, defaulting to\n // \"unlimited\" / \"no immediate fire\" when omitted. This keeps a bare start()\n // after a bounded or one-shot run from silently inheriting the old bounds.\n // `repeat` is a field (pause/resume/_fire read it across the run); `immediate`\n // is consumed here and now, so it stays a local.\n this._repeat = (typeof options.repeat === \"number\" && options.repeat > 0) ? options.repeat : 0;\n const immediate = options.immediate === true;\n\n this._setRunning(true);\n this._segmentStart = Date.now();\n // Baseline this run's per-run repeat counting (set after _setRunning so a\n // re-start of a completed bounded timer fires the full N ticks again).\n this._runStartTick = this._tick;\n\n // Fire immediately on start when requested. _fire() may stop the timer (when\n // repeat is reached), so re-check _running before scheduling the interval.\n if (immediate) {\n this._fire();\n }\n if (this._running) {\n this._timerId = setInterval(this._fire, this._interval);\n }\n }\n\n // Swap the tick period of a live timer in place, WITHOUT re-running start().\n // Unlike stop() + start(), this leaves the per-run repeat progress in flight\n // (`_repeat` and its `_runStartTick` baseline) untouched, so a bounded\n // `repeat=\"N\"` run is not re-baselined to fire N more times. It also never goes\n // through start()'s `immediate` path, so an `immediate` timer does not fire an\n // extra tick. Only re-arms the steady interval; pause()/resume() and reset() are\n // unaffected. No-op when not running (interval is then plain config, captured on\n // the next start) or when the new period is non-positive / non-finite (which\n // would turn setInterval into a hot loop and break resume()'s modulo arithmetic).\n changeInterval(interval: number): void {\n if (!this._running) return;\n if (!(typeof interval === \"number\" && Number.isFinite(interval) && interval > 0)) return;\n if (interval === this._interval) return;\n this._interval = interval;\n // Re-arm the steady ticking at the new period. The current period's progress\n // is intentionally discarded (the next tick is a full new interval away),\n // matching the boundary reset of the previous stop()+start() behaviour.\n this._clearTimer();\n this._timerId = setInterval(this._fire, this._interval);\n }\n\n stop(): void {\n this._clearTimer();\n this._foldElapsed();\n this._paused = false;\n this._setRunning(false);\n }\n\n reset(): void {\n this._clearTimer();\n this._paused = false;\n this._tick = 0;\n this._accumulatedElapsed = 0;\n this._segmentStart = null;\n this._setRunning(false);\n // Notify observers that the counter/elapsed have returned to zero.\n this._dispatchTick();\n }\n\n pause(): void {\n // Pause only a live timer; a no-op otherwise so it composes safely with the\n // declarative lifecycle. Unlike stop(), it records `_paused` so resume() can\n // tell an intentional pause from a full stop.\n if (!this._running || this._paused) return;\n this._clearTimer();\n this._foldElapsed();\n this._paused = true;\n this._setRunning(false);\n }\n\n resume(): void {\n if (!this._paused) return;\n this._paused = false;\n this._setRunning(true);\n this._segmentStart = Date.now();\n // Invariant: `_interval` is fixed at start() and stays constant for the whole\n // pause/resume cycle — changeInterval() only mutates it while *running* (never\n // while paused), so the remainder arithmetic below can safely assume the same\n // period was in effect across the paused segment. Consequence for the Shell:\n // because the live interval-attribute path (attributeChangedCallback ->\n // changeInterval) is gated on `running`, an `interval` change made *while\n // paused* is silently not applied here; it is picked up only on the next\n // start() as plain config. This is by design — see README \"Commands\".\n // Resume seamlessly: a tick fires every `interval` ms of *running* time, so\n // honour the partial period consumed before the pause. Wait only the\n // remainder to the next boundary, then fall back to the steady interval.\n // (`accumulated % interval === 0` — paused exactly on a boundary — yields a\n // full interval, which is correct: the next tick is a whole period away.)\n const remainder = this._interval - (this._accumulatedElapsed % this._interval);\n this._timerId = setTimeout(this._onResumeBoundary, remainder);\n }\n\n // --- Internal ---\n\n private _onResumeBoundary = (): void => {\n this._timerId = null;\n this._fire();\n // _fire() may have auto-stopped the timer (repeat reached); only re-arm the\n // steady interval while still running.\n if (this._running) {\n this._timerId = setInterval(this._fire, this._interval);\n }\n };\n\n private _fire = (): void => {\n this._tick++;\n this._dispatchTick();\n\n // Auto-stop once this run has fired the requested number of ticks (repeat=0\n // runs forever). Counted per-run via `_runStartTick`, so a re-start after a\n // completed bounded run fires N ticks again. `once` is expressed by the Shell\n // as repeat=1.\n if (this._repeat > 0 && (this._tick - this._runStartTick) >= this._repeat) {\n this._clearTimer();\n this._foldElapsed();\n this._setRunning(false);\n }\n };\n\n private _clearTimer(): void {\n if (this._timerId !== null) {\n // `_timerId` may hold a setInterval handle (steady ticking) or a setTimeout\n // handle (the resume remainder). Clear both — per the HTML spec timers\n // share one list and clearTimeout/clearInterval each remove the entry\n // regardless of which call created it.\n clearTimeout(this._timerId);\n clearInterval(this._timerId);\n this._timerId = null;\n }\n }\n\n private _foldElapsed(): void {\n if (this._segmentStart !== null) {\n this._accumulatedElapsed += Date.now() - this._segmentStart;\n this._segmentStart = null;\n }\n }\n\n private _currentElapsed(): number {\n return this._accumulatedElapsed +\n (this._segmentStart !== null ? Date.now() - this._segmentStart : 0);\n }\n}\n","import { config } from \"./config.js\";\nimport type { Timer } from \"./components/Timer.js\";\n\nlet registered = false;\n\nfunction handleClick(event: Event): void {\n const target = event.target;\n if (!(target instanceof Element)) return;\n\n const triggerElement = target.closest<Element>(`[${config.triggerAttribute}]`);\n if (!triggerElement) return;\n\n const timerId = triggerElement.getAttribute(config.triggerAttribute);\n if (!timerId) return;\n\n // Resolve the registered constructor at call time instead of importing Timer\n // as a value. The value import created a components/Timer.ts ⇄ autoTrigger.ts\n // cycle (Timer.connectedCallback() calls registerAutoTrigger()). instanceof\n // against the customElements registry keeps the exact same identity guarantee\n // — only the registered <wcs-timer> class matches — without the import cycle.\n const TimerCtor = customElements.get(config.tagNames.timer);\n const timerElement = document.getElementById(timerId);\n if (!TimerCtor || !(timerElement instanceof TimerCtor)) return;\n\n // Suppress the element's default action so a timer can start without\n // navigating. Intentional: do not attach data-timertarget to an element whose\n // default action you also want (real <a href> link, form-submit button) — it\n // will be cancelled. See README \"Optional DOM Triggering\".\n event.preventDefault();\n (timerElement as Timer).start();\n}\n\nexport function registerAutoTrigger(): void {\n if (registered) return;\n registered = true;\n document.addEventListener(\"click\", handleClick);\n}\n\nexport function unregisterAutoTrigger(): void {\n if (!registered) return;\n registered = false;\n document.removeEventListener(\"click\", handleClick);\n}\n","import { config } from \"../config.js\";\nimport { IWcBindable } from \"../types.js\";\nimport { TimerCore } from \"../core/TimerCore.js\";\nimport { registerAutoTrigger } from \"../autoTrigger.js\";\n\nexport class Timer extends HTMLElement {\n static hasConnectedCallbackPromise = false;\n static wcBindable: IWcBindable = {\n ...TimerCore.wcBindable,\n properties: [\n ...TimerCore.wcBindable.properties,\n { name: \"trigger\", event: \"wcs-timer:trigger-changed\" },\n ],\n // Shell-level settable surface. `attribute` is a purely descriptive hint\n // (per SPEC-extensions.md the binding core does not act on it) naming the\n // mirrored HTML attribute, matching <wcs-geo> / <wcs-debounce>. `trigger` is a\n // momentary command-property with no backing attribute, so it carries no hint\n // (same as those packages). `start` / `stop` / `reset` / `pause` / `resume`\n // commands are inherited from the Core above.\n inputs: [\n { name: \"interval\", attribute: \"interval\" },\n { name: \"once\", attribute: \"once\" },\n { name: \"repeat\", attribute: \"repeat\" },\n { name: \"immediate\", attribute: \"immediate\" },\n { name: \"manual\", attribute: \"manual\" },\n { name: \"trigger\" },\n ],\n };\n static get observedAttributes(): string[] { return [\"interval\"]; }\n\n private _core: TimerCore;\n private _trigger: boolean = false;\n\n constructor() {\n super();\n this._core = new TimerCore(this);\n }\n\n // --- Attribute accessors ---\n\n get interval(): number {\n const attr = this.getAttribute(\"interval\");\n if (attr === null || attr.trim() === \"\") return 1000;\n // Strict parse via Number() (unlike parseInt, \"100px\" -> NaN, not 100),\n // matching <wcs-geo> / <wcs-debounce>. Fall back to the 1000ms default for any\n // invalid period — not only NaN but also 0 / negative values, which would\n // otherwise reach setInterval as a hot loop and break resume()'s modulo\n // arithmetic in the Core.\n const parsed = Number(attr);\n return (Number.isFinite(parsed) && parsed > 0) ? parsed : 1000;\n }\n\n set interval(value: number) {\n this.setAttribute(\"interval\", String(value));\n }\n\n get once(): boolean {\n return this.hasAttribute(\"once\");\n }\n\n set once(value: boolean) {\n if (value) {\n this.setAttribute(\"once\", \"\");\n } else {\n this.removeAttribute(\"once\");\n }\n }\n\n get repeat(): number {\n const attr = this.getAttribute(\"repeat\");\n if (attr === null || attr.trim() === \"\") return 0;\n // Strict parse via Number() (\"3px\" -> NaN, not 3), matching <wcs-geo> /\n // <wcs-debounce>. Normalise any non-positive / non-numeric value to 0\n // (= unlimited), mirroring the `interval` getter. Without this a negative\n // `repeat=\"-3\"` would leak through to start(); harmless today (Core treats\n // `_repeat <= 0` as unlimited) but the asymmetry is a trap.\n const parsed = Number(attr);\n return (Number.isFinite(parsed) && parsed > 0) ? parsed : 0;\n }\n\n set repeat(value: number) {\n this.setAttribute(\"repeat\", String(value));\n }\n\n get immediate(): boolean {\n return this.hasAttribute(\"immediate\");\n }\n\n set immediate(value: boolean) {\n if (value) {\n this.setAttribute(\"immediate\", \"\");\n } else {\n this.removeAttribute(\"immediate\");\n }\n }\n\n get manual(): boolean {\n return this.hasAttribute(\"manual\");\n }\n\n set manual(value: boolean) {\n if (value) {\n this.setAttribute(\"manual\", \"\");\n } else {\n this.removeAttribute(\"manual\");\n }\n }\n\n // --- Core delegated getters ---\n\n get tick(): number {\n return this._core.tick;\n }\n\n get elapsed(): number {\n return this._core.elapsed;\n }\n\n get running(): boolean {\n return this._core.running;\n }\n\n // --- Command property ---\n\n get trigger(): boolean {\n return this._trigger;\n }\n\n set trigger(value: boolean) {\n // Momentary command-property: a false→true write starts the timer. Mirrors\n // the trigger flag on <wcs-fetch> / <wcs-ws>. Prefer the command-token\n // protocol (`command.start: $command.tick`) for state-driven starts; this\n // exists mainly for the DOM click trigger and simple boolean bindings.\n const v = !!value;\n if (v) {\n this._trigger = true;\n this.start();\n this._trigger = false;\n // The `trigger-changed` event reports the momentary flag returning to\n // false, i.e. that the trigger property *changed* — it is deliberately not\n // gated on whether start() actually began a new run. This keeps the\n // wcBindable `trigger` property's change-notification semantics consistent\n // (every false→true write produces exactly one change-back event), even\n // when start() was a no-op because the timer was already running.\n this.dispatchEvent(new CustomEvent(\"wcs-timer:trigger-changed\", {\n detail: false,\n bubbles: true,\n }));\n }\n }\n\n // --- Commands ---\n\n start(): void {\n // `once` is sugar for \"fire exactly one tick\": map it to repeat=1, but let an\n // explicit repeat attribute win when both are present.\n const repeat = this.repeat > 0 ? this.repeat : (this.once ? 1 : 0);\n this._core.start({\n interval: this.interval,\n repeat,\n immediate: this.immediate,\n });\n }\n\n stop(): void {\n this._core.stop();\n }\n\n reset(): void {\n this._core.reset();\n }\n\n pause(): void {\n this._core.pause();\n }\n\n resume(): void {\n this._core.resume();\n }\n\n // --- Lifecycle ---\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n // Live interval changes swap the underlying setInterval period in place.\n // `tick` / `elapsed` and the per-run `repeat` progress are preserved — we\n // deliberately do NOT stop()+start(), which would re-run start() and\n // re-evaluate per-run options (re-firing `immediate` and re-baselining\n // `repeat`). `running` alone gates this: swapping the period is orthogonal to\n // *how* the timer was started, so a `manual` timer the user has explicitly\n // started gets live period changes too. A non-running timer needs no swap —\n // its next start() picks up the new attribute as plain config.\n if (name === \"interval\" && oldValue !== newValue && this.isConnected && this.running) {\n this._core.changeInterval(this.interval);\n }\n }\n\n connectedCallback(): void {\n this.style.display = \"none\";\n if (config.autoTrigger) {\n registerAutoTrigger();\n }\n if (!this.manual) {\n this.start();\n }\n }\n\n disconnectedCallback(): void {\n this._core.stop();\n }\n}\n","import { Timer } from \"./components/Timer.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.timer)) {\n customElements.define(config.tagNames.timer, Timer);\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapTimer(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const t={autoTrigger:!0,triggerAttribute:"data-timertarget",tagNames:{timer:"wcs-timer"}};function e(t){if(null===t||"object"!=typeof t)return t;Object.freeze(t);for(const i of Object.keys(t))e(t[i]);return t}function i(t){if(null===t||"object"!=typeof t)return t;const e={};for(const r of Object.keys(t))e[r]=i(t[r]);return e}let r=null;const s=t;function n(){return r||(r=e(i(t))),r}class a extends EventTarget{static wcBindable={protocol:"wc-bindable",version:1,properties:[{name:"tick",event:"wcs-timer:tick",getter:t=>t.detail.count},{name:"elapsed",event:"wcs-timer:tick",getter:t=>t.detail.elapsed},{name:"running",event:"wcs-timer:running-changed"}],commands:[{name:"start"},{name:"stop"},{name:"reset"},{name:"pause"},{name:"resume"}]};_target;_timerId=null;_tick=0;_running=!1;_paused=!1;_runStartTick=0;_interval=1e3;_repeat=0;_accumulatedElapsed=0;_segmentStart=null;constructor(t){super(),this._target=t??this}get tick(){return this._tick}get elapsed(){return this._currentElapsed()}get running(){return this._running}_dispatchTick(){this._target.dispatchEvent(new CustomEvent("wcs-timer:tick",{detail:{count:this._tick,elapsed:this._currentElapsed()},bubbles:!0}))}_setRunning(t){this._running!==t&&(this._running=t,this._target.dispatchEvent(new CustomEvent("wcs-timer:running-changed",{detail:t,bubbles:!0})))}start(t={}){if(this._running)return;this._paused=!1,"number"==typeof t.interval&&Number.isFinite(t.interval)&&t.interval>0&&(this._interval=t.interval),this._repeat="number"==typeof t.repeat&&t.repeat>0?t.repeat:0;const e=!0===t.immediate;this._setRunning(!0),this._segmentStart=Date.now(),this._runStartTick=this._tick,e&&this._fire(),this._running&&(this._timerId=setInterval(this._fire,this._interval))}changeInterval(t){this._running&&"number"==typeof t&&Number.isFinite(t)&&t>0&&t!==this._interval&&(this._interval=t,this._clearTimer(),this._timerId=setInterval(this._fire,this._interval))}stop(){this._clearTimer(),this._foldElapsed(),this._paused=!1,this._setRunning(!1)}reset(){this._clearTimer(),this._paused=!1,this._tick=0,this._accumulatedElapsed=0,this._segmentStart=null,this._setRunning(!1),this._dispatchTick()}pause(){this._running&&!this._paused&&(this._clearTimer(),this._foldElapsed(),this._paused=!0,this._setRunning(!1))}resume(){if(!this._paused)return;this._paused=!1,this._setRunning(!0),this._segmentStart=Date.now();const t=this._interval-this._accumulatedElapsed%this._interval;this._timerId=setTimeout(this._onResumeBoundary,t)}_onResumeBoundary=()=>{this._timerId=null,this._fire(),this._running&&(this._timerId=setInterval(this._fire,this._interval))};_fire=()=>{this._tick++,this._dispatchTick(),this._repeat>0&&this._tick-this._runStartTick>=this._repeat&&(this._clearTimer(),this._foldElapsed(),this._setRunning(!1))};_clearTimer(){null!==this._timerId&&(clearTimeout(this._timerId),clearInterval(this._timerId),this._timerId=null)}_foldElapsed(){null!==this._segmentStart&&(this._accumulatedElapsed+=Date.now()-this._segmentStart,this._segmentStart=null)}_currentElapsed(){return this._accumulatedElapsed+(null!==this._segmentStart?Date.now()-this._segmentStart:0)}}let u=!1;function c(t){const e=t.target;if(!(e instanceof Element))return;const i=e.closest(`[${s.triggerAttribute}]`);if(!i)return;const r=i.getAttribute(s.triggerAttribute);if(!r)return;const n=customElements.get(s.tagNames.timer),a=document.getElementById(r);n&&a instanceof n&&(t.preventDefault(),a.start())}class h extends HTMLElement{static hasConnectedCallbackPromise=!1;static wcBindable={...a.wcBindable,properties:[...a.wcBindable.properties,{name:"trigger",event:"wcs-timer:trigger-changed"}],inputs:[{name:"interval",attribute:"interval"},{name:"once",attribute:"once"},{name:"repeat",attribute:"repeat"},{name:"immediate",attribute:"immediate"},{name:"manual",attribute:"manual"},{name:"trigger"}]};static get observedAttributes(){return["interval"]}_core;_trigger=!1;constructor(){super(),this._core=new a(this)}get interval(){const t=this.getAttribute("interval");if(null===t||""===t.trim())return 1e3;const e=Number(t);return Number.isFinite(e)&&e>0?e:1e3}set interval(t){this.setAttribute("interval",String(t))}get once(){return this.hasAttribute("once")}set once(t){t?this.setAttribute("once",""):this.removeAttribute("once")}get repeat(){const t=this.getAttribute("repeat");if(null===t||""===t.trim())return 0;const e=Number(t);return Number.isFinite(e)&&e>0?e:0}set repeat(t){this.setAttribute("repeat",String(t))}get immediate(){return this.hasAttribute("immediate")}set immediate(t){t?this.setAttribute("immediate",""):this.removeAttribute("immediate")}get manual(){return this.hasAttribute("manual")}set manual(t){t?this.setAttribute("manual",""):this.removeAttribute("manual")}get tick(){return this._core.tick}get elapsed(){return this._core.elapsed}get running(){return this._core.running}get trigger(){return this._trigger}set trigger(t){!!t&&(this._trigger=!0,this.start(),this._trigger=!1,this.dispatchEvent(new CustomEvent("wcs-timer:trigger-changed",{detail:!1,bubbles:!0})))}start(){const t=this.repeat>0?this.repeat:this.once?1:0;this._core.start({interval:this.interval,repeat:t,immediate:this.immediate})}stop(){this._core.stop()}reset(){this._core.reset()}pause(){this._core.pause()}resume(){this._core.resume()}attributeChangedCallback(t,e,i){"interval"===t&&e!==i&&this.isConnected&&this.running&&this._core.changeInterval(this.interval)}connectedCallback(){this.style.display="none",s.autoTrigger&&(u||(u=!0,document.addEventListener("click",c))),this.manual||this.start()}disconnectedCallback(){this._core.stop()}}function l(e){var i;e&&("boolean"==typeof(i=e).autoTrigger&&(t.autoTrigger=i.autoTrigger),"string"==typeof i.triggerAttribute&&(t.triggerAttribute=i.triggerAttribute),i.tagNames&&Object.assign(t.tagNames,i.tagNames),r=null),customElements.get(s.tagNames.timer)||customElements.define(s.tagNames.timer,h)}export{a as TimerCore,h as WcsTimer,l as bootstrapTimer,n as getConfig};
2
+ //# sourceMappingURL=index.esm.min.js.map