stimeo-ui 0.16.0 → 0.18.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.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +136 -0
  3. data/README.md +27 -11
  4. data/dist/cable/index.js +384 -449
  5. data/dist/controllers/accordion_controller.js +174 -55
  6. data/dist/controllers/alert_dialog_controller.js +903 -235
  7. data/dist/controllers/announcer_controller.js +238 -205
  8. data/dist/controllers/aspect_ratio_controller.js +0 -10
  9. data/dist/controllers/auto_submit_controller.js +414 -145
  10. data/dist/controllers/avatar_controller.js +185 -107
  11. data/dist/controllers/breadcrumb_controller.js +0 -130
  12. data/dist/controllers/bulk_select_controller.js +282 -58
  13. data/dist/controllers/calendar_controller.js +228 -260
  14. data/dist/controllers/carousel_controller.js +536 -436
  15. data/dist/controllers/character_counter_controller.js +493 -207
  16. data/dist/controllers/checkbox_controller.js +38 -74
  17. data/dist/controllers/clipboard_controller.js +261 -149
  18. data/dist/controllers/collapsible_controller.js +304 -120
  19. data/dist/controllers/color_picker_controller.js +178 -146
  20. data/dist/controllers/combobox_controller.js +522 -156
  21. data/dist/controllers/command_palette_controller.js +1156 -395
  22. data/dist/controllers/conditional_fields_controller.js +300 -171
  23. data/dist/controllers/confirm_controller.js +980 -262
  24. data/dist/controllers/context_menu_controller.js +346 -153
  25. data/dist/controllers/count_up_controller.js +73 -21
  26. data/dist/controllers/countdown_controller.js +281 -158
  27. data/dist/controllers/currency_input_controller.js +575 -225
  28. data/dist/controllers/data_grid_controller.js +248 -214
  29. data/dist/controllers/date_range_picker_controller.js +338 -235
  30. data/dist/controllers/dialog_controller.js +899 -237
  31. data/dist/controllers/direct_upload_controller.js +97 -167
  32. data/dist/controllers/dirty_form_controller.js +72 -69
  33. data/dist/controllers/dismissible_controller.js +196 -24
  34. data/dist/controllers/drawer_controller.js +974 -355
  35. data/dist/controllers/dropdown_controller.js +339 -96
  36. data/dist/controllers/editable_controller.js +315 -88
  37. data/dist/controllers/empty_state_controller.js +79 -58
  38. data/dist/controllers/file_dropzone_controller.js +322 -211
  39. data/dist/controllers/filter_controller.js +77 -42
  40. data/dist/controllers/flash_controller.js +238 -347
  41. data/dist/controllers/focus_controller.js +679 -240
  42. data/dist/controllers/form_field_controller.js +156 -132
  43. data/dist/controllers/form_validation_controller.js +31 -97
  44. data/dist/controllers/frame_loading_controller.js +275 -217
  45. data/dist/controllers/highlight_controller.js +107 -75
  46. data/dist/controllers/hover_card_controller.js +327 -130
  47. data/dist/controllers/idle_controller.js +271 -101
  48. data/dist/controllers/input_mask_controller.js +483 -97
  49. data/dist/controllers/intersection_controller.js +150 -106
  50. data/dist/controllers/lazy_frame_controller.js +24 -68
  51. data/dist/controllers/listbox_controller.js +523 -240
  52. data/dist/controllers/local_time_controller.js +102 -77
  53. data/dist/controllers/masonry_controller.js +80 -96
  54. data/dist/controllers/menu_controller.js +302 -188
  55. data/dist/controllers/menubar_controller.js +232 -345
  56. data/dist/controllers/meter_controller.js +417 -87
  57. data/dist/controllers/multi_select_controller.js +785 -393
  58. data/dist/controllers/navigation_menu_controller.js +190 -250
  59. data/dist/controllers/nested_form_controller.js +396 -192
  60. data/dist/controllers/network_status_controller.js +268 -62
  61. data/dist/controllers/number_input_controller.js +610 -303
  62. data/dist/controllers/optimistic_controller.js +45 -87
  63. data/dist/controllers/otp_controller.js +658 -255
  64. data/dist/controllers/overflow_indicator_controller.js +122 -113
  65. data/dist/controllers/overflow_menu_controller.js +470 -295
  66. data/dist/controllers/pagination_controller.js +332 -123
  67. data/dist/controllers/password_reveal_controller.js +392 -121
  68. data/dist/controllers/password_strength_controller.js +111 -158
  69. data/dist/controllers/persist_controller.js +165 -111
  70. data/dist/controllers/pointer_drag_controller.js +434 -188
  71. data/dist/controllers/popover_controller.js +269 -113
  72. data/dist/controllers/portal_controller.js +215 -76
  73. data/dist/controllers/preview_guard_controller.js +243 -116
  74. data/dist/controllers/progress_controller.js +391 -78
  75. data/dist/controllers/radio_group_controller.js +278 -211
  76. data/dist/controllers/range_slider_controller.js +220 -113
  77. data/dist/controllers/rating_controller.js +458 -211
  78. data/dist/controllers/read_more_controller.js +138 -63
  79. data/dist/controllers/reading_progress_controller.js +166 -137
  80. data/dist/controllers/relative_time_controller.js +211 -112
  81. data/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +103 -38
  82. data/dist/controllers/resizable_controller.js +299 -150
  83. data/dist/controllers/roving_controller.js +49 -88
  84. data/dist/controllers/scroll_area_controller.js +490 -246
  85. data/dist/controllers/scroll_restore_controller.js +14 -55
  86. data/dist/controllers/scroll_visibility_controller.js +432 -149
  87. data/dist/controllers/scrollspy_controller.js +193 -248
  88. data/dist/controllers/separator_controller.js +285 -142
  89. data/dist/controllers/sidebar_controller.js +1069 -404
  90. data/dist/controllers/skeleton_controller.js +259 -101
  91. data/dist/controllers/slider_controller.js +187 -86
  92. data/dist/controllers/smart_sticky_header_controller.js +173 -66
  93. data/dist/controllers/sortable_controller.js +26 -125
  94. data/dist/controllers/spinner_controller.js +288 -173
  95. data/dist/controllers/step_indicator_controller.js +105 -46
  96. data/dist/controllers/stepper_controller.js +120 -73
  97. data/dist/controllers/stick_to_bottom_controller.js +275 -140
  98. data/dist/controllers/sticky_observer_controller.js +220 -49
  99. data/dist/controllers/submit_once_controller.js +376 -227
  100. data/dist/controllers/switch_controller.js +201 -84
  101. data/dist/controllers/tabs_controller.js +41 -30
  102. data/dist/controllers/tags_input_controller.js +293 -173
  103. data/dist/controllers/textarea_autosize_controller.js +108 -74
  104. data/dist/controllers/theme_controller.js +140 -116
  105. data/dist/controllers/time_picker_controller.js +331 -127
  106. data/dist/controllers/toast_controller.js +244 -324
  107. data/dist/controllers/toggle_group_controller.js +252 -191
  108. data/dist/controllers/toolbar_controller.js +219 -120
  109. data/dist/controllers/tooltip_controller.js +158 -124
  110. data/dist/controllers/transition_controller.js +123 -119
  111. data/dist/controllers/tree_view_controller.js +283 -369
  112. data/dist/index.js +8573 -10410
  113. data/dist/positioning/index.js +154 -47
  114. data/lib/generators/stimeo/install/install_generator.rb +7 -2
  115. data/lib/generators/stimeo/install/templates/stimeo.js +19 -6
  116. data/lib/stimeo/ui/version.rb +1 -1
  117. metadata +3 -3
