stimeo-ui 0.16.0 → 0.17.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 (115) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/README.md +8 -1
  4. data/dist/cable/index.js +363 -436
  5. data/dist/controllers/accordion_controller.js +166 -55
  6. data/dist/controllers/alert_dialog_controller.js +862 -221
  7. data/dist/controllers/announcer_controller.js +135 -198
  8. data/dist/controllers/aspect_ratio_controller.js +0 -10
  9. data/dist/controllers/auto_submit_controller.js +271 -127
  10. data/dist/controllers/avatar_controller.js +171 -105
  11. data/dist/controllers/breadcrumb_controller.js +0 -130
  12. data/dist/controllers/bulk_select_controller.js +262 -52
  13. data/dist/controllers/calendar_controller.js +175 -209
  14. data/dist/controllers/carousel_controller.js +461 -399
  15. data/dist/controllers/character_counter_controller.js +246 -156
  16. data/dist/controllers/checkbox_controller.js +32 -74
  17. data/dist/controllers/clipboard_controller.js +168 -147
  18. data/dist/controllers/collapsible_controller.js +301 -120
  19. data/dist/controllers/color_picker_controller.js +149 -139
  20. data/dist/controllers/combobox_controller.js +360 -133
  21. data/dist/controllers/command_palette_controller.js +970 -358
  22. data/dist/controllers/conditional_fields_controller.js +166 -124
  23. data/dist/controllers/confirm_controller.js +939 -248
  24. data/dist/controllers/context_menu_controller.js +256 -128
  25. data/dist/controllers/count_up_controller.js +73 -21
  26. data/dist/controllers/countdown_controller.js +183 -148
  27. data/dist/controllers/currency_input_controller.js +134 -158
  28. data/dist/controllers/data_grid_controller.js +114 -186
  29. data/dist/controllers/date_range_picker_controller.js +288 -206
  30. data/dist/controllers/dialog_controller.js +858 -223
  31. data/dist/controllers/direct_upload_controller.js +73 -153
  32. data/dist/controllers/dirty_form_controller.js +14 -48
  33. data/dist/controllers/dismissible_controller.js +175 -21
  34. data/dist/controllers/drawer_controller.js +933 -341
  35. data/dist/controllers/dropdown_controller.js +312 -82
  36. data/dist/controllers/editable_controller.js +158 -68
  37. data/dist/controllers/empty_state_controller.js +67 -53
  38. data/dist/controllers/file_dropzone_controller.js +311 -207
  39. data/dist/controllers/filter_controller.js +67 -39
  40. data/dist/controllers/flash_controller.js +172 -314
  41. data/dist/controllers/focus_controller.js +654 -240
  42. data/dist/controllers/form_field_controller.js +147 -132
  43. data/dist/controllers/form_validation_controller.js +13 -86
  44. data/dist/controllers/frame_loading_controller.js +264 -213
  45. data/dist/controllers/highlight_controller.js +107 -75
  46. data/dist/controllers/hover_card_controller.js +309 -118
  47. data/dist/controllers/idle_controller.js +267 -101
  48. data/dist/controllers/input_mask_controller.js +71 -72
  49. data/dist/controllers/intersection_controller.js +147 -106
  50. data/dist/controllers/lazy_frame_controller.js +9 -65
  51. data/dist/controllers/listbox_controller.js +306 -204
  52. data/dist/controllers/local_time_controller.js +54 -64
  53. data/dist/controllers/masonry_controller.js +70 -93
  54. data/dist/controllers/menu_controller.js +214 -156
  55. data/dist/controllers/menubar_controller.js +170 -329
  56. data/dist/controllers/meter_controller.js +151 -67
  57. data/dist/controllers/multi_select_controller.js +593 -358
  58. data/dist/controllers/navigation_menu_controller.js +124 -232
  59. data/dist/controllers/nested_form_controller.js +352 -182
  60. data/dist/controllers/network_status_controller.js +242 -54
  61. data/dist/controllers/number_input_controller.js +320 -263
  62. data/dist/controllers/optimistic_controller.js +16 -76
  63. data/dist/controllers/otp_controller.js +198 -193
  64. data/dist/controllers/overflow_indicator_controller.js +116 -113
  65. data/dist/controllers/overflow_menu_controller.js +343 -283
  66. data/dist/controllers/pagination_controller.js +295 -119
  67. data/dist/controllers/password_reveal_controller.js +389 -121
  68. data/dist/controllers/password_strength_controller.js +99 -153
  69. data/dist/controllers/persist_controller.js +237 -103
  70. data/dist/controllers/pointer_drag_controller.js +185 -165
  71. data/dist/controllers/popover_controller.js +236 -97
  72. data/dist/controllers/portal_controller.js +209 -76
  73. data/dist/controllers/preview_guard_controller.js +232 -116
  74. data/dist/controllers/progress_controller.js +125 -56
  75. data/dist/controllers/radio_group_controller.js +117 -137
  76. data/dist/controllers/range_slider_controller.js +192 -105
  77. data/dist/controllers/rating_controller.js +418 -207
  78. data/dist/controllers/read_more_controller.js +134 -63
  79. data/dist/controllers/reading_progress_controller.js +147 -135
  80. data/dist/controllers/relative_time_controller.js +145 -110
  81. data/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +97 -38
  82. data/dist/controllers/resizable_controller.js +255 -139
  83. data/dist/controllers/roving_controller.js +39 -84
  84. data/dist/controllers/scroll_area_controller.js +428 -225
  85. data/dist/controllers/scroll_restore_controller.js +0 -53
  86. data/dist/controllers/scroll_visibility_controller.js +395 -145
  87. data/dist/controllers/scrollspy_controller.js +181 -242
  88. data/dist/controllers/separator_controller.js +267 -140
  89. data/dist/controllers/sidebar_controller.js +1023 -386
  90. data/dist/controllers/skeleton_controller.js +248 -97
  91. data/dist/controllers/slider_controller.js +159 -79
  92. data/dist/controllers/smart_sticky_header_controller.js +162 -63
  93. data/dist/controllers/sortable_controller.js +0 -112
  94. data/dist/controllers/spinner_controller.js +277 -169
  95. data/dist/controllers/step_indicator_controller.js +99 -46
  96. data/dist/controllers/stepper_controller.js +114 -73
  97. data/dist/controllers/stick_to_bottom_controller.js +262 -138
  98. data/dist/controllers/sticky_observer_controller.js +214 -49
  99. data/dist/controllers/submit_once_controller.js +294 -205
  100. data/dist/controllers/switch_controller.js +33 -60
  101. data/dist/controllers/tabs_controller.js +35 -29
  102. data/dist/controllers/tags_input_controller.js +136 -145
  103. data/dist/controllers/textarea_autosize_controller.js +71 -58
  104. data/dist/controllers/theme_controller.js +130 -112
  105. data/dist/controllers/time_picker_controller.js +146 -80
  106. data/dist/controllers/toast_controller.js +186 -297
  107. data/dist/controllers/toggle_group_controller.js +95 -136
  108. data/dist/controllers/toolbar_controller.js +68 -98
  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 +150 -345
  112. data/dist/index.js +6370 -9346
  113. data/dist/positioning/index.js +148 -47
  114. data/lib/stimeo/ui/version.rb +1 -1
  115. metadata +3 -3
