stimeo-ui 0.15.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 +209 -0
  3. data/README.md +128 -1
  4. data/dist/cable/index.js +392 -417
  5. data/dist/controllers/accordion_controller.js +228 -28
  6. data/dist/controllers/alert_dialog_controller.js +862 -221
  7. data/dist/controllers/announcer_controller.js +135 -191
  8. data/dist/controllers/aspect_ratio_controller.js +0 -10
  9. data/dist/controllers/auto_submit_controller.js +295 -110
  10. data/dist/controllers/avatar_controller.js +172 -106
  11. data/dist/controllers/breadcrumb_controller.js +0 -129
  12. data/dist/controllers/bulk_select_controller.js +264 -53
  13. data/dist/controllers/calendar_controller.js +346 -180
  14. data/dist/controllers/carousel_controller.js +587 -300
  15. data/dist/controllers/character_counter_controller.js +271 -143
  16. data/dist/controllers/checkbox_controller.js +77 -75
  17. data/dist/controllers/clipboard_controller.js +187 -108
  18. data/dist/controllers/collapsible_controller.js +374 -108
  19. data/dist/controllers/color_picker_controller.js +183 -127
  20. data/dist/controllers/combobox_controller.js +426 -109
  21. data/dist/controllers/command_palette_controller.js +994 -350
  22. data/dist/controllers/conditional_fields_controller.js +212 -125
  23. data/dist/controllers/confirm_controller.js +939 -245
  24. data/dist/controllers/context_menu_controller.js +275 -127
  25. data/dist/controllers/count_up_controller.js +73 -21
  26. data/dist/controllers/countdown_controller.js +235 -97
  27. data/dist/controllers/currency_input_controller.js +241 -118
  28. data/dist/controllers/data_grid_controller.js +229 -135
  29. data/dist/controllers/date_range_picker_controller.js +359 -165
  30. data/dist/controllers/dialog_controller.js +887 -225
  31. data/dist/controllers/direct_upload_controller.js +80 -142
  32. data/dist/controllers/dirty_form_controller.js +26 -47
  33. data/dist/controllers/dismissible_controller.js +175 -20
  34. data/dist/controllers/drawer_controller.js +963 -336
  35. data/dist/controllers/dropdown_controller.js +342 -85
  36. data/dist/controllers/editable_controller.js +182 -58
  37. data/dist/controllers/empty_state_controller.js +67 -53
  38. data/dist/controllers/file_dropzone_controller.js +426 -229
  39. data/dist/controllers/filter_controller.js +78 -36
  40. data/dist/controllers/flash_controller.js +328 -211
  41. data/dist/controllers/focus_controller.js +654 -239
  42. data/dist/controllers/form_field_controller.js +153 -136
  43. data/dist/controllers/form_validation_controller.js +29 -96
  44. data/dist/controllers/frame_loading_controller.js +263 -198
  45. data/dist/controllers/highlight_controller.js +119 -70
  46. data/dist/controllers/hover_card_controller.js +335 -118
  47. data/dist/controllers/idle_controller.js +316 -65
  48. data/dist/controllers/input_mask_controller.js +116 -61
  49. data/dist/controllers/intersection_controller.js +147 -103
  50. data/dist/controllers/lazy_frame_controller.js +9 -56
  51. data/dist/controllers/listbox_controller.js +413 -153
  52. data/dist/controllers/local_time_controller.js +54 -64
  53. data/dist/controllers/masonry_controller.js +70 -95
  54. data/dist/controllers/menu_controller.js +254 -167
  55. data/dist/controllers/menubar_controller.js +206 -331
  56. data/dist/controllers/meter_controller.js +159 -71
  57. data/dist/controllers/multi_select_controller.js +797 -388
  58. data/dist/controllers/navigation_menu_controller.js +156 -231
  59. data/dist/controllers/nested_form_controller.js +373 -174
  60. data/dist/controllers/network_status_controller.js +241 -45
  61. data/dist/controllers/number_input_controller.js +387 -227
  62. data/dist/controllers/optimistic_controller.js +28 -75
  63. data/dist/controllers/otp_controller.js +344 -196
  64. data/dist/controllers/overflow_indicator_controller.js +167 -93
  65. data/dist/controllers/overflow_menu_controller.js +408 -277
  66. data/dist/controllers/pagination_controller.js +342 -120
  67. data/dist/controllers/password_reveal_controller.js +424 -99
  68. data/dist/controllers/password_strength_controller.js +99 -153
  69. data/dist/controllers/persist_controller.js +252 -96
  70. data/dist/controllers/pointer_drag_controller.js +263 -164
  71. data/dist/controllers/popover_controller.js +267 -94
  72. data/dist/controllers/portal_controller.js +209 -72
  73. data/dist/controllers/preview_guard_controller.js +243 -112
  74. data/dist/controllers/progress_controller.js +132 -59
  75. data/dist/controllers/radio_group_controller.js +138 -133
  76. data/dist/controllers/range_slider_controller.js +245 -112
  77. data/dist/controllers/rating_controller.js +429 -194
  78. data/dist/controllers/read_more_controller.js +185 -47
  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 +294 -118
  83. data/dist/controllers/roving_controller.js +39 -84
  84. data/dist/controllers/scroll_area_controller.js +428 -221
  85. data/dist/controllers/scroll_restore_controller.js +0 -53
  86. data/dist/controllers/scroll_visibility_controller.js +395 -146
  87. data/dist/controllers/scrollspy_controller.js +181 -236
  88. data/dist/controllers/separator_controller.js +288 -132
  89. data/dist/controllers/sidebar_controller.js +1071 -375
  90. data/dist/controllers/skeleton_controller.js +248 -92
  91. data/dist/controllers/slider_controller.js +211 -96
  92. data/dist/controllers/smart_sticky_header_controller.js +163 -54
  93. data/dist/controllers/sortable_controller.js +13 -110
  94. data/dist/controllers/spinner_controller.js +277 -161
  95. data/dist/controllers/step_indicator_controller.js +107 -53
  96. data/dist/controllers/stepper_controller.js +171 -48
  97. data/dist/controllers/stick_to_bottom_controller.js +310 -116
  98. data/dist/controllers/sticky_observer_controller.js +214 -49
  99. data/dist/controllers/submit_once_controller.js +294 -192
  100. data/dist/controllers/switch_controller.js +107 -43
  101. data/dist/controllers/tabs_controller.js +50 -25
  102. data/dist/controllers/tags_input_controller.js +290 -149
  103. data/dist/controllers/textarea_autosize_controller.js +71 -58
  104. data/dist/controllers/theme_controller.js +148 -80
  105. data/dist/controllers/time_picker_controller.js +162 -81
  106. data/dist/controllers/toast_controller.js +365 -193
  107. data/dist/controllers/toggle_group_controller.js +194 -99
  108. data/dist/controllers/toolbar_controller.js +92 -90
  109. data/dist/controllers/tooltip_controller.js +185 -125
  110. data/dist/controllers/transition_controller.js +123 -115
  111. data/dist/controllers/tree_view_controller.js +248 -290
  112. data/dist/index.js +8649 -8572
  113. data/dist/positioning/index.js +148 -45
  114. data/lib/stimeo/ui/version.rb +1 -1
  115. metadata +3 -3