@@ -1,44 +1,7 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/reading_progress_controller.ts
4
-
5
- // src/utils/before_cache_reset.ts
6
- var BeforeCacheReset = class _BeforeCacheReset {
7
- /** Every subscribed instance, iterated by the one shared document listener. */
8
- static #subscribers = /* @__PURE__ */ new Set();
9
- /** The shared listener; installed while at least one instance is subscribed. */
10
- static #onBeforeCache = () => {
11
- for (const subscriber of _BeforeCacheReset.#subscribers) subscriber.#rewind();
12
- };
13
- #rewind;
14
- /** @param rewind - the pass that returns this controller's state to its initial form. */
15
- constructor(rewind) {
16
- this.#rewind = rewind;
17
- }
18
- /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */
19
- activate() {
20
- const first = _BeforeCacheReset.#subscribers.size === 0;
21
- _BeforeCacheReset.#subscribers.add(this);
22
- if (first) {
23
- document.addEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
24
- }
25
- }
26
- /** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */
27
- deactivate() {
28
- _BeforeCacheReset.#subscribers.delete(this);
29
- if (_BeforeCacheReset.#subscribers.size > 0) return;
30
- document.removeEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
31
- }
32
- };
33
-
34
- // src/utils/frame_coalescer.ts
35
3
  var FrameCoalescer = class {
36
4
  #frame = null;
37
- /**
38
- * Runs `run` on the next frame, unless a frame is already pending — the first
39
- * request of a burst wins and the rest are dropped. The pending frame is
40
- * released before `run`, so `run` may request the next one.
41
- */
42
5
  schedule(run) {
43
6
  if (this.#frame !== null) return;
44
7
  this.#frame = requestAnimationFrame(() => {
@@ -46,14 +9,6 @@ var FrameCoalescer = class {
46
9
  run();
47
10
  });
48
11
  }
49
- /**
50
- * Drops the pending frame, and reaches the platform only when there is one.
51
- *
52
- * There is no handle value that stands for "nothing pending":
53
- * `cancelAnimationFrame` takes an `unsigned long`, so a negative placeholder
54
- * arrives as a large positive number that the same allocator can hand out, and
55
- * an idle cancel would then drop a frame belonging to someone else.
56
- */
57
12
  cancel() {
58
13
  if (this.#frame === null) return;
59
14
  cancelAnimationFrame(this.#frame);
@@ -61,18 +16,15 @@ var FrameCoalescer = class {
61
16
  }
62
17
  };
63
18
 
64
- // src/utils/layout_observer.ts
65
19
  var LayoutObserver = class {
66
20
  #callback;
67
21
  #resizeObserverFactory;
68
22
  #resizeObserver = null;
69
23
  #observingViewport = false;
70
24
  #loadContainer = null;
71
- /** Stable bound handler so add/removeEventListener target the same reference. */
72
25
  #handleViewportResize = () => {
73
26
  this.#callback();
74
27
  };
75
- /** Stable bound handler for the capture-phase `load`; see {@link observeDescendantLoads}. */
76
28
  #handleDescendantLoad = () => {
77
29
  this.#callback();
78
30
  };
@@ -80,11 +32,6 @@ var LayoutObserver = class {
80
32
  this.#callback = callback;
81
33
  this.#resizeObserverFactory = options.resizeObserverFactory ?? (typeof ResizeObserver === "undefined" ? null : (cb) => new ResizeObserver(cb));
82
34
  }
83
- /**
84
- * Starts observing an element's size. Repeated calls observe additional
85
- * elements through the same shared observer. No-ops when no
86
- * `ResizeObserver` implementation is available.
87
- */
88
35
  observe(element) {
89
36
  if (!this.#resizeObserverFactory) return;
90
37
  if (!this.#resizeObserver) {
@@ -94,47 +41,28 @@ var LayoutObserver = class {
94
41
  }
95
42
  this.#resizeObserver.observe(element);
96
43
  }
97
- /** Stops observing a single element while leaving any others in place. */
98
44
  unobserve(element) {
99
45
  this.#resizeObserver?.unobserve(element);
100
46
  }
101
- /** Starts observing viewport resizes. Idempotent: the listener is added once. */
102
47
  observeViewport() {
103
48
  if (this.#observingViewport) return;
104
49
  this.#observingViewport = true;
105
50
  window.addEventListener("resize", this.#handleViewportResize);
106
51
  }
107
- /** Stops observing viewport resizes without affecting element observation. */
108
52
  unobserveViewport() {
109
53
  if (!this.#observingViewport) return;
110
54
  this.#observingViewport = false;
111
55
  window.removeEventListener("resize", this.#handleViewportResize);
112
56
  }
113
- /**
114
- * Starts reporting a `load` from anywhere inside `container` — an image or a
115
- * frame settling changes the box it sits in, and it measures as zero high until
116
- * then. `load` does not bubble, so the subscription is a capture-phase listener
117
- * on the container itself and nothing the caller spells.
118
- *
119
- * **One container at a time.** A further call moves the observation, so a widget
120
- * whose content element is swapped at runtime releases the element it let go by
121
- * naming the new one — there is no second place for the release to drift from.
122
- */
123
57
  observeDescendantLoads(container) {
124
58
  this.unobserveDescendantLoads();
125
59
  this.#loadContainer = container;
126
60
  container.addEventListener("load", this.#handleDescendantLoad, true);
127
61
  }
128
- /** Stops reporting descendant loads without affecting element or viewport observation. */
129
62
  unobserveDescendantLoads() {
130
63
  this.#loadContainer?.removeEventListener("load", this.#handleDescendantLoad, true);
131
64
  this.#loadContainer = null;
132
65
  }
133
- /**
134
- * Releases every observation: disconnects the {@link ResizeObserver} and removes
135
- * the viewport and descendant-load listeners. Safe to call multiple times. Call
136
- * this from a controller's `disconnect()`.
137
- */
138
66
  disconnect() {
139
67
  this.#resizeObserver?.disconnect();
140
68
  this.#resizeObserver = null;
@@ -143,81 +71,196 @@ var LayoutObserver = class {
143
71
  }
144
72
  };
145
73
 
146
- // src/utils/style_property_lease.ts
147
- var StylePropertyLease = class {
74
+ var ListenerSet = class {
75
+ #abort = new AbortController();
76
+ add(target, type, handler, options) {
77
+ target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
78
+ }
79
+ dispose() {
80
+ this.#abort.abort();
81
+ this.#abort = new AbortController();
82
+ }
83
+ };
84
+
85
+ function setAttributeIfChanged(element, name, value, beforeWrite) {
86
+ if (element.getAttribute(name) === value) return false;
87
+ if (value === null) element.removeAttribute(name);
88
+ else element.setAttribute(name, value);
89
+ return true;
90
+ }
91
+
92
+ function sharedRegistry(key, create) {
93
+ const symbol = Symbol.for(key);
94
+ const scope = globalThis;
95
+ const existing = scope[symbol];
96
+ if (existing !== void 0) return existing;
97
+ const registry = create();
98
+ Object.defineProperty(globalThis, symbol, { value: registry });
99
+ return registry;
100
+ }
101
+
102
+ var StylePropertyLease = class _StylePropertyLease {
103
+ static #registry = sharedRegistry(
104
+ "stimeo-ui.style-property-lease.registry.v1",
105
+ () => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
106
+ );
148
107
  #property;
149
- #records = /* @__PURE__ */ new Map();
150
- /** @param property - The CSS property whose temporary values this lease owns. */
151
- constructor(property) {
108
+ #record;
109
+ #held = /* @__PURE__ */ new Set();
110
+ constructor(property, owner) {
152
111
  this.#property = property;
112
+ this.#record = `data-${owner}-style-${property}-lease`;
113
+ const names = _StylePropertyLease.#registry.names;
114
+ names.set(property, (names.get(property) ?? /* @__PURE__ */ new Set()).add(this.#record));
153
115
  }
154
- /** Writes or removes the leased declaration while preserving its authored value. */
155
116
  write(element, value, priority = "") {
156
- const existing = this.#records.get(element);
157
- if (existing) {
158
- existing.writtenValue = value;
159
- existing.writtenPriority = value === null ? "" : priority;
160
- } else {
161
- this.#records.set(element, {
162
- originalValue: element.style.getPropertyValue(this.#property),
163
- originalPriority: element.style.getPropertyPriority(this.#property),
164
- writtenValue: value,
165
- writtenPriority: value === null ? "" : priority
166
- });
167
- }
168
- this.#reflect(element, value, priority);
117
+ const stack = this.#stack(element);
118
+ const hold = this.#take(stack) ?? this.#acquire(element, stack);
119
+ this.#held.add(element);
120
+ const shows = !this.#covered(element, stack, hold);
121
+ hold.writtenValue = value;
122
+ hold.writtenPriority = value === null ? "" : priority;
123
+ this.#mark(element, stack);
124
+ if (shows) this.#show(element, value, hold.writtenPriority);
169
125
  }
170
- /** Returns one lease without overwriting a later consumer declaration. */
171
126
  return(element) {
172
- const record = this.#records.get(element);
173
- if (!record) return;
174
- this.#records.delete(element);
175
- const style = element.style;
176
- const stillOwned = style.getPropertyValue(this.#property) === (record.writtenValue ?? "") && style.getPropertyPriority(this.#property) === record.writtenPriority;
177
- if (stillOwned) {
178
- this.#reflect(element, record.originalValue, record.originalPriority);
179
- }
127
+ const held = this.#held.delete(element);
128
+ const known = _StylePropertyLease.#registry.stacks.get(element)?.has(this.#property);
129
+ const stack = held || known || element.hasAttribute(this.#record) ? this.#stack(element) : [];
130
+ const hold = this.#take(stack);
131
+ if (!hold) return;
132
+ const owns = this.#carries(element, hold) && !this.#covered(element, stack, hold);
133
+ const index = stack.indexOf(hold);
134
+ stack.splice(index, 1);
135
+ const above = stack[index];
136
+ if (above) above.linked &&= hold.linked;
137
+ this.#mark(element, stack);
138
+ if (!owns) return;
139
+ const below = hold.linked ? stack[index - 1] : void 0;
140
+ if (below) this.#show(element, below.writtenValue, below.writtenPriority);
141
+ else this.#show(element, hold.originalValue, hold.originalPriority);
180
142
  }
181
- /** Returns every outstanding declaration lease. */
182
143
  returnAll() {
183
- for (const element of Array.from(this.#records.keys())) this.return(element);
144
+ for (const element of Array.from(this.#held)) this.return(element);
145
+ }
146
+ #recorded(element, name) {
147
+ try {
148
+ const parsed = JSON.parse(element.getAttribute(name) ?? "null");
149
+ if (!Array.isArray(parsed)) return null;
150
+ const [originalValue, originalPriority, writtenValue, writtenPriority, ...rest] = parsed;
151
+ if (typeof originalValue !== "string" || typeof originalPriority !== "string") return null;
152
+ if (typeof writtenValue !== "string" && writtenValue !== null) return null;
153
+ if (typeof writtenPriority !== "string") return null;
154
+ const linked = rest[0] !== false;
155
+ const beneath = linked ? rest : rest.slice(1);
156
+ if (!beneath.every((under) => typeof under === "string")) return null;
157
+ return { originalValue, originalPriority, writtenValue, writtenPriority, linked, beneath };
158
+ } catch {
159
+ return null;
160
+ }
184
161
  }
185
- /** Reflects only a real declaration transition. */
186
- #reflect(element, value, priority) {
162
+ #stack(element) {
163
+ const stacks = _StylePropertyLease.#registry.stacks;
164
+ const byProperty = stacks.get(element) ?? /* @__PURE__ */ new Map();
165
+ stacks.set(element, byProperty);
166
+ const stack = byProperty.get(this.#property) ?? this.#seed(element);
167
+ byProperty.set(this.#property, stack);
168
+ return stack;
169
+ }
170
+ #seed(element) {
171
+ const found = [];
172
+ for (const record of _StylePropertyLease.#registry.names.get(this.#property) ?? []) {
173
+ const read = this.#recorded(element, record);
174
+ if (read) found.push({ ...read, record });
175
+ }
176
+ const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
177
+ return found.sort((one, other) => depth(one) - depth(other)).map((entry, index) => ({
178
+ lease: null,
179
+ record: entry.record,
180
+ writtenValue: entry.writtenValue,
181
+ writtenPriority: entry.writtenPriority,
182
+ originalValue: entry.originalValue,
183
+ originalPriority: entry.originalPriority,
184
+ linked: entry.linked && index > 0
185
+ }));
186
+ }
187
+ #take(stack) {
188
+ const hold = stack.find((held) => held.lease === this) ?? stack.find((held) => held.lease === null && held.record === this.#record);
189
+ if (hold) hold.lease = this;
190
+ return hold;
191
+ }
192
+ #acquire(element, stack) {
193
+ const top = stack.at(-1);
194
+ const over = top && this.#carries(element, top) ? top : void 0;
187
195
  const style = element.style;
188
- const nextValue = value ?? "";
189
- const nextPriority = value === null ? "" : priority;
190
- if (style.getPropertyValue(this.#property) === nextValue && style.getPropertyPriority(this.#property) === nextPriority) {
191
- return;
196
+ const hold = {
197
+ lease: this,
198
+ record: this.#record,
199
+ writtenValue: null,
200
+ writtenPriority: "",
201
+ originalValue: over ? over.originalValue : style.getPropertyValue(this.#property),
202
+ originalPriority: over ? over.originalPriority : style.getPropertyPriority(this.#property),
203
+ linked: over !== void 0
204
+ };
205
+ stack.push(hold);
206
+ return hold;
207
+ }
208
+ #covered(element, stack, hold) {
209
+ return stack.slice(stack.indexOf(hold) + 1).some((above) => this.#carries(element, above));
210
+ }
211
+ #mark(element, stack) {
212
+ const records = /* @__PURE__ */ new Map([[this.#record, null]]);
213
+ stack.forEach((hold, index) => {
214
+ const names = stack.slice(0, index).map((under) => under.record);
215
+ const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
216
+ const marker = hold.linked || beneath.length === 0 ? [] : [false];
217
+ const { originalValue, originalPriority, writtenValue, writtenPriority } = hold;
218
+ records.set(
219
+ hold.record,
220
+ (writtenValue ?? "") === originalValue && writtenPriority === originalPriority && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([
221
+ originalValue,
222
+ originalPriority,
223
+ writtenValue,
224
+ writtenPriority,
225
+ ...marker,
226
+ ...beneath
227
+ ])
228
+ );
229
+ });
230
+ for (const [name, recorded] of records) {
231
+ setAttributeIfChanged(element, name, recorded);
192
232
  }
193
- if (value === null) style.removeProperty(this.#property);
194
- else style.setProperty(this.#property, value, priority);
233
+ }
234
+ #carries(element, hold) {
235
+ return this.#holds(element, hold.writtenValue ?? "", hold.writtenPriority);
236
+ }
237
+ #holds(element, value, priority) {
238
+ const style = element.style;
239
+ return style.getPropertyValue(this.#property) === value && style.getPropertyPriority(this.#property) === priority;
240
+ }
241
+ #show(element, value, priority) {
242
+ if (this.#holds(element, value ?? "", priority)) return;
243
+ if (value === null) element.style.removeProperty(this.#property);
244
+ else element.style.setProperty(this.#property, value, priority);
195
245
  }
196
246
  };
197
247
 
198
- // src/controllers/reading_progress_controller.ts
199
248
  var PROGRESS_PROPERTY = "--stimeo--reading-progress";
200
249
  var ReadingProgressController = class extends Controller {
201
250
  static events = ["change", "complete"];
202
- /** Owns both faces of the published property so teardown can hand them back. */
203
- #lease = new StylePropertyLease(PROGRESS_PROPERTY);
204
- /** The article's own box and the viewport: either changes the span. */
251
+ #lease = new StylePropertyLease(PROGRESS_PROPERTY, this.identifier);
205
252
  #layout = new LayoutObserver(() => this.#onScroll());
206
- #beforeCache = new BeforeCacheReset(() => this.#rewindForCache());
207
- /** Coalesces scroll bursts, and the connect baseline, into one frame. */
208
253
  #frames = new FrameCoalescer();
209
- /** Last published progress, so `change`/`complete` fire only on movement. */
210
254
  #progress = -1;
211
- /** False until the connect frame has run: `complete` needs real reading. */
212
255
  #baselined = false;
213
256
  #onScroll = () => this.#frames.schedule(() => this.#measure());
257
+ #listeners = new ListenerSet();
214
258
  connect() {
215
259
  this.#progress = -1;
216
260
  this.#baselined = false;
217
- window.addEventListener("scroll", this.#onScroll, { passive: true, capture: true });
261
+ this.#listeners.add(window, "scroll", this.#onScroll, { passive: true, capture: true });
218
262
  this.#layout.observe(this.element);
219
263
  this.#layout.observeViewport();
220
- this.#beforeCache.activate();
221
264
  this.#measure();
222
265
  this.#frames.schedule(() => {
223
266
  this.#measure();
@@ -225,25 +268,12 @@ var ReadingProgressController = class extends Controller {
225
268
  });
226
269
  }
227
270
  disconnect() {
228
- window.removeEventListener("scroll", this.#onScroll, { capture: true });
271
+ this.#listeners.dispose();
229
272
  this.#layout.disconnect();
230
- this.#beforeCache.deactivate();
231
- this.#frames.cancel();
232
- this.#lease.returnAll();
233
- }
234
- /**
235
- * Hands both declarations back before the page is snapshotted, so a restored
236
- * page starts from the authored DOM rather than from someone else's progress.
237
- * The baseline goes back with them: a cancelled visit leaves this page on
238
- * screen, and the next measurement has to publish afresh rather than match a
239
- * value that has already been handed back.
240
- */
241
- #rewindForCache() {
242
273
  this.#frames.cancel();
243
- this.#lease.returnAll();
244
- this.#progress = -1;
274
+ this.#lease.return(this.element);
275
+ this.#lease.return(document.documentElement);
245
276
  }
246
- /** Computes and publishes the progress; emits on movement only. */
247
277
  #measure() {
248
278
  const rect = this.element.getBoundingClientRect();
249
279
  if (rect.width === 0 && rect.height === 0) return;
@@ -262,5 +292,4 @@ var ReadingProgressController = class extends Controller {
262
292
  };
263
293
 
264
294
  export { ReadingProgressController };
265
- //# sourceMappingURL=reading_progress_controller.js.map
266
295
  //# sourceMappingURL=reading_progress_controller.js.map