@@ -1,78 +1,110 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/transition_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);
3
+ var DetachGate = class _DetachGate {
4
+ #pending = false;
5
+ get pending() {
6
+ return this.#pending;
7
+ }
8
+ static isDetached(host) {
9
+ return !host.element.isConnected || !_DetachGate.#listed(host);
10
+ }
11
+ disconnected(host, teardown) {
12
+ const carried = _DetachGate.#carried(host);
13
+ if (!carried && _DetachGate.isDetached(host)) {
14
+ this.#pending = false;
15
+ teardown();
16
+ return;
24
17
  }
18
+ this.#pending = true;
19
+ const probe = () => {
20
+ if (!this.#pending) return;
21
+ this.#pending = false;
22
+ teardown();
23
+ };
24
+ if (carried) setTimeout(probe, 0);
25
+ else queueMicrotask(probe);
25
26
  }
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);
27
+ static #carried(host) {
28
+ const element = host.element;
29
+ return !element.isConnected && element.closest("[data-turbo-permanent]") !== null && _DetachGate.#listed(host);
30
+ }
31
+ static #listed(host) {
32
+ const tokens = (host.element.getAttribute("data-controller") ?? "").split(/\s+/);
33
+ return tokens.includes(host.identifier);
34
+ }
35
+ cancel() {
36
+ this.#pending = false;
37
+ }
38
+ };
39
+
40
+ var MAX_TIMER_DELAY_MS = 2147483647;
41
+
42
+ var NUMBER_BOUNDS = {
43
+ timer: { finite: true, min: 0, max: MAX_TIMER_DELAY_MS }};
44
+ function matchesNumberBounds(value, bounds) {
45
+ if (!Number.isFinite(value)) {
46
+ const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
47
+ if (direction === null) return false;
48
+ if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
49
+ }
50
+ if (bounds.min !== void 0 && value < bounds.min) return false;
51
+ if (bounds.max !== void 0 && value > bounds.max) return false;
52
+ if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
53
+ if (bounds.integer && !Number.isInteger(value)) return false;
54
+ if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
55
+ return true;
56
+ }
57
+
58
+ function readNumber(raw, fallback, bounds) {
59
+ return matchesNumberBounds(raw, bounds) ? raw : fallback;
60
+ }
61
+
62
+ var NumberValueReader = class {
63
+ #lastRejected = /* @__PURE__ */ new Map();
64
+ read(owner, name, raw, fallback, bounds) {
65
+ const resolved = readNumber(raw, fallback, bounds);
66
+ if (matchesNumberBounds(raw, bounds)) {
67
+ this.#lastRejected.delete(name);
68
+ return resolved;
69
+ }
70
+ const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
71
+ const literal = owner.element.getAttribute(attribute);
72
+ if (literal === null) {
73
+ this.#lastRejected.delete(name);
74
+ return resolved;
75
+ }
76
+ if (this.#lastRejected.get(name) !== literal) {
77
+ this.#lastRejected.set(name, literal);
78
+ console.warn(
79
+ `Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
80
+ );
81
+ }
82
+ return resolved;
31
83
  }
32
84
  };
33
85
 
34
- // src/utils/reduced_motion.ts
35
86
  function prefersReducedMotion() {
36
87
  return typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
37
88
  }
38
89
 
39
- // src/utils/safe_timeout.ts
40
90
  var TimerRegistry = class {
41
- /** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
42
91
  ids = /* @__PURE__ */ new Set();
43
- /**
44
- * Cancels a single tracked timer.
45
- *
46
- * No-ops if the id is unknown (already cleared, fired, or never owned by this
47
- * registry), so callers can clear defensively without guarding.
48
- */
49
92
  clear(id) {
50
93
  if (this.ids.delete(id)) {
51
94
  this.cancel(id);
52
95
  }
53
96
  }
54
- /**
55
- * Cancels every tracked timer. Call this from a controller's `disconnect()`
56
- * to guarantee no timer outlives the element.
57
- */
58
97
  clearAll() {
59
98
  for (const id of this.ids) {
60
99
  this.cancel(id);
61
100
  }
62
101
  this.ids.clear();
63
102
  }
64
- /** Number of timers currently tracked (pending). */
65
103
  get size() {
66
104
  return this.ids.size;
67
105
  }
68
106
  };
69
107
  var SafeTimeout = class extends TimerRegistry {
70
- /**
71
- * Schedules `callback` after `delay` ms and returns the timer id.
72
- *
73
- * The id is removed from the registry automatically when the timeout fires,
74
- * so {@link TimerRegistry.size | size} reflects only still-pending timers.
75
- */
76
108
  set(callback, delay) {
77
109
  const id = this.schedule(() => {
78
110
  this.ids.delete(id);
@@ -89,7 +121,6 @@ var SafeTimeout = class extends TimerRegistry {
89
121
  }
90
122
  };
91
123
 
92
- // src/utils/transition_completion.ts
93
124
  function timeMs(value) {
94
125
  const trimmed = value.trim();
95
126
  const amount = Number.parseFloat(trimmed);
@@ -125,13 +156,6 @@ var TransitionCompletion = class {
125
156
  #complete = null;
126
157
  #pendingProperties = null;
127
158
  #deadline = 0;
128
- /**
129
- * Replaces any prior wait and invokes `complete` synchronously for a 0ms
130
- * transition (including when `getComputedStyle` is unavailable).
131
- *
132
- * With a positive `options.timeoutMs` the synchronous fast-path is skipped and
133
- * the override replaces the auto-computed fallback (see {@link TransitionWaitOptions}).
134
- */
135
159
  wait(element, complete, options = {}) {
136
160
  this.cancel();
137
161
  const requested = options.timeoutMs ?? 0;
@@ -151,18 +175,10 @@ var TransitionCompletion = class {
151
175
  element.addEventListener("transitioncancel", this.#onTerminal);
152
176
  this.#timers.set(() => this.#finish(), override > 0 ? override : maximum + 50);
153
177
  }
154
- /** Cancels the pending wait without invoking its completion callback. */
155
178
  cancel() {
156
179
  this.#complete = null;
157
180
  this.#teardown();
158
181
  }
159
- /**
160
- * Handles terminal events from the observed element only.
161
- *
162
- * For explicit property lists, every declared positive-time property must
163
- * settle. For `all`, no reliable property set exists, so an event can finish
164
- * only after the computed maximum time; the safety timeout owns the usual path.
165
- */
166
182
  #onTerminal = (event) => {
167
183
  if (event.target !== this.#element) return;
168
184
  const transitionEvent = event;
@@ -182,10 +198,6 @@ var TransitionCompletion = class {
182
198
  }
183
199
  if (Date.now() >= this.#deadline) this.#finish();
184
200
  };
185
- /**
186
- * Returns active CSS transition properties expanded to the names reported by
187
- * terminal events. CSS animations and pseudo-element effects are excluded.
188
- */
189
201
  #activeTransitionProperties(element) {
190
202
  if (!element || typeof element.getAnimations !== "function") return /* @__PURE__ */ new Set();
191
203
  try {
@@ -203,7 +215,6 @@ var TransitionCompletion = class {
203
215
  return /* @__PURE__ */ new Set();
204
216
  }
205
217
  }
206
- /** Returns explicit positive-time properties, or `null` for the ambiguous `all`. */
207
218
  #explicitPendingProperties(timings) {
208
219
  if (timings.some(({ property }) => property === "all")) return null;
209
220
  const pending = new Set(
@@ -211,7 +222,6 @@ var TransitionCompletion = class {
211
222
  );
212
223
  return pending.size > 0 ? pending : null;
213
224
  }
214
- /** Completes exactly once, releasing listeners and the fallback before the callback. */
215
225
  #finish() {
216
226
  const complete = this.#complete;
217
227
  if (!complete) return;
@@ -219,7 +229,6 @@ var TransitionCompletion = class {
219
229
  this.#teardown();
220
230
  complete();
221
231
  }
222
- /** Releases the exact element listeners and timer owned by the current wait. */
223
232
  #teardown() {
224
233
  this.#timers.clearAll();
225
234
  this.#element?.removeEventListener("transitionend", this.#onTerminal);
@@ -230,9 +239,10 @@ var TransitionCompletion = class {
230
239
  }
231
240
  };
232
241
 
233
- // src/controllers/transition_controller.ts
234
242
  var tokensOf = (value) => value.split(/\s+/).filter(Boolean);
235
- var TransitionController = class extends Controller {
243
+ var STAGED_RECORD = "staged";
244
+ var TransitionController = class _TransitionController extends Controller {
245
+ #numbers = new NumberValueReader();
236
246
  static values = {
237
247
  enter: { type: String, default: "" },
238
248
  enterFrom: { type: String, default: "" },
@@ -242,45 +252,56 @@ var TransitionController = class extends Controller {
242
252
  leaveTo: { type: String, default: "" },
243
253
  timeout: { type: Number, default: 0 }
244
254
  };
255
+ static valueConstraints = {
256
+ timeout: NUMBER_BOUNDS.timer
257
+ };
245
258
  static actions = ["enter", "leave", "toggle"];
246
259
  static events = ["entered", "left"];
247
- /** Owns the cancellable completion wait (terminal events + bounded fallback). */
248
260
  #transition = new TransitionCompletion();
249
- /** Rewinds a half-applied stage before Turbo copies the page into its snapshot. */
250
- #beforeCache = new BeforeCacheReset(() => this.#rewindForCache());
251
261
  #rafId = null;
252
- /**
253
- * Stage classes this controller put on the element. Removing by declaration
254
- * instead would take a token the consumer also authored, and would strand the
255
- * token that was applied when a Value changes mid-transition.
256
- */
257
262
  #staged = /* @__PURE__ */ new Set();
263
+ #gate = new DetachGate();
258
264
  connect() {
259
- this.#beforeCache.activate();
265
+ const moved = this.#gate.pending;
266
+ this.#gate.cancel();
267
+ if (moved) return;
268
+ if (this.#staged.size === 0) this.#stripRecorded();
260
269
  this.#settleState();
261
270
  }
262
271
  disconnect() {
263
- this.#beforeCache.deactivate();
264
- this.#cancel();
272
+ this.#gate.disconnected(this, () => this.#cancel());
273
+ }
274
+ get #stagedRecord() {
275
+ return `data-${this.identifier}-${STAGED_RECORD}`;
276
+ }
277
+ #stripRecorded() {
278
+ const raw = this.element.getAttribute(this.#stagedRecord) ?? "null";
279
+ this.element.removeAttribute(this.#stagedRecord);
280
+ let recorded = null;
281
+ try {
282
+ recorded = JSON.parse(raw);
283
+ } catch {
284
+ }
285
+ if (!Array.isArray(recorded)) return;
286
+ for (const token of recorded) {
287
+ if (typeof token === "string" && token !== "") this.element.classList.remove(token);
288
+ }
289
+ }
290
+ #record() {
291
+ if (this.#staged.size === 0) this.element.removeAttribute(this.#stagedRecord);
292
+ else this.element.setAttribute(this.#stagedRecord, JSON.stringify([...this.#staged]));
265
293
  }
266
- /** Shows the element with the enter transition. */
267
294
  enter() {
268
295
  this.#run("enter");
269
296
  }
270
- /** Hides the element with the leave transition. */
271
297
  leave() {
272
298
  this.#run("leave");
273
299
  }
274
- /** Reverses the current direction (enter when hidden/leaving, else leave). */
275
300
  toggle() {
276
301
  const state = this.element.getAttribute("data-transition-state");
277
302
  if (state === "entered" || state === "entering") this.leave();
278
303
  else this.enter();
279
304
  }
280
- /**
281
- * @stimeoRuntimeOnly The class lists and `timeout` shape this one transition; `#finish` strips
282
- * the classes, so none of them stays at rest.
283
- */
284
305
  #run(kind) {
285
306
  this.#cancel();
286
307
  const isEnter = kind === "enter";
@@ -293,18 +314,16 @@ var TransitionController = class extends Controller {
293
314
  const base = isEnter ? this.enterValue : this.leaveValue;
294
315
  const from = isEnter ? this.enterFromValue : this.leaveFromValue;
295
316
  const to = isEnter ? this.enterToValue : this.leaveToValue;
317
+ const timeoutMs = this.#safeTimeout;
296
318
  this.#add(base, from);
297
319
  void this.element.offsetWidth;
298
320
  this.#rafId = this.#raf(() => {
299
321
  this.#rafId = null;
300
322
  this.#remove(from);
301
323
  this.#add(to);
302
- this.#transition.wait(this.element, () => this.#finish(kind), {
303
- timeoutMs: this.timeoutValue
304
- });
324
+ this.#transition.wait(this.element, () => this.#finish(kind), { timeoutMs });
305
325
  });
306
326
  }
