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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +136 -0
- data/README.md +27 -11
- data/dist/cable/index.js +384 -449
- data/dist/controllers/accordion_controller.js +174 -55
- data/dist/controllers/alert_dialog_controller.js +903 -235
- data/dist/controllers/announcer_controller.js +238 -205
- data/dist/controllers/aspect_ratio_controller.js +0 -10
- data/dist/controllers/auto_submit_controller.js +414 -145
- data/dist/controllers/avatar_controller.js +185 -107
- data/dist/controllers/breadcrumb_controller.js +0 -130
- data/dist/controllers/bulk_select_controller.js +282 -58
- data/dist/controllers/calendar_controller.js +228 -260
- data/dist/controllers/carousel_controller.js +536 -436
- data/dist/controllers/character_counter_controller.js +493 -207
- data/dist/controllers/checkbox_controller.js +38 -74
- data/dist/controllers/clipboard_controller.js +261 -149
- data/dist/controllers/collapsible_controller.js +304 -120
- data/dist/controllers/color_picker_controller.js +178 -146
- data/dist/controllers/combobox_controller.js +522 -156
- data/dist/controllers/command_palette_controller.js +1156 -395
- data/dist/controllers/conditional_fields_controller.js +300 -171
- data/dist/controllers/confirm_controller.js +980 -262
- data/dist/controllers/context_menu_controller.js +346 -153
- data/dist/controllers/count_up_controller.js +73 -21
- data/dist/controllers/countdown_controller.js +281 -158
- data/dist/controllers/currency_input_controller.js +575 -225
- data/dist/controllers/data_grid_controller.js +248 -214
- data/dist/controllers/date_range_picker_controller.js +338 -235
- data/dist/controllers/dialog_controller.js +899 -237
- data/dist/controllers/direct_upload_controller.js +97 -167
- data/dist/controllers/dirty_form_controller.js +72 -69
- data/dist/controllers/dismissible_controller.js +196 -24
- data/dist/controllers/drawer_controller.js +974 -355
- data/dist/controllers/dropdown_controller.js +339 -96
- data/dist/controllers/editable_controller.js +315 -88
- data/dist/controllers/empty_state_controller.js +79 -58
- data/dist/controllers/file_dropzone_controller.js +322 -211
- data/dist/controllers/filter_controller.js +77 -42
- data/dist/controllers/flash_controller.js +238 -347
- data/dist/controllers/focus_controller.js +679 -240
- data/dist/controllers/form_field_controller.js +156 -132
- data/dist/controllers/form_validation_controller.js +31 -97
- data/dist/controllers/frame_loading_controller.js +275 -217
- data/dist/controllers/highlight_controller.js +107 -75
- data/dist/controllers/hover_card_controller.js +327 -130
- data/dist/controllers/idle_controller.js +271 -101
- data/dist/controllers/input_mask_controller.js +483 -97
- data/dist/controllers/intersection_controller.js +150 -106
- data/dist/controllers/lazy_frame_controller.js +24 -68
- data/dist/controllers/listbox_controller.js +523 -240
- data/dist/controllers/local_time_controller.js +102 -77
- data/dist/controllers/masonry_controller.js +80 -96
- data/dist/controllers/menu_controller.js +302 -188
- data/dist/controllers/menubar_controller.js +232 -345
- data/dist/controllers/meter_controller.js +417 -87
- data/dist/controllers/multi_select_controller.js +785 -393
- data/dist/controllers/navigation_menu_controller.js +190 -250
- data/dist/controllers/nested_form_controller.js +396 -192
- data/dist/controllers/network_status_controller.js +268 -62
- data/dist/controllers/number_input_controller.js +610 -303
- data/dist/controllers/optimistic_controller.js +45 -87
- data/dist/controllers/otp_controller.js +658 -255
- data/dist/controllers/overflow_indicator_controller.js +122 -113
- data/dist/controllers/overflow_menu_controller.js +470 -295
- data/dist/controllers/pagination_controller.js +332 -123
- data/dist/controllers/password_reveal_controller.js +392 -121
- data/dist/controllers/password_strength_controller.js +111 -158
- data/dist/controllers/persist_controller.js +165 -111
- data/dist/controllers/pointer_drag_controller.js +434 -188
- data/dist/controllers/popover_controller.js +269 -113
- data/dist/controllers/portal_controller.js +215 -76
- data/dist/controllers/preview_guard_controller.js +243 -116
- data/dist/controllers/progress_controller.js +391 -78
- data/dist/controllers/radio_group_controller.js +278 -211
- data/dist/controllers/range_slider_controller.js +220 -113
- data/dist/controllers/rating_controller.js +458 -211
- data/dist/controllers/read_more_controller.js +138 -63
- data/dist/controllers/reading_progress_controller.js +166 -137
- data/dist/controllers/relative_time_controller.js +211 -112
- data/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +103 -38
- data/dist/controllers/resizable_controller.js +299 -150
- data/dist/controllers/roving_controller.js +49 -88
- data/dist/controllers/scroll_area_controller.js +490 -246
- data/dist/controllers/scroll_restore_controller.js +14 -55
- data/dist/controllers/scroll_visibility_controller.js +432 -149
- data/dist/controllers/scrollspy_controller.js +193 -248
- data/dist/controllers/separator_controller.js +285 -142
- data/dist/controllers/sidebar_controller.js +1069 -404
- data/dist/controllers/skeleton_controller.js +259 -101
- data/dist/controllers/slider_controller.js +187 -86
- data/dist/controllers/smart_sticky_header_controller.js +173 -66
- data/dist/controllers/sortable_controller.js +26 -125
- data/dist/controllers/spinner_controller.js +288 -173
- data/dist/controllers/step_indicator_controller.js +105 -46
- data/dist/controllers/stepper_controller.js +120 -73
- data/dist/controllers/stick_to_bottom_controller.js +275 -140
- data/dist/controllers/sticky_observer_controller.js +220 -49
- data/dist/controllers/submit_once_controller.js +376 -227
- data/dist/controllers/switch_controller.js +201 -84
- data/dist/controllers/tabs_controller.js +41 -30
- data/dist/controllers/tags_input_controller.js +293 -173
- data/dist/controllers/textarea_autosize_controller.js +108 -74
- data/dist/controllers/theme_controller.js +140 -116
- data/dist/controllers/time_picker_controller.js +331 -127
- data/dist/controllers/toast_controller.js +244 -324
- data/dist/controllers/toggle_group_controller.js +252 -191
- data/dist/controllers/toolbar_controller.js +219 -120
- data/dist/controllers/tooltip_controller.js +158 -124
- data/dist/controllers/transition_controller.js +123 -119
- data/dist/controllers/tree_view_controller.js +283 -369
- data/dist/index.js +8573 -10410
- data/dist/positioning/index.js +154 -47
- data/lib/generators/stimeo/install/install_generator.rb +7 -2
- data/lib/generators/stimeo/install/templates/stimeo.js +19 -6
- data/lib/stimeo/ui/version.rb +1 -1
- metadata +3 -3
|
@@ -1,98 +1,188 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
9
|
-
|
|
10
|
-
|
|
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
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
|
29
|
-
|
|
30
|
-
this.#
|
|
31
|
-
const
|
|
32
|
-
if (
|
|
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.#
|
|
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
|
-
|
|
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
|
-
}
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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. */
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|