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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +209 -0
- data/README.md +128 -1
- data/dist/cable/index.js +392 -417
- data/dist/controllers/accordion_controller.js +228 -28
- data/dist/controllers/alert_dialog_controller.js +862 -221
- data/dist/controllers/announcer_controller.js +135 -191
- data/dist/controllers/aspect_ratio_controller.js +0 -10
- data/dist/controllers/auto_submit_controller.js +295 -110
- data/dist/controllers/avatar_controller.js +172 -106
- data/dist/controllers/breadcrumb_controller.js +0 -129
- data/dist/controllers/bulk_select_controller.js +264 -53
- data/dist/controllers/calendar_controller.js +346 -180
- data/dist/controllers/carousel_controller.js +587 -300
- data/dist/controllers/character_counter_controller.js +271 -143
- data/dist/controllers/checkbox_controller.js +77 -75
- data/dist/controllers/clipboard_controller.js +187 -108
- data/dist/controllers/collapsible_controller.js +374 -108
- data/dist/controllers/color_picker_controller.js +183 -127
- data/dist/controllers/combobox_controller.js +426 -109
- data/dist/controllers/command_palette_controller.js +994 -350
- data/dist/controllers/conditional_fields_controller.js +212 -125
- data/dist/controllers/confirm_controller.js +939 -245
- data/dist/controllers/context_menu_controller.js +275 -127
- data/dist/controllers/count_up_controller.js +73 -21
- data/dist/controllers/countdown_controller.js +235 -97
- data/dist/controllers/currency_input_controller.js +241 -118
- data/dist/controllers/data_grid_controller.js +229 -135
- data/dist/controllers/date_range_picker_controller.js +359 -165
- data/dist/controllers/dialog_controller.js +887 -225
- data/dist/controllers/direct_upload_controller.js +80 -142
- data/dist/controllers/dirty_form_controller.js +26 -47
- data/dist/controllers/dismissible_controller.js +175 -20
- data/dist/controllers/drawer_controller.js +963 -336
- data/dist/controllers/dropdown_controller.js +342 -85
- data/dist/controllers/editable_controller.js +182 -58
- data/dist/controllers/empty_state_controller.js +67 -53
- data/dist/controllers/file_dropzone_controller.js +426 -229
- data/dist/controllers/filter_controller.js +78 -36
- data/dist/controllers/flash_controller.js +328 -211
- data/dist/controllers/focus_controller.js +654 -239
- data/dist/controllers/form_field_controller.js +153 -136
- data/dist/controllers/form_validation_controller.js +29 -96
- data/dist/controllers/frame_loading_controller.js +263 -198
- data/dist/controllers/highlight_controller.js +119 -70
- data/dist/controllers/hover_card_controller.js +335 -118
- data/dist/controllers/idle_controller.js +316 -65
- data/dist/controllers/input_mask_controller.js +116 -61
- data/dist/controllers/intersection_controller.js +147 -103
- data/dist/controllers/lazy_frame_controller.js +9 -56
- data/dist/controllers/listbox_controller.js +413 -153
- data/dist/controllers/local_time_controller.js +54 -64
- data/dist/controllers/masonry_controller.js +70 -95
- data/dist/controllers/menu_controller.js +254 -167
- data/dist/controllers/menubar_controller.js +206 -331
- data/dist/controllers/meter_controller.js +159 -71
- data/dist/controllers/multi_select_controller.js +797 -388
- data/dist/controllers/navigation_menu_controller.js +156 -231
- data/dist/controllers/nested_form_controller.js +373 -174
- data/dist/controllers/network_status_controller.js +241 -45
- data/dist/controllers/number_input_controller.js +387 -227
- data/dist/controllers/optimistic_controller.js +28 -75
- data/dist/controllers/otp_controller.js +344 -196
- data/dist/controllers/overflow_indicator_controller.js +167 -93
- data/dist/controllers/overflow_menu_controller.js +408 -277
- data/dist/controllers/pagination_controller.js +342 -120
- data/dist/controllers/password_reveal_controller.js +424 -99
- data/dist/controllers/password_strength_controller.js +99 -153
- data/dist/controllers/persist_controller.js +252 -96
- data/dist/controllers/pointer_drag_controller.js +263 -164
- data/dist/controllers/popover_controller.js +267 -94
- data/dist/controllers/portal_controller.js +209 -72
- data/dist/controllers/preview_guard_controller.js +243 -112
- data/dist/controllers/progress_controller.js +132 -59
- data/dist/controllers/radio_group_controller.js +138 -133
- data/dist/controllers/range_slider_controller.js +245 -112
- data/dist/controllers/rating_controller.js +429 -194
- data/dist/controllers/read_more_controller.js +185 -47
- data/dist/controllers/reading_progress_controller.js +147 -135
- data/dist/controllers/relative_time_controller.js +145 -110
- data/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +97 -38
- data/dist/controllers/resizable_controller.js +294 -118
- data/dist/controllers/roving_controller.js +39 -84
- data/dist/controllers/scroll_area_controller.js +428 -221
- data/dist/controllers/scroll_restore_controller.js +0 -53
- data/dist/controllers/scroll_visibility_controller.js +395 -146
- data/dist/controllers/scrollspy_controller.js +181 -236
- data/dist/controllers/separator_controller.js +288 -132
- data/dist/controllers/sidebar_controller.js +1071 -375
- data/dist/controllers/skeleton_controller.js +248 -92
- data/dist/controllers/slider_controller.js +211 -96
- data/dist/controllers/smart_sticky_header_controller.js +163 -54
- data/dist/controllers/sortable_controller.js +13 -110
- data/dist/controllers/spinner_controller.js +277 -161
- data/dist/controllers/step_indicator_controller.js +107 -53
- data/dist/controllers/stepper_controller.js +171 -48
- data/dist/controllers/stick_to_bottom_controller.js +310 -116
- data/dist/controllers/sticky_observer_controller.js +214 -49
- data/dist/controllers/submit_once_controller.js +294 -192
- data/dist/controllers/switch_controller.js +107 -43
- data/dist/controllers/tabs_controller.js +50 -25
- data/dist/controllers/tags_input_controller.js +290 -149
- data/dist/controllers/textarea_autosize_controller.js +71 -58
- data/dist/controllers/theme_controller.js +148 -80
- data/dist/controllers/time_picker_controller.js +162 -81
- data/dist/controllers/toast_controller.js +365 -193
- data/dist/controllers/toggle_group_controller.js +194 -99
- data/dist/controllers/toolbar_controller.js +92 -90
- data/dist/controllers/tooltip_controller.js +185 -125
- data/dist/controllers/transition_controller.js +123 -115
- data/dist/controllers/tree_view_controller.js +248 -290
- data/dist/index.js +8649 -8572
- data/dist/positioning/index.js +148 -45
- data/lib/stimeo/ui/version.rb +1 -1
- metadata +3 -3
|
@@ -1,98 +1,179 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
function sharedRegistry(key, create) {
|
|
4
|
+
const symbol = Symbol.for(key);
|
|
5
|
+
const scope = globalThis;
|
|
6
|
+
const existing = scope[symbol];
|
|
7
|
+
if (existing !== void 0) return existing;
|
|
8
|
+
const registry = create();
|
|
9
|
+
Object.defineProperty(globalThis, symbol, { value: registry });
|
|
10
|
+
return registry;
|
|
11
|
+
}
|
|
4
12
|
|
|
5
|
-
|
|
6
|
-
|
|
13
|
+
function isAttributeValue(value) {
|
|
14
|
+
return value === null || typeof value === "string";
|
|
15
|
+
}
|
|
16
|
+
function readLeaseRecord(element, record) {
|
|
17
|
+
try {
|
|
18
|
+
const parsed = JSON.parse(element.getAttribute(record) ?? "null");
|
|
19
|
+
if (!Array.isArray(parsed)) return void 0;
|
|
20
|
+
const [original, written, ...rest] = parsed;
|
|
21
|
+
const linked = rest[0] !== false;
|
|
22
|
+
const beneath = linked ? rest : rest.slice(1);
|
|
23
|
+
if (!beneath.every((under) => typeof under === "string")) return void 0;
|
|
24
|
+
return isAttributeValue(original) && isAttributeValue(written) ? { original, written, linked, beneath } : void 0;
|
|
25
|
+
} catch {
|
|
26
|
+
return void 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
var AttributeLease = class _AttributeLease {
|
|
30
|
+
static #registry = sharedRegistry(
|
|
31
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
32
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
33
|
+
);
|
|
7
34
|
#attribute;
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
|
|
35
|
+
#record;
|
|
36
|
+
#base;
|
|
37
|
+
#held = /* @__PURE__ */ new Set();
|
|
38
|
+
constructor(attribute, owner, options = {}) {
|
|
11
39
|
this.#attribute = attribute;
|
|
40
|
+
this.#record = `data-${owner}-${attribute}-lease`;
|
|
41
|
+
this.#base = options.base === true;
|
|
42
|
+
const names = _AttributeLease.#registry.names;
|
|
43
|
+
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
12
44
|
}
|
|
13
|
-
/** Writes or removes the leased attribute while preserving its authored value. */
|
|
14
45
|
write(element, value) {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
this.#reflect(element, value);
|
|
46
|
+
const stack = this.#stack(element);
|
|
47
|
+
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
48
|
+
this.#held.add(element);
|
|
49
|
+
const shows = !this.#covered(element, stack, hold);
|
|
50
|
+
hold.written = value;
|
|
51
|
+
this.#mark(element, stack);
|
|
52
|
+
if (shows) this.#reflect(element, value);
|
|
25
53
|
}
|
|
26
|
-
/** Returns one lease without overwriting a value subsequently authored by a consumer. */
|
|
27
54
|
return(element) {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
this.#
|
|
31
|
-
const
|
|
32
|
-
if (
|
|
55
|
+
const held = this.#held.delete(element);
|
|
56
|
+
const known = _AttributeLease.#registry.stacks.get(element)?.has(this.#attribute);
|
|
57
|
+
const stack = held || known || element.hasAttribute(this.#record) ? this.#stack(element) : [];
|
|
58
|
+
const hold = this.#take(stack);
|
|
59
|
+
if (!hold) return false;
|
|
60
|
+
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
61
|
+
const owns = carries && !this.#covered(element, stack, hold);
|
|
62
|
+
const index = stack.indexOf(hold);
|
|
63
|
+
stack.splice(index, 1);
|
|
64
|
+
const above = stack[index];
|
|
65
|
+
if (above) above.linked &&= hold.linked;
|
|
66
|
+
this.#mark(element, stack);
|
|
67
|
+
if (!owns) return true;
|
|
68
|
+
const below = hold.linked ? stack[index - 1] : void 0;
|
|
69
|
+
this.#reflect(element, below ? below.written : hold.original);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
returnAll() {
|
|
73
|
+
for (const element of Array.from(this.#held)) this.return(element);
|
|
74
|
+
}
|
|
75
|
+
#stack(element) {
|
|
76
|
+
const stacks = _AttributeLease.#registry.stacks;
|
|
77
|
+
const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
78
|
+
stacks.set(element, byAttribute);
|
|
79
|
+
const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
|
|
80
|
+
byAttribute.set(this.#attribute, stack);
|
|
81
|
+
return stack;
|
|
82
|
+
}
|
|
83
|
+
#seed(element) {
|
|
84
|
+
const found = [];
|
|
85
|
+
for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
|
|
86
|
+
const read = readLeaseRecord(element, record);
|
|
87
|
+
if (read) found.push({ ...read, record });
|
|
88
|
+
}
|
|
89
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
90
|
+
return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
91
|
+
lease: null,
|
|
92
|
+
record,
|
|
93
|
+
written,
|
|
94
|
+
original,
|
|
95
|
+
linked: linked && index > 0
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
#take(stack) {
|
|
99
|
+
const hold = stack.find((held) => held.lease === this) ?? stack.find((held) => held.lease === null && held.record === this.#record);
|
|
100
|
+
if (hold) hold.lease = this;
|
|
101
|
+
return hold;
|
|
102
|
+
}
|
|
103
|
+
#acquire(element, stack) {
|
|
104
|
+
const current = element.getAttribute(this.#attribute);
|
|
105
|
+
const top = stack.at(-1);
|
|
106
|
+
const bottom = stack[0];
|
|
107
|
+
const over = top?.written === current ? top : void 0;
|
|
108
|
+
const from = this.#base ? bottom : over;
|
|
109
|
+
const hold = {
|
|
110
|
+
lease: this,
|
|
111
|
+
record: this.#record,
|
|
112
|
+
written: current,
|
|
113
|
+
original: from ? from.original : current,
|
|
114
|
+
linked: !this.#base && over !== void 0
|
|
115
|
+
};
|
|
116
|
+
if (this.#base && bottom) {
|
|
117
|
+
bottom.linked = true;
|
|
118
|
+
stack.unshift(hold);
|
|
119
|
+
} else stack.push(hold);
|
|
120
|
+
return hold;
|
|
121
|
+
}
|
|
122
|
+
#covered(element, stack, hold) {
|
|
123
|
+
const current = element.getAttribute(this.#attribute);
|
|
124
|
+
return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);
|
|
125
|
+
}
|
|
126
|
+
#mark(element, stack) {
|
|
127
|
+
const records = /* @__PURE__ */ new Map([[this.#record, null]]);
|
|
128
|
+
stack.forEach((hold, index) => {
|
|
129
|
+
const names = stack.slice(0, index).map((under) => under.record);
|
|
130
|
+
const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
|
|
131
|
+
const marker = hold.linked || beneath.length === 0 ? [] : [false];
|
|
132
|
+
records.set(
|
|
133
|
+
hold.record,
|
|
134
|
+
hold.written === hold.original && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.original, hold.written, ...marker, ...beneath])
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
for (const [name, recorded] of records) {
|
|
138
|
+
if (element.getAttribute(name) === recorded) continue;
|
|
139
|
+
if (recorded === null) element.removeAttribute(name);
|
|
140
|
+
else element.setAttribute(name, recorded);
|
|
141
|
+
}
|
|
33
142
|
}
|
|
34
|
-
/** Reflects only a real value transition, avoiding self-triggered mutation work. */
|
|
35
143
|
#reflect(element, value) {
|
|
36
144
|
if (element.getAttribute(this.#attribute) === value) return;
|
|
37
145
|
if (value === null) element.removeAttribute(this.#attribute);
|
|
38
146
|
else element.setAttribute(this.#attribute, value);
|
|
39
147
|
}
|
|
40
|
-
/** Returns every outstanding lease using the same ownership check as {@link return}. */
|
|
41
|
-
returnAll() {
|
|
42
|
-
for (const element of Array.from(this.#records.keys())) this.return(element);
|
|
43
|
-
}
|
|
44
148
|
};
|
|
45
149
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
}
|
|
150
|
+
var ListenerSet = class {
|
|
151
|
+
#abort = new AbortController();
|
|
152
|
+
add(target, type, handler, options) {
|
|
153
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
66
154
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (_BeforeCacheReset.#subscribers.size > 0) return;
|
|
71
|
-
document.removeEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
|
|
155
|
+
dispose() {
|
|
156
|
+
this.#abort.abort();
|
|
157
|
+
this.#abort = new AbortController();
|
|
72
158
|
}
|
|
73
159
|
};
|
|
74
160
|
|
|
75
|
-
// src/utils/microtask_coalescer.ts
|
|
76
161
|
var MicrotaskCoalescer = class {
|
|
77
162
|
#run;
|
|
78
163
|
#queued = false;
|
|
79
164
|
#active = false;
|
|
80
165
|
#generation = 0;
|
|
81
|
-
/** @param run - the single reconciliation pass, invoked at most once per batch. */
|
|
82
166
|
constructor(run) {
|
|
83
167
|
this.#run = run;
|
|
84
168
|
}
|
|
85
|
-
/** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
|
|
86
169
|
activate() {
|
|
87
170
|
this.#active = true;
|
|
88
171
|
}
|
|
89
|
-
/** Closes the window and drops any pending pass; call from `disconnect()`. */
|
|
90
172
|
cancel() {
|
|
91
173
|
this.#active = false;
|
|
92
174
|
this.#queued = false;
|
|
93
175
|
this.#generation += 1;
|
|
94
176
|
}
|
|
95
|
-
/** Requests one pass after the batch settles. Idempotent; inert outside the window. */
|
|
96
177
|
schedule() {
|
|
97
178
|
if (!this.#active || this.#queued) return;
|
|
98
179
|
this.#queued = true;
|
|
@@ -105,32 +186,49 @@ var MicrotaskCoalescer = class {
|
|
|
105
186
|
}
|
|
106
187
|
};
|
|
107
188
|
|
|
108
|
-
|
|
189
|
+
var MorphRenderWatcher = class {
|
|
190
|
+
#listeners = new ListenerSet();
|
|
191
|
+
#pass;
|
|
192
|
+
#element = null;
|
|
193
|
+
#onMorph = () => this.#pass.schedule();
|
|
194
|
+
constructor(run) {
|
|
195
|
+
this.#pass = new MicrotaskCoalescer(run);
|
|
196
|
+
}
|
|
197
|
+
observe(element) {
|
|
198
|
+
if (this.#element === element) return;
|
|
199
|
+
this.disconnect();
|
|
200
|
+
this.#element = element;
|
|
201
|
+
this.#pass.activate();
|
|
202
|
+
this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
|
|
203
|
+
}
|
|
204
|
+
schedule() {
|
|
205
|
+
this.#pass.schedule();
|
|
206
|
+
}
|
|
207
|
+
disconnect() {
|
|
208
|
+
this.#listeners.dispose();
|
|
209
|
+
this.#pass.cancel();
|
|
210
|
+
this.#element = null;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
109
214
|
var AvatarController = class extends Controller {
|
|
110
215
|
static targets = ["image", "fallback"];
|
|
111
216
|
static values = { src: String };
|
|
112
217
|
static actions = ["onError", "onLoad"];
|
|
113
218
|
static events = ["error"];
|
|
114
|
-
|
|
115
|
-
#
|
|
116
|
-
|
|
117
|
-
#
|
|
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. */
|
|
219
|
+
#reconcile = new MorphRenderWatcher(() => this.#render());
|
|
220
|
+
#src = new AttributeLease("src", this.identifier);
|
|
221
|
+
#imageHidden = new AttributeLease("hidden", this.identifier);
|
|
222
|
+
#fallbackHidden = new AttributeLease("hidden", this.identifier);
|
|
122
223
|
#connected = false;
|
|
123
|
-
/** Watches the non-Value render input used by the direct `<img src>` form. */
|
|
124
224
|
#srcObserver = new MutationObserver((records) => {
|
|
125
225
|
if (records.some((record) => this.hasImageTarget && record.target === this.imageTarget)) {
|
|
126
226
|
this.#reconcile.schedule();
|
|
127
227
|
}
|
|
128
228
|
});
|
|
129
|
-
/** Starts retained-DOM observation and silently derives the current phase. */
|
|
130
229
|
connect() {
|
|
131
230
|
this.#connected = true;
|
|
132
|
-
this.#reconcile.
|
|
133
|
-
this.#beforeCache.activate();
|
|
231
|
+
this.#reconcile.observe(this.element);
|
|
134
232
|
this.#srcObserver.observe(this.element, {
|
|
135
233
|
attributes: true,
|
|
136
234
|
attributeFilter: ["src"],
|
|
@@ -138,22 +236,17 @@ var AvatarController = class extends Controller {
|
|
|
138
236
|
});
|
|
139
237
|
this.#render();
|
|
140
238
|
}
|
|
141
|
-
/** Cancels asynchronous work while retaining the last materialized visual state. */
|
|
142
239
|
disconnect() {
|
|
143
240
|
this.#connected = false;
|
|
144
|
-
this.#reconcile.
|
|
145
|
-
this.#beforeCache.deactivate();
|
|
241
|
+
this.#reconcile.disconnect();
|
|
146
242
|
this.#srcObserver.disconnect();
|
|
147
243
|
}
|
|
148
|
-
/** Repaints when application code or a Turbo morph changes the source Value. */
|
|
149
244
|
srcValueChanged() {
|
|
150
245
|
this.#reconcile.schedule();
|
|
151
246
|
}
|
|
152
|
-
/** Applies the current source and phase to an image inserted or replaced at runtime. */
|
|
153
247
|
imageTargetConnected() {
|
|
154
248
|
this.#reconcile.schedule();
|
|
155
249
|
}
|
|
156
|
-
/** Returns attributes borrowed from an image that leaves this live avatar. */
|
|
157
250
|
imageTargetDisconnected(image) {
|
|
158
251
|
if (this.#connected) {
|
|
159
252
|
this.#src.return(image);
|
|
@@ -161,16 +254,13 @@ var AvatarController = class extends Controller {
|
|
|
161
254
|
}
|
|
162
255
|
this.#reconcile.schedule();
|
|
163
256
|
}
|
|
164
|
-
/** Applies the current phase to a fallback inserted or replaced at runtime. */
|
|
165
257
|
fallbackTargetConnected() {
|
|
166
258
|
this.#reconcile.schedule();
|
|
167
259
|
}
|
|
168
|
-
/** Returns authored visibility when a fallback leaves this live avatar. */
|
|
169
260
|
fallbackTargetDisconnected(fallback) {
|
|
170
261
|
if (this.#connected) this.#fallbackHidden.return(fallback);
|
|
171
262
|
this.#reconcile.schedule();
|
|
172
263
|
}
|
|
173
|
-
/** Reveals the current image after its native `load` event. */
|
|
174
264
|
onLoad(event) {
|
|
175
265
|
const image = this.#eventImage(event);
|
|
176
266
|
if (!image) return;
|
|
@@ -180,12 +270,6 @@ var AvatarController = class extends Controller {
|
|
|
180
270
|
}
|
|
181
271
|
this.#reflect("loaded");
|
|
182
272
|
}
|
|
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
273
|
onError(event) {
|
|
190
274
|
const image = this.#eventImage(event);
|
|
191
275
|
if (!image) return;
|
|
@@ -197,14 +281,6 @@ var AvatarController = class extends Controller {
|
|
|
197
281
|
this.#reflect("error");
|
|
198
282
|
this.dispatch("error", { detail: { src } });
|
|
199
283
|
}
|
|
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
284
|
#render() {
|
|
209
285
|
if (!this.hasImageTarget) {
|
|
210
286
|
this.#reflect("empty");
|
|
@@ -222,24 +298,21 @@ var AvatarController = class extends Controller {
|
|
|
222
298
|
}
|
|
223
299
|
this.#reflect(image.naturalWidth > 0 ? "loaded" : "error");
|
|
224
300
|
}
|
|
225
|
-
/** Applies Value precedence and returns the effective raw `src` attribute. */
|
|
226
301
|
#applySource(image) {
|
|
227
|
-
if (!this.element.hasAttribute(
|
|
302
|
+
if (!this.element.hasAttribute(`data-${this.identifier}-src-value`)) {
|
|
228
303
|
this.#src.return(image);
|
|
229
304
|
return image.getAttribute("src");
|
|
230
305
|
}
|
|
231
306
|
const desired = this.srcValue.length > 0 ? this.srcValue : null;
|
|
232
|
-
|
|
307
|
+
this.#src.write(image, desired);
|
|
233
308
|
return desired;
|
|
234
309
|
}
|
|
235
|
-
/** Accepts an action only from the singular image target currently controlled. */
|
|
236
310
|
#eventImage(event) {
|
|
237
311
|
const candidate = event.currentTarget;
|
|
238
312
|
if (!(candidate instanceof HTMLImageElement)) return null;
|
|
239
313
|
if (!this.hasImageTarget || candidate !== this.imageTarget) return null;
|
|
240
314
|
return candidate;
|
|
241
315
|
}
|
|
242
|
-
/** Writes the visibility pair and public root state as one controller-owned output. */
|
|
243
316
|
#reflect(state) {
|
|
244
317
|
const showImage = state === "loading" || state === "loaded";
|
|
245
318
|
if (this.hasImageTarget) {
|
|
@@ -250,14 +323,7 @@ var AvatarController = class extends Controller {
|
|
|
250
323
|
}
|
|
251
324
|
this.element.setAttribute("data-state", state);
|
|
252
325
|
}
|
|
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
326
|
};
|
|
260
327
|
|
|
261
328
|
export { AvatarController };
|
|
262
|
-
//# sourceMappingURL=avatar_controller.js.map
|
|
263
329
|
//# sourceMappingURL=avatar_controller.js.map
|