307
- /** Settles the element into the completed state, clearing the stage classes. */
308
327
  #finish(kind) {
309
328
  this.#strip();
310
329
  if (kind === "enter") {
@@ -316,22 +335,9 @@ var TransitionController = class extends Controller {
316
335
  this.dispatch("left", { detail: {} });
317
336
  }
318
337
  }
319
- /** Writes the state hook the element's visibility implies. */
320
338
  #settleState() {
321
339
  this.element.setAttribute("data-transition-state", this.element.hidden ? "left" : "entered");
322
340
  }
323
- /**
324
- * Returns the element to a settled state before Turbo copies the page.
325
- *
326
- * The snapshot is taken while the controller is still connected, so stripping on
327
- * the next `connect()` would only repair the page after it has been painted from
328
- * the cache. The pass is silent: `connect()` derives the state again on restore.
329
- */
330
- #rewindForCache() {
331
- this.#cancel();
332
- this.#settleState();
333
- }
334
- /** Cancels any in-flight transition (interruption / teardown). */
335
341
  #cancel() {
336
342
  if (this.#rafId !== null) {
337
343
  this.#cancelRaf(this.#rafId);
@@ -340,34 +346,24 @@ var TransitionController = class extends Controller {
340
346
  this.#transition.cancel();
341
347
  this.#strip();
342
348
  }
343
- /**
344
- * Applies the stage tokens this controller does not already find on the
345
- * element, and claims exactly those.
346
- *
347
- * A token already on the element is left unclaimed: it is either the consumer's
348
- * standing class or one an earlier stage of this transition already claimed, and
349
- * in neither case may this call take ownership of it. That is what keeps a
350
- * standing class the consumer also named as a stage Value; the cost is that such
351
- * a token cannot be staged, so the property it drives resolves from their CSS.
352
- */
353
349
  #add(...lists) {
354
350
  for (const token of lists.flatMap(tokensOf)) {
355
351
  if (this.element.classList.contains(token)) continue;
356
352
  this.element.classList.add(token);
357
353
  this.#staged.add(token);
358
354
  }
355
+ this.#record();
359
356
  }
