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,98 +1,188 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/avatar_controller.ts
3
+ function setAttributeIfChanged(element, name, value, beforeWrite) {
4
+ if (element.getAttribute(name) === value) return false;
5
+ if (value === null) element.removeAttribute(name);
6
+ else element.setAttribute(name, value);
7
+ return true;
8
+ }
4
9
 
5
- // src/utils/attribute_lease.ts
10
+ function sharedRegistry(key, create) {
11
+ const symbol = Symbol.for(key);
12
+ const scope = globalThis;
13
+ const existing = scope[symbol];
14
+ if (existing !== void 0) return existing;
15
+ const registry2 = create();
16
+ Object.defineProperty(globalThis, symbol, { value: registry2 });
17
+ return registry2;
18
+ }
19
+
20
+ var registry = sharedRegistry(
21
+ "stimeo-ui.attribute-lease.registry.v1",
22
+ () => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
23
+ );
24
+ function isAttributeValue(value) {
25
+ return value === null || typeof value === "string";
26
+ }
27
+ function readLeaseRecord(element, record) {
28
+ try {
29
+ const parsed = JSON.parse(element.getAttribute(record) ?? "null");
30
+ if (!Array.isArray(parsed)) return void 0;
31
+ const [original, written, ...rest] = parsed;
32
+ const linked = rest[0] !== false;
33
+ const beneath = linked ? rest : rest.slice(1);
34
+ if (!beneath.every((under) => typeof under === "string")) return void 0;
35
+ return isAttributeValue(original) && isAttributeValue(written) ? { original, written, linked, beneath } : void 0;
36
+ } catch {
37
+ return void 0;
38
+ }
39
+ }
40
+ function attributeStack(element, attribute) {
41
+ const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
42
+ registry.stacks.set(element, byAttribute);
43
+ const known = byAttribute.get(attribute);
44
+ if (known) return known;
45
+ const found = [];
46
+ for (const record of registry.names.get(attribute) ?? []) {
47
+ const read = readLeaseRecord(element, record);
48
+ if (read) found.push({ ...read, record });
49
+ }
50
+ const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
51
+ const stack = found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
52
+ lease: null,
53
+ record,
54
+ written,
55
+ original,
56
+ linked: linked && index > 0
57
+ }));
58
+ byAttribute.set(attribute, stack);
59
+ return stack;
60
+ }
61
+ function findHold(stack, lease, record) {
62
+ return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
63
+ }
6
64
  var AttributeLease = class {
7
65
  #attribute;
8
- #records = /* @__PURE__ */ new Map();
9
- /** @param attribute - The attribute whose temporary values this lease owns. */
10
- constructor(attribute) {
66
+ #record;
67
+ #base;
68
+ #preserveAuthor;
69
+ #held = /* @__PURE__ */ new Set();
70
+ constructor(attribute, owner, options = {}) {
11
71
  this.#attribute = attribute;
72
+ this.#record = `data-${owner}-${attribute}-lease`;
73
+ this.#base = options.base === true;
74
+ this.#preserveAuthor = options.preserveAuthor === true;
75
+ const names = registry.names;
76
+ names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
12
77
  }
13
- /** Writes or removes the leased attribute while preserving its authored value. */
14
78
  write(element, value) {
15
- const existing = this.#records.get(element);
16
- if (existing) {
17
- existing.written = value;
18
- } else {
19
- this.#records.set(element, {
20
- original: element.getAttribute(this.#attribute),
21
- written: value
22
- });
23
- }
24
- this.#reflect(element, value);
79
+ const stack = attributeStack(element, this.#attribute);
80
+ const hold = this.#take(stack) ?? this.#acquire(element, stack);
81
+ this.#held.add(element);
82
+ const shows = !this.#covered(element, stack, hold);
83
+ hold.written = value;
84
+ this.#mark(element, stack);
85
+ if (shows) this.#reflect(element, value);
25
86
  }
26
- /** Returns one lease without overwriting a value subsequently authored by a consumer. */
27
87
  return(element) {
28
- const record = this.#records.get(element);
29
- if (!record) return;
30
- this.#records.delete(element);
31
- const stillOwned = element.getAttribute(this.#attribute) === record.written;
32
- if (stillOwned) this.#reflect(element, record.original);
88
+ const held = this.#held.delete(element);
89
+ const known = registry.stacks.get(element)?.has(this.#attribute);
90
+ const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
91
+ const hold = this.#take(stack);
92
+ if (!hold) return false;
93
+ const carries = element.getAttribute(this.#attribute) === hold.written;
94
+ const owns = carries && !this.#covered(element, stack, hold);
95
+ const index = stack.indexOf(hold);
96
+ stack.splice(index, 1);
97
+ const above = stack[index];
98
+ if (above) above.linked &&= hold.linked;
99
+ this.#mark(element, stack);
100
+ if (!owns) return true;
101
+ const below = hold.linked ? stack[index - 1] : void 0;
102
+ this.#reflect(element, below ? below.written : hold.original);
103
+ return true;
33
104
  }
34
- /** Reflects only a real value transition, avoiding self-triggered mutation work. */
35
- #reflect(element, value) {
36
- if (element.getAttribute(this.#attribute) === value) return;
37
- if (value === null) element.removeAttribute(this.#attribute);
38
- else element.setAttribute(this.#attribute, value);
39
- }
40
- /** Returns every outstanding lease using the same ownership check as {@link return}. */
41
105
  returnAll() {
42
- for (const element of Array.from(this.#records.keys())) this.return(element);
106
+ for (const element of Array.from(this.#held)) this.return(element);
107
+ }
108
+ #take(stack) {
109
+ const hold = findHold(stack, this, this.#record);
110
+ if (hold) hold.lease = this;
111
+ return hold;
112
+ }
113
+ #acquire(element, stack) {
114
+ const current = element.getAttribute(this.#attribute);
115
+ const top = stack.at(-1);
116
+ const bottom = stack[0];
117
+ const over = top?.written === current ? top : void 0;
118
+ const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
119
+ const hold = {
120
+ lease: this,
121
+ record: this.#record,
122
+ written: current,
123
+ original: from ? from.original : current,
124
+ linked: !this.#base && over !== void 0
125
+ };
126
+ if (this.#base && bottom) {
127
+ bottom.linked = true;
128
+ stack.unshift(hold);
129
+ } else stack.push(hold);
130
+ return hold;
131
+ }
132
+ #covered(element, stack, hold) {
133
+ const current = element.getAttribute(this.#attribute);
134
+ return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);
135
+ }
136
+ #mark(element, stack) {
137
+ const records = /* @__PURE__ */ new Map([[this.#record, null]]);
138
+ stack.forEach((hold, index) => {
139
+ const names = stack.slice(0, index).map((under) => under.record);
140
+ const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
141
+ const marker = hold.linked || beneath.length === 0 ? [] : [false];
142
+ records.set(
143
+ hold.record,
144
+ hold.written === hold.original && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.original, hold.written, ...marker, ...beneath])
145
+ );
146
+ });
147
+ for (const [name, recorded] of records) {
148
+ setAttributeIfChanged(element, name, recorded);
149
+ }
150
+ }
151
+ #reflect(element, value) {
152
+ setAttributeIfChanged(element, this.#attribute, value);
43
153
  }
44
154
  };
45
155
 
46
- // src/utils/before_cache_reset.ts
47
- var BeforeCacheReset = class _BeforeCacheReset {
48
- /** Every subscribed instance, iterated by the one shared document listener. */
49
- static #subscribers = /* @__PURE__ */ new Set();
50
- /** The shared listener; installed while at least one instance is subscribed. */
51
- static #onBeforeCache = () => {
52
- for (const subscriber of _BeforeCacheReset.#subscribers) subscriber.#rewind();
53
- };
54
- #rewind;
55
- /** @param rewind - the pass that returns this controller's state to its initial form. */
56
- constructor(rewind) {
57
- this.#rewind = rewind;
58
- }
59
- /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */
60
- activate() {
61
- const first = _BeforeCacheReset.#subscribers.size === 0;
62
- _BeforeCacheReset.#subscribers.add(this);
63
- if (first) {
64
- document.addEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
65
- }
156
+ var ListenerSet = class {
157
+ #abort = new AbortController();
158
+ add(target, type, handler, options) {
159
+ target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
66
160
  }
67
- /** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */
68
- deactivate() {
69
- _BeforeCacheReset.#subscribers.delete(this);
70
- if (_BeforeCacheReset.#subscribers.size > 0) return;
71
- document.removeEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
161
+ dispose() {
162
+ this.#abort.abort();
163
+ this.#abort = new AbortController();
72
164
  }
73
165
  };
74
166
 
75
- // src/utils/microtask_coalescer.ts
76
167
  var MicrotaskCoalescer = class {
77
168
  #run;
78
169
  #queued = false;
79
170
  #active = false;
80
171
  #generation = 0;
81
- /** @param run - the single reconciliation pass, invoked at most once per batch. */
82
172
  constructor(run) {
83
173
  this.#run = run;
84
174
  }
85
- /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
86
175
  activate() {
87
176
  this.#active = true;
88
177
  }
89
- /** Closes the window and drops any pending pass; call from `disconnect()`. */
90
178
  cancel() {
91
179
  this.#active = false;
92
180
  this.#queued = false;
93
181
  this.#generation += 1;
94
182
  }
95
- /** Requests one pass after the batch settles. Idempotent; inert outside the window. */
183
+ get pending() {
184
+ return this.#queued;
185
+ }
96
186
  schedule() {
97
187
  if (!this.#active || this.#queued) return;
98
188
  this.#queued = true;
@@ -105,32 +195,52 @@ var MicrotaskCoalescer = class {
105
195
  }
106
196
  };
107
197
 
108
- // src/controllers/avatar_controller.ts
198
+ var MorphRenderWatcher = class {
199
+ #listeners = new ListenerSet();
200
+ #pass;
201
+ #element = null;
202
+ #onMorph = () => this.#pass.schedule();
203
+ constructor(run) {
204
+ this.#pass = new MicrotaskCoalescer(run);
205
+ }
206
+ observe(element) {
207
+ if (this.#element === element) return;
208
+ this.disconnect();
209
+ this.#element = element;
210
+ this.#pass.activate();
211
+ this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
212
+ }
213
+ schedule() {
214
+ this.#pass.schedule();
215
+ }
216
+ get pending() {
217
+ return this.#pass.pending;
218
+ }
219
+ disconnect() {
220
+ this.#listeners.dispose();
221
+ this.#pass.cancel();
222
+ this.#element = null;
223
+ }
224
+ };
225
+
109
226
  var AvatarController = class extends Controller {
110
227
  static targets = ["image", "fallback"];
111
228
  static values = { src: String };
112
229
  static actions = ["onError", "onLoad"];
113
230
  static events = ["error"];
114
- /** Collapses one morph's Value, target, and direct-attribute signals into one pass. */
115
- #reconcile = new MicrotaskCoalescer(() => this.#render());
116
- /** Preserves directly-authored source and visibility while targets are controlled. */
117
- #beforeCache = new BeforeCacheReset(() => this.#rewindForCache());
118
- #src = new AttributeLease("src");
119
- #imageHidden = new AttributeLease("hidden");
120
- #fallbackHidden = new AttributeLease("hidden");
121
- /** True only while target departure means ownership was actually relinquished. */
231
+ #reconcile = new MorphRenderWatcher(() => this.#render());
232
+ #src = new AttributeLease("src", this.identifier);
233
+ #imageHidden = new AttributeLease("hidden", this.identifier);
234
+ #fallbackHidden = new AttributeLease("hidden", this.identifier);
122
235
  #connected = false;
123
- /** Watches the non-Value render input used by the direct `<img src>` form. */
124
236
  #srcObserver = new MutationObserver((records) => {
125
237
  if (records.some((record) => this.hasImageTarget && record.target === this.imageTarget)) {
126
238
  this.#reconcile.schedule();
127
239
  }
128
240
  });
129
- /** Starts retained-DOM observation and silently derives the current phase. */
130
241
  connect() {
131
242
  this.#connected = true;
132
- this.#reconcile.activate();
133
- this.#beforeCache.activate();
243
+ this.#reconcile.observe(this.element);
134
244
  this.#srcObserver.observe(this.element, {
135
245
  attributes: true,
136
246
  attributeFilter: ["src"],
@@ -138,22 +248,17 @@ var AvatarController = class extends Controller {
138
248
  });
139
249
  this.#render();
140
250
  }
141
- /** Cancels asynchronous work while retaining the last materialized visual state. */
142
251
  disconnect() {
143
252
  this.#connected = false;
144
- this.#reconcile.cancel();
145
- this.#beforeCache.deactivate();
253
+ this.#reconcile.disconnect();
146
254
  this.#srcObserver.disconnect();
147
255
  }
148
- /** Repaints when application code or a Turbo morph changes the source Value. */
149
256
  srcValueChanged() {
150
257
  this.#reconcile.schedule();
151
258
  }
152
- /** Applies the current source and phase to an image inserted or replaced at runtime. */
153
259
  imageTargetConnected() {
154
260
  this.#reconcile.schedule();
155
261
  }
156
- /** Returns attributes borrowed from an image that leaves this live avatar. */
157
262
  imageTargetDisconnected(image) {
158
263
  if (this.#connected) {
159
264
  this.#src.return(image);
@@ -161,16 +266,13 @@ var AvatarController = class extends Controller {
161
266
  }
162
267
  this.#reconcile.schedule();
163
268
  }
164
- /** Applies the current phase to a fallback inserted or replaced at runtime. */
165
269
  fallbackTargetConnected() {
166
270
  this.#reconcile.schedule();
167
271
  }
168
- /** Returns authored visibility when a fallback leaves this live avatar. */
169
272
  fallbackTargetDisconnected(fallback) {
170
273
  if (this.#connected) this.#fallbackHidden.return(fallback);
171
274
  this.#reconcile.schedule();
172
275
  }
173
- /** Reveals the current image after its native `load` event. */
174
276
  onLoad(event) {
175
277
  const image = this.#eventImage(event);
176
278
  if (!image) return;
@@ -180,12 +282,6 @@ var AvatarController = class extends Controller {
180
282
  }
181
283
  this.#reflect("loaded");
182
284
  }
183
- /**
184
- * Reveals the fallback after the current image's native `error` event.
185
- *
186
- * Dispatches `stimeo--avatar:error` with `{ src: string }`, where `src` is
187
- * the attempted attribute value. Empty/stale/detached image events are ignored.
188
- */
189
285
  onError(event) {
190
286
  const image = this.#eventImage(event);
191
287
  if (!image) return;
@@ -197,14 +293,6 @@ var AvatarController = class extends Controller {
197
293
  this.#reflect("error");
198
294
  this.dispatch("error", { detail: { src } });
199
295
  }
200
- /**
201
- * Materializes the phase from the final source/target DOM after one mutation batch.
202
- *
203
- * Cached success and failure are state reconstruction, not new load events, so
204
- * this pass never dispatches the public `error` event.
205
- *
206
- * @stimeoRenderRoot
207
- */
208
296
  #render() {
209
297
  if (!this.hasImageTarget) {
210
298
  this.#reflect("empty");
@@ -222,24 +310,21 @@ var AvatarController = class extends Controller {
222
310
  }
223
311
  this.#reflect(image.naturalWidth > 0 ? "loaded" : "error");
224
312
  }
225
- /** Applies Value precedence and returns the effective raw `src` attribute. */
226
313
  #applySource(image) {
227
314
  if (!this.element.hasAttribute(`data-${this.identifier}-src-value`)) {
228
315
  this.#src.return(image);
229
316
  return image.getAttribute("src");
230
317
  }
231
318
  const desired = this.srcValue.length > 0 ? this.srcValue : null;
232
- if (image.getAttribute("src") !== desired) this.#src.write(image, desired);
319
+ this.#src.write(image, desired);
233
320
  return desired;
234
321
  }
235
- /** Accepts an action only from the singular image target currently controlled. */
236
322
  #eventImage(event) {
237
323
  const candidate = event.currentTarget;
238
324
  if (!(candidate instanceof HTMLImageElement)) return null;
239
325
  if (!this.hasImageTarget || candidate !== this.imageTarget) return null;
240
326
  return candidate;
241
327
  }
242
- /** Writes the visibility pair and public root state as one controller-owned output. */
243
328
  #reflect(state) {
244
329
  const showImage = state === "loading" || state === "loaded";
245
330
  if (this.hasImageTarget) {
@@ -250,14 +335,7 @@ var AvatarController = class extends Controller {
250
335
  }
251
336
  this.element.setAttribute("data-state", state);
252
337
  }
253
- /** Returns borrowed image and fallback semantics before Turbo snapshots the page. */
254
- #rewindForCache() {
255
- this.#src.returnAll();
256
- this.#imageHidden.returnAll();
257
- this.#fallbackHidden.returnAll();
258
- }
259
338
  };
260
339
 
261
340
  export { AvatarController };
262
- //# sourceMappingURL=avatar_controller.js.map
263
341
  //# sourceMappingURL=avatar_controller.js.map