@@ -1,108 +1,264 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/preview_guard_controller.ts
3
+ var ListenerSet = class {
4
+ #abort = new AbortController();
5
+ add(target, type, handler, options) {
6
+ target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
7
+ }
8
+ dispose() {
9
+ this.#abort.abort();
10
+ this.#abort = new AbortController();
11
+ }
12
+ };
4
13
 
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;
14
+ var MicrotaskCoalescer = class {
15
+ #run;
16
+ #queued = false;
17
+ #active = false;
18
+ #generation = 0;
19
+ constructor(run) {
20
+ this.#run = run;
17
21
  }
18
- /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */
19
22
  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
- }
23
+ this.#active = true;
24
+ }
25
+ cancel() {
26
+ this.#active = false;
27
+ this.#queued = false;
28
+ this.#generation += 1;
25
29
  }
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);
30
+ schedule() {
31
+ if (!this.#active || this.#queued) return;
32
+ this.#queued = true;
33
+ const generation = this.#generation;
34
+ queueMicrotask(() => {
35
+ if (generation !== this.#generation || !this.#queued || !this.#active) return;
36
+ this.#queued = false;
37
+ this.#run();
38
+ });
31
39
  }
32
40
  };
33
41
 
34
- // src/utils/style_property_lease.ts
35
- var StylePropertyLease = class {
42
+ var MorphRenderWatcher = class {
43
+ #listeners = new ListenerSet();
44
+ #pass;
45
+ #element = null;
46
+ #onMorph = () => this.#pass.schedule();
47
+ constructor(run) {
48
+ this.#pass = new MicrotaskCoalescer(run);
49
+ }
50
+ observe(element) {
51
+ if (this.#element === element) return;
52
+ this.disconnect();
53
+ this.#element = element;
54
+ this.#pass.activate();
55
+ this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
56
+ }
57
+ schedule() {
58
+ this.#pass.schedule();
59
+ }
60
+ disconnect() {
61
+ this.#listeners.dispose();
62
+ this.#pass.cancel();
63
+ this.#element = null;
64
+ }
65
+ };
66
+
67
+ function sharedRegistry(key, create) {
68
+ const symbol = Symbol.for(key);
69
+ const scope = globalThis;
70
+ const existing = scope[symbol];
71
+ if (existing !== void 0) return existing;
72
+ const registry = create();
73
+ Object.defineProperty(globalThis, symbol, { value: registry });
74
+ return registry;
75
+ }
76
+
77
+ var StylePropertyLease = class _StylePropertyLease {
78
+ static #registry = sharedRegistry(
79
+ "stimeo-ui.style-property-lease.registry.v1",
80
+ () => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
81
+ );
36
82
  #property;
37
- #records = /* @__PURE__ */ new Map();
38
- /** @param property - The CSS property whose temporary values this lease owns. */
39
- constructor(property) {
83
+ #record;
84
+ #held = /* @__PURE__ */ new Set();
85
+ constructor(property, owner) {
40
86
  this.#property = property;
87
+ this.#record = `data-${owner}-style-${property}-lease`;
88
+ const names = _StylePropertyLease.#registry.names;
89
+ names.set(property, (names.get(property) ?? /* @__PURE__ */ new Set()).add(this.#record));
41
90
  }
42
- /** Writes or removes the leased declaration while preserving its authored value. */
43
91
  write(element, value, priority = "") {
44
- const existing = this.#records.get(element);
45
- if (existing) {
46
- existing.writtenValue = value;
47
- existing.writtenPriority = value === null ? "" : priority;
48
- } else {
49
- this.#records.set(element, {
50
- originalValue: element.style.getPropertyValue(this.#property),
51
- originalPriority: element.style.getPropertyPriority(this.#property),
52
- writtenValue: value,
53
- writtenPriority: value === null ? "" : priority
54
- });
55
- }
56
- this.#reflect(element, value, priority);
92
+ const stack = this.#stack(element);
93
+ const hold = this.#take(stack) ?? this.#acquire(element, stack);
94
+ this.#held.add(element);
95
+ const shows = !this.#covered(element, stack, hold);
96
+ hold.writtenValue = value;
97
+ hold.writtenPriority = value === null ? "" : priority;
98
+ this.#mark(element, stack);
99
+ if (shows) this.#show(element, value, hold.writtenPriority);
57
100
  }
58
- /** Returns one lease without overwriting a later consumer declaration. */
59
101
  return(element) {
60
- const record = this.#records.get(element);
61
- if (!record) return;
62
- this.#records.delete(element);
63
- const style = element.style;
64
- const stillOwned = style.getPropertyValue(this.#property) === (record.writtenValue ?? "") && style.getPropertyPriority(this.#property) === record.writtenPriority;
65
- if (stillOwned) {
66
- this.#reflect(element, record.originalValue, record.originalPriority);
67
- }
102
+ const held = this.#held.delete(element);
103
+ const known = _StylePropertyLease.#registry.stacks.get(element)?.has(this.#property);
104
+ const stack = held || known || element.hasAttribute(this.#record) ? this.#stack(element) : [];
105
+ const hold = this.#take(stack);
106
+ if (!hold) return;
107
+ const owns = this.#carries(element, hold) && !this.#covered(element, stack, hold);
108
+ const index = stack.indexOf(hold);
109
+ stack.splice(index, 1);
110
+ const above = stack[index];
111
+ if (above) above.linked &&= hold.linked;
112
+ this.#mark(element, stack);
113
+ if (!owns) return;
114
+ const below = hold.linked ? stack[index - 1] : void 0;
115
+ if (below) this.#show(element, below.writtenValue, below.writtenPriority);
116
+ else this.#show(element, hold.originalValue, hold.originalPriority);
68
117
  }
69
- /** Returns every outstanding declaration lease. */
70
118
  returnAll() {
71
- for (const element of Array.from(this.#records.keys())) this.return(element);
119
+ for (const element of Array.from(this.#held)) this.return(element);
120
+ }
121
+ #recorded(element, name) {
122
+ try {
123
+ const parsed = JSON.parse(element.getAttribute(name) ?? "null");
124
+ if (!Array.isArray(parsed)) return null;
125
+ const [originalValue, originalPriority, writtenValue, writtenPriority, ...rest] = parsed;
126
+ if (typeof originalValue !== "string" || typeof originalPriority !== "string") return null;
127
+ if (typeof writtenValue !== "string" && writtenValue !== null) return null;
128
+ if (typeof writtenPriority !== "string") return null;
129
+ const linked = rest[0] !== false;
130
+ const beneath = linked ? rest : rest.slice(1);
131
+ if (!beneath.every((under) => typeof under === "string")) return null;
132
+ return { originalValue, originalPriority, writtenValue, writtenPriority, linked, beneath };
133
+ } catch {
134
+ return null;
135
+ }
136
+ }
137
+ #stack(element) {
138
+ const stacks = _StylePropertyLease.#registry.stacks;
139
+ const byProperty = stacks.get(element) ?? /* @__PURE__ */ new Map();
140
+ stacks.set(element, byProperty);
141
+ const stack = byProperty.get(this.#property) ?? this.#seed(element);
142
+ byProperty.set(this.#property, stack);
143
+ return stack;
144
+ }
145
+ #seed(element) {
146
+ const found = [];
147
+ for (const record of _StylePropertyLease.#registry.names.get(this.#property) ?? []) {
148
+ const read = this.#recorded(element, record);
149
+ if (read) found.push({ ...read, record });
150
+ }
151
+ const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
152
+ return found.sort((one, other) => depth(one) - depth(other)).map((entry, index) => ({
153
+ lease: null,
154
+ record: entry.record,
155
+ writtenValue: entry.writtenValue,
156
+ writtenPriority: entry.writtenPriority,
157
+ originalValue: entry.originalValue,
158
+ originalPriority: entry.originalPriority,
159
+ linked: entry.linked && index > 0
160
+ }));
161
+ }
162
+ #take(stack) {
163
+ const hold = stack.find((held) => held.lease === this) ?? stack.find((held) => held.lease === null && held.record === this.#record);
164
+ if (hold) hold.lease = this;
165
+ return hold;
72
166
  }
73
- /** Reflects only a real declaration transition. */
74
- #reflect(element, value, priority) {
167
+ #acquire(element, stack) {
168
+ const top = stack.at(-1);
169
+ const over = top && this.#carries(element, top) ? top : void 0;
75
170
  const style = element.style;
76
- const nextValue = value ?? "";
77
- const nextPriority = value === null ? "" : priority;
78
- if (style.getPropertyValue(this.#property) === nextValue && style.getPropertyPriority(this.#property) === nextPriority) {
79
- return;
171
+ const hold = {
172
+ lease: this,
173
+ record: this.#record,
174
+ writtenValue: null,
175
+ writtenPriority: "",
176
+ originalValue: over ? over.originalValue : style.getPropertyValue(this.#property),
177
+ originalPriority: over ? over.originalPriority : style.getPropertyPriority(this.#property),
178
+ linked: over !== void 0
179
+ };
180
+ stack.push(hold);
181
+ return hold;
182
+ }
183
+ #covered(element, stack, hold) {
184
+ return stack.slice(stack.indexOf(hold) + 1).some((above) => this.#carries(element, above));
185
+ }
186
+ #mark(element, stack) {
187
+ const records = /* @__PURE__ */ new Map([[this.#record, null]]);
188
+ stack.forEach((hold, index) => {
189
+ const names = stack.slice(0, index).map((under) => under.record);
190
+ const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
191
+ const marker = hold.linked || beneath.length === 0 ? [] : [false];
192
+ const { originalValue, originalPriority, writtenValue, writtenPriority } = hold;
193
+ records.set(
194
+ hold.record,
195
+ (writtenValue ?? "") === originalValue && writtenPriority === originalPriority && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([
196
+ originalValue,
197
+ originalPriority,
198
+ writtenValue,
199
+ writtenPriority,
200
+ ...marker,
201
+ ...beneath
202
+ ])
203
+ );
204
+ });
205
+ for (const [name, recorded] of records) {
206
+ if (element.getAttribute(name) === recorded) continue;
207
+ if (recorded === null) element.removeAttribute(name);
208
+ else element.setAttribute(name, recorded);
80
209
  }
81
- if (value === null) style.removeProperty(this.#property);
82
- else style.setProperty(this.#property, value, priority);
210
+ }
211
+ #carries(element, hold) {
212
+ return this.#holds(element, hold.writtenValue ?? "", hold.writtenPriority);
213
+ }
214
+ #holds(element, value, priority) {
215
+ const style = element.style;
216
+ return style.getPropertyValue(this.#property) === value && style.getPropertyPriority(this.#property) === priority;
217
+ }
218
+ #show(element, value, priority) {
219
+ if (this.#holds(element, value ?? "", priority)) return;
220
+ if (value === null) element.style.removeProperty(this.#property);
221
+ else element.style.setProperty(this.#property, value, priority);
83
222
  }
84
223
  };
85
224
 
86
- // src/controllers/preview_guard_controller.ts
225
+ var TransientHooks = class {
226
+ #attributes;
227
+ constructor(options) {
228
+ this.#attributes = options.attributes;
229
+ }
230
+ reset(element) {
231
+ for (const attribute of this.#attributes) element.removeAttribute(attribute);
232
+ }
233
+ };
234
+
235
+ var TRANSIENT = new TransientHooks({ attributes: ["data-preview-hidden"] });
236
+ var CONTENT_RECORD = "content";
87
237
  var PreviewGuardController = class extends Controller {
88
238
  static values = {
89
239
  placeholder: { type: String, default: "" }
90
240
  };
91
241
  static events = ["hide", "show"];
92
- #visibility = new StylePropertyLease("visibility");
93
- #beforeCache = new BeforeCacheReset(() => this.#restore());
242
+ #visibility = new StylePropertyLease("visibility", this.identifier);
94
243
  #observer = null;
95
244
  #connected = false;
96
245
  #hidden = false;
97
- /** Child nodes a placeholder displaced; non-null marks that content — not visibility — was swapped. */
98
246
  #savedNodes = null;
99
- /** The descendant that held focus when the guard went up, so show can hand it back. */
100
247
  #focused = null;
248
+ #morphRender = new MorphRenderWatcher(() => {
249
+ this.#sync();
250
+ if (this.#hidden) this.#reguard();
251
+ });
101
252
  connect() {
253
+ this.#morphRender.observe(this.element);
102
254
  this.#connected = true;
103
- if (this.#hidden) this.#reguard();
104
- else this.element.removeAttribute("data-preview-hidden");
105
- this.#beforeCache.activate();
255
+ if (this.#hidden) {
256
+ this.#reguard();
257
+ } else {
258
+ if (this.element.hasAttribute("data-preview-hidden")) this.#restoreRecordedContent();
259
+ this.#visibility.return(this.element);
260
+ TRANSIENT.reset(this.element);
261
+ }
106
262
  if (typeof MutationObserver !== "undefined") {
107
263
  this.#observer = new MutationObserver(() => this.#sync());
108
264
  this.#observer.observe(document.documentElement, {
@@ -113,24 +269,15 @@ var PreviewGuardController = class extends Controller {
113
269
  this.#sync();
114
270
  }
115
271
  disconnect() {
272
+ this.#morphRender.disconnect();
116
273
  this.#connected = false;
117
- this.#beforeCache.deactivate();
118
274
  this.#observer?.disconnect();
119
275
  this.#observer = null;
120
276
  }
121
- /**
122
- * Re-guards to match a `placeholder` changed at runtime — the value is the content on
123
- * display while the guard is up, so a morph that swaps it must not leave the old one.
124
- */
125
277
  placeholderValueChanged() {
126
278
  if (!this.#connected || !this.#hidden) return;
127
279
  this.#reguard();
128
280
  }
129
- /**
130
- * Reflects the current `data-turbo-preview` state onto the element.
131
- *
132
- * @stimeoRenderRoot
133
- */
134
281
  #sync() {
135
282
  const previewing = document.documentElement.hasAttribute("data-turbo-preview");
136
283
  if (previewing && !this.#hidden) this.#hide();
@@ -141,28 +288,33 @@ var PreviewGuardController = class extends Controller {
141
288
  this.#applyGuard();
142
289
  this.dispatch("hide", { detail: {} });
143
290
  }
144
- /** Puts the guard up in the form the current `placeholder` calls for. */
145
291
  #applyGuard() {
146
292
  this.#hidden = true;
147
293
  if (this.placeholderValue === "") {
148
294
  this.#visibility.write(this.element, "hidden");
149
295
  } else {
296
+ this.element.setAttribute(this.#contentRecord, JSON.stringify(this.element.innerHTML));
150
297
  this.#savedNodes = document.createDocumentFragment();
151
298
  this.#savedNodes.append(...this.element.childNodes);
152
299
  this.element.textContent = this.placeholderValue;
153
300
  }
154
301
  this.element.setAttribute("data-preview-hidden", "true");
155
302
  }
156
- /**
157
- * Re-forms a guard that is already up so it matches the current `placeholder`.
158
- *
159
- * No event: `hide` reports that the guard went up, and it has not come down. Swapping
160
- * one stand-in text for another writes only that text — putting the held content back
161
- * first would reconnect the whole subtree for an instant. Only a change of *form* —
162
- * to or from the empty placeholder — has to revert, and the focus the guard is holding
163
- * carries across it rather than being handed back and taken again.
164
- */
303
+ get #contentRecord() {
304
+ return `data-${this.identifier}-${CONTENT_RECORD}`;
305
+ }
306
+ #restoreRecordedContent() {
307
+ const raw = this.element.getAttribute(this.#contentRecord) ?? "null";
308
+ this.element.removeAttribute(this.#contentRecord);
309
+ let content = null;
310
+ try {
311
+ content = JSON.parse(raw);
312
+ } catch {
313
+ }
314
+ if (typeof content === "string") this.element.innerHTML = content;
315
+ }
165
316
  #reguard() {
317
+ this.element.setAttribute("data-preview-hidden", "true");
166
318
  if (this.#savedNodes && this.placeholderValue !== "") {
167
319
  this.element.textContent = this.placeholderValue;
168
320
  return;
@@ -176,46 +328,26 @@ var PreviewGuardController = class extends Controller {
176
328
  this.#restore();
177
329
  this.dispatch("show", { detail: {} });
178
330
  }
179
- /** Reverts the guard and hands focus back. Used by show and by the snapshot rewind. */
180
331
  #restore() {
181
332
  this.#revert();
182
333
  this.#refocus();
183
334
  }
184
- /**
185
- * Puts the element back the way the guard found it.
186
- *
187
- * Every step is a no-op on an element this controller never guarded: the lease returns
188
- * only declarations it recorded, and the hook is removed whether or not it is there.
189
- */
190
335
  #revert() {
191
336
  this.#hidden = false;
192
337
  if (this.#savedNodes) {
193
338
  this.element.textContent = "";
194
339
  this.element.append(this.#savedNodes);
195
340
  this.#savedNodes = null;
341
+ this.element.removeAttribute(this.#contentRecord);
196
342
  } else {
197
343
  this.#visibility.return(this.element);
198
344
  }
199
345
  this.element.removeAttribute("data-preview-hidden");
200
346
  }
201
- /**
202
- * The focused element the guard is about to make unfocusable, if any.
203
- *
204
- * The element itself counts as well as its descendants: guarding takes focus either way
205
- * — a `visibility: hidden` subtree cannot hold it, and a placeholder displaces the nodes
206
- * outright — so the browser drops focus to `<body>` the moment the guard goes up.
207
- */
208
347
  #focusedInside() {
209
348
  const active = document.activeElement;
210
349
  return active instanceof HTMLElement && this.element.contains(active) ? active : null;
211
350
  }
212
- /**
213
- * Hands focus back to the element the guard took it from.
214
- *
215
- * Only when that element is still in the document and focus has not moved on since —
216
- * anything else is the user's or another controller's, and putting it back would be
217
- * taking it.
218
- */
219
351
  #refocus() {
220
352
  const target = this.#focused;
221
353
  this.#focused = null;
@@ -225,5 +357,4 @@ var PreviewGuardController = class extends Controller {
225
357
  };
226
358
 
227
359
  export { PreviewGuardController };
228
- //# sourceMappingURL=preview_guard_controller.js.map
229
360
  //# sourceMappingURL=preview_guard_controller.js.map