360
- /** Drops the named tokens that are this controller's to drop. */
361
357
  #remove(...lists) {
362
358
  for (const token of lists.flatMap(tokensOf)) {
363
359
  if (!this.#staged.delete(token)) continue;
364
360
  this.element.classList.remove(token);
365
361
  }
366
362
  }
367
- /** Removes every stage class this controller applied, so none lingers. */
368
363
  #strip() {
369
364
  this.element.classList.remove(...this.#staged);
370
365
  this.#staged.clear();
366
+ this.#record();
371
367
  }
372
368
  #raf(callback) {
373
369
  if (typeof window.requestAnimationFrame === "function") {
@@ -379,8 +375,16 @@ var TransitionController = class extends Controller {
379
375
  if (typeof window.cancelAnimationFrame === "function") window.cancelAnimationFrame(id);
380
376
  else window.clearTimeout(id);
381
377
  }
378
+ get #safeTimeout() {
379
+ return this.#numbers.read(
380
+ this,
381
+ "timeout",
382
+ this.timeoutValue,
383
+ _TransitionController.values.timeout.default,
384
+ _TransitionController.valueConstraints.timeout
385
+ );
386
+ }
382
387
  };
383
388
 
384
389
  export { TransitionController };
385
- //# sourceMappingURL=transition_controller.js.map
386
390
  //# sourceMappingURL=transition_controller.js.map