@livetemplate/client 0.11.3 → 0.11.5

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.
@@ -3,15 +3,37 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LoadingIndicator = void 0;
4
4
  /**
5
5
  * Handles showing and hiding the global LiveTemplate loading indicator.
6
+ *
7
+ * Two activation paths share the same physical bar:
8
+ *
9
+ * 1. Initial connect — `data-lvt-loading="true"` on the wrapper triggers
10
+ * `show()` in autoInit; `hide()` fires from the first server payload.
11
+ * 2. Per-action wait — `data-lvt-loading-debounce-ms="<ms>"` on the wrapper
12
+ * enables `enablePerActionIndicator(ms)`, which arms a timer on
13
+ * `lvt:pending` (capture-phase) and hides on `lvt:updated`. Idempotent.
6
14
  */
7
15
  class LoadingIndicator {
8
16
  constructor() {
9
17
  this.bar = null;
18
+ this.actionTimer = null;
19
+ // Counts in-flight actions so concurrent server roundtrips don't hide
20
+ // the bar prematurely: the bar stays visible as long as at least one
21
+ // `lvt:pending` is outstanding. Without this counter, action B
22
+ // completing first would clear the bar even though action A is still
23
+ // in flight.
24
+ this.pendingCount = 0;
25
+ this.pendingHandler = null;
26
+ this.updatedHandler = null;
27
+ // Current per-action debounce — tracked so a follow-up enable call
28
+ // with a different value reconfigures cleanly instead of silently
29
+ // dropping the new value.
30
+ this.currentDebounceMs = null;
10
31
  }
11
32
  show() {
12
33
  if (this.bar)
13
34
  return;
14
35
  const bar = document.createElement("div");
36
+ bar.className = "lvt-loading-bar";
15
37
  bar.style.cssText = `
16
38
  position: fixed;
17
39
  top: 0;
@@ -45,6 +67,91 @@ class LoadingIndicator {
45
67
  }
46
68
  this.bar = null;
47
69
  }
70
+ /**
71
+ * Show the loading bar after `debounceMs` of an action being in flight;
72
+ * hide on the next `lvt:updated`. Capture-phase listeners on document
73
+ * catch both events regardless of dispatch target. Safe to call more
74
+ * than once — repeat calls are no-ops.
75
+ */
76
+ enablePerActionIndicator(debounceMs) {
77
+ // Same value as already enabled → no-op (idempotent).
78
+ // Different value → tear down and re-register cleanly. This
79
+ // matters for callers that re-read the debounce attribute after
80
+ // a config change; without it, the second call would silently
81
+ // discard the new value.
82
+ if (this.pendingHandler) {
83
+ if (this.currentDebounceMs === debounceMs)
84
+ return;
85
+ this.disablePerActionIndicator();
86
+ }
87
+ this.pendingCount = 0;
88
+ this.currentDebounceMs = debounceMs;
89
+ this.pendingHandler = () => {
90
+ this.pendingCount++;
91
+ // Only arm a debounce timer on the 0→1 transition. Subsequent
92
+ // concurrent actions don't reset the timer or re-show the bar —
93
+ // the bar that is or will become visible already represents "at
94
+ // least one action in flight".
95
+ if (this.pendingCount === 1 &&
96
+ this.actionTimer === null &&
97
+ this.bar === null) {
98
+ this.actionTimer = setTimeout(() => {
99
+ this.actionTimer = null;
100
+ // Re-check pendingCount at fire time. In single-threaded JS
101
+ // `updatedHandler` would have called `clearTimeout` before the
102
+ // count could reach zero, so this guard is defensive: it
103
+ // documents the invariant and protects against any future
104
+ // reordering of teardown vs. show.
105
+ if (this.pendingCount > 0)
106
+ this.show();
107
+ }, debounceMs);
108
+ }
109
+ };
110
+ this.updatedHandler = () => {
111
+ // Math.max guards against an `lvt:updated` arriving without a
112
+ // matching `lvt:pending` (e.g. a server push, or an action whose
113
+ // pending event was dispatched before the listener was attached).
114
+ this.pendingCount = Math.max(0, this.pendingCount - 1);
115
+ if (this.pendingCount === 0) {
116
+ if (this.actionTimer !== null) {
117
+ clearTimeout(this.actionTimer);
118
+ this.actionTimer = null;
119
+ }
120
+ this.hide();
121
+ }
122
+ };
123
+ document.addEventListener("lvt:pending", this.pendingHandler, true);
124
+ document.addEventListener("lvt:updated", this.updatedHandler, true);
125
+ }
126
+ /**
127
+ * Teardown for `enablePerActionIndicator`. Stops the listeners, cancels
128
+ * any pending debounce timer, resets the counter, and hides the bar
129
+ * if it's currently visible. Hiding is part of teardown so a caller
130
+ * that reconfigures (different debounce → disable + re-enable) doesn't
131
+ * leave the prior cycle's bar orphaned waiting for an `lvt:updated`
132
+ * that no listener will receive.
133
+ *
134
+ * Production callers reach this path via two routes: an explicit
135
+ * reconfigure inside `enablePerActionIndicator`, and the LiveTemplate
136
+ * client's `disconnect()` teardown.
137
+ */
138
+ disablePerActionIndicator() {
139
+ if (this.pendingHandler) {
140
+ document.removeEventListener("lvt:pending", this.pendingHandler, true);
141
+ this.pendingHandler = null;
142
+ }
143
+ if (this.updatedHandler) {
144
+ document.removeEventListener("lvt:updated", this.updatedHandler, true);
145
+ this.updatedHandler = null;
146
+ }
147
+ if (this.actionTimer !== null) {
148
+ clearTimeout(this.actionTimer);
149
+ this.actionTimer = null;
150
+ }
151
+ this.pendingCount = 0;
152
+ this.currentDebounceMs = null;
153
+ this.hide();
154
+ }
48
155
  }
49
156
  exports.LoadingIndicator = LoadingIndicator;
50
157
  //# sourceMappingURL=loading-indicator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"loading-indicator.js","sourceRoot":"","sources":["../../dom/loading-indicator.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,MAAa,gBAAgB;IAA7B;QACU,QAAG,GAAuB,IAAI,CAAC;IA0CzC,CAAC;IAxCC,IAAI;QACF,IAAI,IAAI,CAAC,GAAG;YAAE,OAAO;QAErB,MAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC1C,GAAG,CAAC,KAAK,CAAC,OAAO,GAAG;;;;;;;;;;KAUnB,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,oBAAoB,CAAC,EAAE,CAAC;YACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YAC9C,KAAK,CAAC,EAAE,GAAG,oBAAoB,CAAC;YAChC,KAAK,CAAC,WAAW,GAAG;;;;;OAKnB,CAAC;YACF,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1D,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAED,IAAI;QACF,IAAI,CAAC,IAAI,CAAC,GAAG;YAAE,OAAO;QAEtB,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;YACxB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5C,CAAC;QACD,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;IAClB,CAAC;CACF;AA3CD,4CA2CC"}
1
+ {"version":3,"file":"loading-indicator.js","sourceRoot":"","sources":["../../dom/loading-indicator.ts"],"names":[],"mappings":"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"}