stimeo-ui 0.9.0 → 0.10.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 (32) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +74 -0
  3. data/dist/controllers/alert_dialog_controller.js +17 -7
  4. data/dist/controllers/announcer_controller.js +1 -1
  5. data/dist/controllers/bulk_select_controller.js +2 -2
  6. data/dist/controllers/collapsible_controller.js +1 -1
  7. data/dist/controllers/command_palette_controller.js +15 -5
  8. data/dist/controllers/confirm_controller.js +15 -5
  9. data/dist/controllers/countdown_controller.js +1 -1
  10. data/dist/controllers/data_grid_controller.js +1 -1
  11. data/dist/controllers/dialog_controller.js +15 -5
  12. data/dist/controllers/direct_upload_controller.js +1 -5
  13. data/dist/controllers/drawer_controller.js +17 -7
  14. data/dist/controllers/focus_controller.js +45 -7
  15. data/dist/controllers/form_field_controller.js +1 -1
  16. data/dist/controllers/menubar_controller.js +2 -2
  17. data/dist/controllers/multi_select_controller.js +1 -1
  18. data/dist/controllers/overflow_menu_controller.js +2 -2
  19. data/dist/controllers/password_reveal_controller.js +102 -3
  20. data/dist/controllers/password_strength_controller.js +287 -42
  21. data/dist/controllers/resizable_controller.js +1 -1
  22. data/dist/controllers/scroll_restore_controller.js +127 -27
  23. data/dist/controllers/scroll_visibility_controller.js +167 -14
  24. data/dist/controllers/sidebar_controller.js +15 -5
  25. data/dist/controllers/step_indicator_controller.js +0 -5
  26. data/dist/controllers/theme_controller.js +151 -40
  27. data/dist/controllers/toast_controller.js +2 -2
  28. data/dist/controllers/transition_controller.js +79 -15
  29. data/dist/index.js +740 -178
  30. data/dist/positioning/index.js +84 -25
  31. data/lib/stimeo/ui/version.rb +1 -1
  32. metadata +2 -2
@@ -2,6 +2,35 @@ import { Controller } from '@hotwired/stimulus';
2
2
 
3
3
  // src/controllers/transition_controller.ts
4
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
+
5
34
  // src/utils/reduced_motion.ts
6
35
  function prefersReducedMotion() {
7
36
  return typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
@@ -217,12 +246,21 @@ var TransitionController = class extends Controller {
217
246
  static events = ["entered", "left"];
218
247
  /** Owns the cancellable completion wait (terminal events + bounded fallback). */
219
248
  #transition = new TransitionCompletion();
249
+ /** Rewinds a half-applied stage before Turbo copies the page into its snapshot. */
250
+ #beforeCache = new BeforeCacheReset(() => this.#rewindForCache());
220
251
  #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
+ #staged = /* @__PURE__ */ new Set();
221
258
  connect() {
222
- this.#strip();
223
- this.element.setAttribute("data-transition-state", this.element.hidden ? "left" : "entered");
259
+ this.#beforeCache.activate();
260
+ this.#settleState();
224
261
  }
225
262
  disconnect() {
263
+ this.#beforeCache.deactivate();
226
264
  this.#cancel();
227
265
  }
228
266
  /** Shows the element with the enter transition. */
@@ -252,6 +290,7 @@ var TransitionController = class extends Controller {
252
290
  const from = isEnter ? this.enterFromValue : this.leaveFromValue;
253
291
  const to = isEnter ? this.enterToValue : this.leaveToValue;
254
292
  this.#add(base, from);
293
+ void this.element.offsetWidth;
255
294
  this.#rafId = this.#raf(() => {
256
295
  this.#rafId = null;
257
296
  this.#remove(from);
@@ -273,6 +312,21 @@ var TransitionController = class extends Controller {
273
312
  this.dispatch("left", { detail: {} });
274
313
  }
275
314
  }
315
+ /** Writes the state hook the element's visibility implies. */
316
+ #settleState() {
317
+ this.element.setAttribute("data-transition-state", this.element.hidden ? "left" : "entered");
318
+ }
319
+ /**
320
+ * Returns the element to a settled state before Turbo copies the page.
321
+ *
322
+ * The snapshot is taken while the controller is still connected, so stripping on
323
+ * the next `connect()` would only repair the page after it has been painted from
324
+ * the cache. The pass is silent: `connect()` derives the state again on restore.
325
+ */
326
+ #rewindForCache() {
327
+ this.#cancel();
328
+ this.#settleState();
329
+ }
276
330
  /** Cancels any in-flight transition (interruption / teardown). */
277
331
  #cancel() {
278
332
  if (this.#rafId !== null) {
@@ -282,24 +336,34 @@ var TransitionController = class extends Controller {
282
336
  this.#transition.cancel();
283
337
  this.#strip();
284
338
  }
339
+ /**
340
+ * Applies the stage tokens this controller does not already find on the
341
+ * element, and claims exactly those.
342
+ *
343
+ * A token already on the element is left unclaimed: it is either the consumer's
344
+ * standing class or one an earlier stage of this transition already claimed, and
345
+ * in neither case may this call take ownership of it. That is what keeps a
346
+ * standing class the consumer also named as a stage Value; the cost is that such
347
+ * a token cannot be staged, so the property it drives resolves from their CSS.
348
+ */
285
349
  #add(...lists) {
286
- const tokens = lists.flatMap(tokensOf);
287
- if (tokens.length > 0) this.element.classList.add(...tokens);
350
+ for (const token of lists.flatMap(tokensOf)) {
351
+ if (this.element.classList.contains(token)) continue;
352
+ this.element.classList.add(token);
353
+ this.#staged.add(token);
354
+ }
288
355
  }
356
+ /** Drops the named tokens that are this controller's to drop. */
289
357
  #remove(...lists) {
290
- const tokens = lists.flatMap(tokensOf);
291
- if (tokens.length > 0) this.element.classList.remove(...tokens);
358
+ for (const token of lists.flatMap(tokensOf)) {
359
+ if (!this.#staged.delete(token)) continue;
360
+ this.element.classList.remove(token);
361
+ }
292
362
  }
293
- /** Removes every stage class so no half-applied state lingers. */
363
+ /** Removes every stage class this controller applied, so none lingers. */
294
364
  #strip() {
295
- this.#remove(
296
- this.enterValue,
297
- this.enterFromValue,
298
- this.enterToValue,
299
- this.leaveValue,
300
- this.leaveFromValue,
301
- this.leaveToValue
302
- );
365
+ this.element.classList.remove(...this.#staged);
366
+ this.#staged.clear();
303
367
  }
304
368
  #raf(callback) {
305
369
  if (typeof window.requestAnimationFrame === "function") {