@ramstack/alpinegear-main 1.4.2 → 1.4.4
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.
- package/README.md +163 -187
- package/alpinegear-main.esm.js +623 -615
- package/alpinegear-main.esm.min.js +1 -1
- package/alpinegear-main.js +623 -624
- package/alpinegear-main.min.js +1 -1
- package/package.json +9 -3
package/alpinegear-main.esm.js
CHANGED
|
@@ -37,70 +37,70 @@ function has_setter(value) {
|
|
|
37
37
|
return typeof value?.set === "function";
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
const key = Symbol();
|
|
41
|
-
let observer;
|
|
42
|
-
|
|
43
|
-
function observe_resize(el, listener) {
|
|
44
|
-
observer ??= new ResizeObserver(entries => {
|
|
45
|
-
for (const e of entries) {
|
|
46
|
-
for (const callback of e.target[key]?.values() ?? []) {
|
|
47
|
-
callback(e);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
el[key] ??= new Set();
|
|
53
|
-
el[key].add(listener);
|
|
54
|
-
|
|
55
|
-
observer.observe(el);
|
|
56
|
-
|
|
57
|
-
return () => {
|
|
58
|
-
el[key].delete(listener);
|
|
59
|
-
|
|
60
|
-
if (!el[key].size) {
|
|
61
|
-
observer.unobserve(el);
|
|
62
|
-
el[key] = null;
|
|
63
|
-
}
|
|
64
|
-
};
|
|
40
|
+
const key = Symbol();
|
|
41
|
+
let observer;
|
|
42
|
+
|
|
43
|
+
function observe_resize(el, listener) {
|
|
44
|
+
observer ??= new ResizeObserver(entries => {
|
|
45
|
+
for (const e of entries) {
|
|
46
|
+
for (const callback of e.target[key]?.values() ?? []) {
|
|
47
|
+
callback(e);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
el[key] ??= new Set();
|
|
53
|
+
el[key].add(listener);
|
|
54
|
+
|
|
55
|
+
observer.observe(el);
|
|
56
|
+
|
|
57
|
+
return () => {
|
|
58
|
+
el[key].delete(listener);
|
|
59
|
+
|
|
60
|
+
if (!el[key].size) {
|
|
61
|
+
observer.unobserve(el);
|
|
62
|
+
el[key] = null;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
const warn = (...args) => console.warn("alpinegear.js:", ...args);
|
|
68
|
-
const is_array = Array.isArray;
|
|
69
|
-
const is_nullish = value => value === null || value === undefined;
|
|
70
|
-
const is_checkable_input = el => el.type === "checkbox" || el.type === "radio";
|
|
71
|
-
const is_numeric_input = el => el.type === "number" || el.type === "range";
|
|
72
|
-
const is_template = el => el.matches("template");
|
|
73
|
-
const is_element = el => el.nodeType === Node.ELEMENT_NODE;
|
|
74
|
-
const as_array = value => is_array(value) ? value : [value];
|
|
75
|
-
const loose_equal = (a, b) => a == b;
|
|
76
|
-
const loose_index_of = (array, value) => array.findIndex(v => v == value);
|
|
77
|
-
const has_modifier = (modifiers, modifier) => modifiers.includes(modifier);
|
|
78
|
-
|
|
79
|
-
function assert(value, message) {
|
|
80
|
-
if (!value) {
|
|
81
|
-
throw new Error(message);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const listen = (target, type, listener, options) => {
|
|
86
|
-
target.addEventListener(type, listener, options);
|
|
87
|
-
return () => target.removeEventListener(type, listener, options);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const clone = value =>
|
|
91
|
-
typeof value === "object"
|
|
92
|
-
? JSON.parse(JSON.stringify(value))
|
|
93
|
-
: value;
|
|
94
|
-
|
|
95
|
-
const closest = (el, callback) => {
|
|
96
|
-
while (el && !callback(el)) {
|
|
97
|
-
el = (el._x_teleportBack ?? el).parentElement;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return el;
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
const create_map = keys => new Map(
|
|
67
|
+
const warn = (...args) => console.warn("alpinegear.js:", ...args);
|
|
68
|
+
const is_array = Array.isArray;
|
|
69
|
+
const is_nullish = value => value === null || value === undefined;
|
|
70
|
+
const is_checkable_input = el => el.type === "checkbox" || el.type === "radio";
|
|
71
|
+
const is_numeric_input = el => el.type === "number" || el.type === "range";
|
|
72
|
+
const is_template = el => el.matches("template");
|
|
73
|
+
const is_element = el => el.nodeType === Node.ELEMENT_NODE;
|
|
74
|
+
const as_array = value => is_array(value) ? value : [value];
|
|
75
|
+
const loose_equal = (a, b) => a == b;
|
|
76
|
+
const loose_index_of = (array, value) => array.findIndex(v => v == value);
|
|
77
|
+
const has_modifier = (modifiers, modifier) => modifiers.includes(modifier);
|
|
78
|
+
|
|
79
|
+
function assert(value, message) {
|
|
80
|
+
if (!value) {
|
|
81
|
+
throw new Error(message);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const listen = (target, type, listener, options) => {
|
|
86
|
+
target.addEventListener(type, listener, options);
|
|
87
|
+
return () => target.removeEventListener(type, listener, options);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const clone = value =>
|
|
91
|
+
typeof value === "object"
|
|
92
|
+
? JSON.parse(JSON.stringify(value))
|
|
93
|
+
: value;
|
|
94
|
+
|
|
95
|
+
const closest = (el, callback) => {
|
|
96
|
+
while (el && !callback(el)) {
|
|
97
|
+
el = (el._x_teleportBack ?? el).parentElement;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return el;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const create_map = keys => new Map(
|
|
104
104
|
keys.split(",").map(v => [v.trim().toLowerCase(), v.trim()]));
|
|
105
105
|
|
|
106
106
|
function watch(get_value, callback, options = null) {
|
|
@@ -128,7 +128,7 @@ function watch(get_value, callback, options = null) {
|
|
|
128
128
|
setTimeout(() => {
|
|
129
129
|
callback(new_value, old_value);
|
|
130
130
|
old_value = new_value;
|
|
131
|
-
}
|
|
131
|
+
});
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
initialized = true;
|
|
@@ -137,569 +137,577 @@ function watch(get_value, callback, options = null) {
|
|
|
137
137
|
return () => release(handle);
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
const canonical_names = create_map(
|
|
141
|
-
"value,checked,files," +
|
|
142
|
-
"innerHTML,innerText,textContent," +
|
|
143
|
-
"videoHeight,videoWidth," +
|
|
144
|
-
"naturalHeight,naturalWidth," +
|
|
145
|
-
"clientHeight,clientWidth,offsetHeight,offsetWidth," +
|
|
146
|
-
"indeterminate," +
|
|
147
|
-
"open," +
|
|
148
|
-
"group");
|
|
149
|
-
|
|
150
|
-
function plugin$
|
|
151
|
-
// creating a shortcut for the directive,
|
|
152
|
-
// when an attribute name starting with & will refer to our directive,
|
|
153
|
-
// allowing us to write like this: &value="prop",
|
|
154
|
-
// which is equivalent to x-bound:value="prop"
|
|
155
|
-
mapAttributes(attr => ({
|
|
156
|
-
name: attr.name.replace(/^&/, prefixed("bound:")),
|
|
157
|
-
value: attr.value
|
|
158
|
-
}));
|
|
159
|
-
|
|
160
|
-
directive("bound", (el, { expression, value, modifiers }, { effect, cleanup }) => {
|
|
161
|
-
if (!value) {
|
|
162
|
-
warn("x-bound directive expects the presence of a bound property name");
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const tag_name = el.tagName.toUpperCase();
|
|
167
|
-
|
|
168
|
-
expression = expression?.trim();
|
|
169
|
-
|
|
170
|
-
// since attributes come in a lowercase,
|
|
171
|
-
// we need to convert the bound property name to its canonical form
|
|
172
|
-
const property_name = canonical_names.get(value.trim().replace("-", "").toLowerCase());
|
|
173
|
-
|
|
174
|
-
// if the expression is omitted, then we assume it corresponds
|
|
175
|
-
// to the bound property name, allowing us to write expressions more concisely,
|
|
176
|
-
// and write &value instead of &value="value"
|
|
177
|
-
expression ||= property_name;
|
|
178
|
-
|
|
179
|
-
const get_value = create_getter(evaluateLater, el, expression);
|
|
180
|
-
const set_value = create_setter(evaluateLater, el, expression);
|
|
181
|
-
|
|
182
|
-
const update_property = () => loose_equal(el[property_name], get_value()) || mutateDom(() => el[property_name] = get_value());
|
|
183
|
-
const update_variable = () => set_value(is_numeric_input(el) ? to_number(el[property_name]) : el[property_name]);
|
|
184
|
-
|
|
185
|
-
let processed;
|
|
186
|
-
|
|
187
|
-
switch (property_name) {
|
|
188
|
-
case "value":
|
|
189
|
-
process_value();
|
|
190
|
-
break;
|
|
191
|
-
|
|
192
|
-
case "checked":
|
|
193
|
-
process_checked();
|
|
194
|
-
break;
|
|
195
|
-
|
|
196
|
-
case "files":
|
|
197
|
-
process_files();
|
|
198
|
-
break;
|
|
199
|
-
|
|
200
|
-
case "innerHTML":
|
|
201
|
-
case "innerText":
|
|
202
|
-
case "textContent":
|
|
203
|
-
process_contenteditable();
|
|
204
|
-
break;
|
|
205
|
-
|
|
206
|
-
case "videoHeight":
|
|
207
|
-
case "videoWidth":
|
|
208
|
-
process_media_resize("VIDEO", "resize");
|
|
209
|
-
break;
|
|
210
|
-
|
|
211
|
-
case "naturalHeight":
|
|
212
|
-
case "naturalWidth":
|
|
213
|
-
process_media_resize("IMG", "load");
|
|
214
|
-
break;
|
|
215
|
-
|
|
216
|
-
case "clientHeight":
|
|
217
|
-
case "clientWidth":
|
|
218
|
-
case "offsetHeight":
|
|
219
|
-
case "offsetWidth":
|
|
220
|
-
process_dimensions();
|
|
221
|
-
break;
|
|
222
|
-
|
|
223
|
-
case "indeterminate":
|
|
224
|
-
process_indeterminate();
|
|
225
|
-
break;
|
|
226
|
-
|
|
227
|
-
case "open":
|
|
228
|
-
process_open_attribute();
|
|
229
|
-
break;
|
|
230
|
-
|
|
231
|
-
case "group":
|
|
232
|
-
process_group();
|
|
233
|
-
break;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (!processed) {
|
|
237
|
-
const modifier =
|
|
238
|
-
has_modifier(modifiers, "in") ? "in" :
|
|
239
|
-
has_modifier(modifiers, "out") ? "out" : "inout";
|
|
240
|
-
|
|
241
|
-
const source_el = expression === value
|
|
242
|
-
? closest(el.parentNode, node => node._x_dataStack)
|
|
243
|
-
: el;
|
|
244
|
-
|
|
245
|
-
if (!el._x_dataStack) {
|
|
246
|
-
warn("x-bound directive requires the presence of the x-data directive to bind component properties");
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (!source_el) {
|
|
251
|
-
warn(`x-bound directive cannot find the parent scope where the '${ value }' property is defined`);
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const source = {
|
|
256
|
-
get: create_getter(evaluateLater, source_el, expression),
|
|
257
|
-
set: create_setter(evaluateLater, source_el, expression)
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
const target = {
|
|
261
|
-
get: create_getter(evaluateLater, el, value),
|
|
262
|
-
set: create_setter(evaluateLater, el, value)
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
switch (modifier) {
|
|
266
|
-
case "in":
|
|
267
|
-
cleanup(watch(() => source.get(), v => target.set(clone(v))));
|
|
268
|
-
break;
|
|
269
|
-
case "out":
|
|
270
|
-
cleanup(watch(() => target.get(), v => source.set(clone(v))));
|
|
271
|
-
break;
|
|
272
|
-
default:
|
|
273
|
-
cleanup(entangle(source, target));
|
|
274
|
-
break;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
function process_value() {
|
|
279
|
-
switch (tag_name) {
|
|
280
|
-
case "INPUT":
|
|
281
|
-
case "TEXTAREA":
|
|
282
|
-
// if the value of the bound property is "null" or "undefined",
|
|
283
|
-
// we initialize it with the value from the element.
|
|
284
|
-
is_nullish(get_value()) && update_variable();
|
|
285
|
-
|
|
286
|
-
effect(update_property);
|
|
287
|
-
cleanup(listen(el, "input", update_variable));
|
|
288
|
-
|
|
289
|
-
processed = true;
|
|
290
|
-
break;
|
|
291
|
-
|
|
292
|
-
case "SELECT":
|
|
293
|
-
// WORKAROUND:
|
|
294
|
-
// For the "select" element, there might be a situation
|
|
295
|
-
// where options are generated dynamically using the "x-for" directive,
|
|
296
|
-
// and in this case, attempting to set the "value" property
|
|
297
|
-
// will have no effect since there are no options yet.
|
|
298
|
-
// Therefore, we use a small trick to set the value a bit later
|
|
299
|
-
// when the "x-for" directive has finished its work.
|
|
300
|
-
setTimeout(() => {
|
|
301
|
-
// if the value of the bound property is "null" or "undefined",
|
|
302
|
-
// we initialize it with the value from the element.
|
|
303
|
-
is_nullish(get_value()) && update_variable();
|
|
304
|
-
|
|
305
|
-
effect(() => apply_select_values(el, as_array(get_value() ?? [])));
|
|
306
|
-
cleanup(listen(el, "change", () => set_value(collect_selected_values(el))));
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
processed = true;
|
|
310
|
-
break;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
function process_checked() {
|
|
315
|
-
if (is_checkable_input(el)) {
|
|
316
|
-
effect(update_property);
|
|
317
|
-
cleanup(listen(el, "change", update_variable));
|
|
318
|
-
processed = true;
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
function process_indeterminate() {
|
|
323
|
-
if (el.type === "checkbox") {
|
|
324
|
-
is_nullish(get_value()) && update_variable();
|
|
325
|
-
effect(update_property);
|
|
326
|
-
cleanup(listen(el, "change", update_variable));
|
|
327
|
-
processed = true;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
function process_files() {
|
|
332
|
-
if (el.type === "file") {
|
|
333
|
-
get_value() instanceof FileList || update_variable();
|
|
334
|
-
|
|
335
|
-
effect(update_property);
|
|
336
|
-
cleanup(listen(el, "input", update_variable));
|
|
337
|
-
processed = true;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
function process_contenteditable() {
|
|
342
|
-
if (el.isContentEditable) {
|
|
343
|
-
is_nullish(get_value()) && update_variable();
|
|
344
|
-
|
|
345
|
-
effect(update_property);
|
|
346
|
-
cleanup(listen(el, "input", update_variable));
|
|
347
|
-
processed = true;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
function process_media_resize(name, event_name) {
|
|
352
|
-
if (tag_name === name) {
|
|
353
|
-
update_variable();
|
|
354
|
-
cleanup(listen(el, event_name, update_variable));
|
|
355
|
-
processed = true;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
function process_dimensions() {
|
|
360
|
-
cleanup(observe_resize(el, update_variable));
|
|
361
|
-
processed = true;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
function process_open_attribute() {
|
|
365
|
-
const [is_details, is_dialog] = [tag_name === "DETAILS", tag_name === "DIALOG"];
|
|
366
|
-
|
|
367
|
-
if (is_details || is_dialog) {
|
|
368
|
-
//
|
|
369
|
-
// <details>:
|
|
370
|
-
// Supports safe two-way binding via the "open" attribute,
|
|
371
|
-
// so we initialize from the element only if the bound value
|
|
372
|
-
// is null or undefined.
|
|
373
|
-
//
|
|
374
|
-
// <dialog>:
|
|
375
|
-
// Directly setting element.open is discouraged by the spec,
|
|
376
|
-
// as it breaks native dialog behavior and the "close" event.
|
|
377
|
-
// Therefore, we always initialize state from the element
|
|
378
|
-
// and treat it as a one-way source of truth.
|
|
379
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/open#value
|
|
380
|
-
//
|
|
381
|
-
(is_dialog || is_nullish(get_value())) && update_variable();
|
|
382
|
-
|
|
383
|
-
//
|
|
384
|
-
// Enable two-way binding only for "<details>"
|
|
385
|
-
//
|
|
386
|
-
is_details && effect(update_property);
|
|
387
|
-
cleanup(listen(el, "toggle", update_variable));
|
|
388
|
-
processed = true;
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
function process_group() {
|
|
393
|
-
if (is_checkable_input(el)) {
|
|
394
|
-
el.name || mutateDom(() => el.name = expression);
|
|
395
|
-
|
|
396
|
-
effect(() =>
|
|
397
|
-
mutateDom(() =>
|
|
398
|
-
apply_group_values(el, get_value() ?? [])));
|
|
399
|
-
|
|
400
|
-
cleanup(listen(el, "input", () => set_value(collect_group_values(el, get_value()))));
|
|
401
|
-
processed = true;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
function to_number(value) {
|
|
408
|
-
return value === "" ? null : +value;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
function apply_select_values(el, values) {
|
|
412
|
-
for (const option of el.options) {
|
|
413
|
-
option.selected = loose_index_of(values, option.value) >= 0;
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
function collect_selected_values(el) {
|
|
418
|
-
if (el.multiple) {
|
|
419
|
-
return [...el.selectedOptions].map(o => o.value);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
return el.value;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
function apply_group_values(el, values) {
|
|
426
|
-
el.checked = is_array(values)
|
|
427
|
-
? loose_index_of(values, el.value) >= 0
|
|
428
|
-
: loose_equal(el.value, values);
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
function collect_group_values(el, values) {
|
|
432
|
-
if (el.type === "radio") {
|
|
433
|
-
return el.value;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
values = as_array(values);
|
|
437
|
-
const index = loose_index_of(values, el.value);
|
|
438
|
-
|
|
439
|
-
if (el.checked) {
|
|
440
|
-
index >= 0 || values.push(el.value);
|
|
441
|
-
}
|
|
442
|
-
else {
|
|
443
|
-
index >= 0 && values.splice(index, 1);
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
return values;
|
|
140
|
+
const canonical_names = create_map(
|
|
141
|
+
"value,checked,files," +
|
|
142
|
+
"innerHTML,innerText,textContent," +
|
|
143
|
+
"videoHeight,videoWidth," +
|
|
144
|
+
"naturalHeight,naturalWidth," +
|
|
145
|
+
"clientHeight,clientWidth,offsetHeight,offsetWidth," +
|
|
146
|
+
"indeterminate," +
|
|
147
|
+
"open," +
|
|
148
|
+
"group");
|
|
149
|
+
|
|
150
|
+
function plugin$6({ directive, entangle, evaluateLater, mapAttributes, mutateDom, prefixed }) {
|
|
151
|
+
// creating a shortcut for the directive,
|
|
152
|
+
// when an attribute name starting with & will refer to our directive,
|
|
153
|
+
// allowing us to write like this: &value="prop",
|
|
154
|
+
// which is equivalent to x-bound:value="prop"
|
|
155
|
+
mapAttributes(attr => ({
|
|
156
|
+
name: attr.name.replace(/^&/, prefixed("bound:")),
|
|
157
|
+
value: attr.value
|
|
158
|
+
}));
|
|
159
|
+
|
|
160
|
+
directive("bound", (el, { expression, value, modifiers }, { effect, cleanup }) => {
|
|
161
|
+
if (!value) {
|
|
162
|
+
warn("x-bound directive expects the presence of a bound property name");
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const tag_name = el.tagName.toUpperCase();
|
|
167
|
+
|
|
168
|
+
expression = expression?.trim();
|
|
169
|
+
|
|
170
|
+
// since attributes come in a lowercase,
|
|
171
|
+
// we need to convert the bound property name to its canonical form
|
|
172
|
+
const property_name = canonical_names.get(value.trim().replace("-", "").toLowerCase());
|
|
173
|
+
|
|
174
|
+
// if the expression is omitted, then we assume it corresponds
|
|
175
|
+
// to the bound property name, allowing us to write expressions more concisely,
|
|
176
|
+
// and write &value instead of &value="value"
|
|
177
|
+
expression ||= property_name;
|
|
178
|
+
|
|
179
|
+
const get_value = create_getter(evaluateLater, el, expression);
|
|
180
|
+
const set_value = create_setter(evaluateLater, el, expression);
|
|
181
|
+
|
|
182
|
+
const update_property = () => loose_equal(el[property_name], get_value()) || mutateDom(() => el[property_name] = get_value());
|
|
183
|
+
const update_variable = () => set_value(is_numeric_input(el) ? to_number(el[property_name]) : el[property_name]);
|
|
184
|
+
|
|
185
|
+
let processed;
|
|
186
|
+
|
|
187
|
+
switch (property_name) {
|
|
188
|
+
case "value":
|
|
189
|
+
process_value();
|
|
190
|
+
break;
|
|
191
|
+
|
|
192
|
+
case "checked":
|
|
193
|
+
process_checked();
|
|
194
|
+
break;
|
|
195
|
+
|
|
196
|
+
case "files":
|
|
197
|
+
process_files();
|
|
198
|
+
break;
|
|
199
|
+
|
|
200
|
+
case "innerHTML":
|
|
201
|
+
case "innerText":
|
|
202
|
+
case "textContent":
|
|
203
|
+
process_contenteditable();
|
|
204
|
+
break;
|
|
205
|
+
|
|
206
|
+
case "videoHeight":
|
|
207
|
+
case "videoWidth":
|
|
208
|
+
process_media_resize("VIDEO", "resize");
|
|
209
|
+
break;
|
|
210
|
+
|
|
211
|
+
case "naturalHeight":
|
|
212
|
+
case "naturalWidth":
|
|
213
|
+
process_media_resize("IMG", "load");
|
|
214
|
+
break;
|
|
215
|
+
|
|
216
|
+
case "clientHeight":
|
|
217
|
+
case "clientWidth":
|
|
218
|
+
case "offsetHeight":
|
|
219
|
+
case "offsetWidth":
|
|
220
|
+
process_dimensions();
|
|
221
|
+
break;
|
|
222
|
+
|
|
223
|
+
case "indeterminate":
|
|
224
|
+
process_indeterminate();
|
|
225
|
+
break;
|
|
226
|
+
|
|
227
|
+
case "open":
|
|
228
|
+
process_open_attribute();
|
|
229
|
+
break;
|
|
230
|
+
|
|
231
|
+
case "group":
|
|
232
|
+
process_group();
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (!processed) {
|
|
237
|
+
const modifier =
|
|
238
|
+
has_modifier(modifiers, "in") ? "in" :
|
|
239
|
+
has_modifier(modifiers, "out") ? "out" : "inout";
|
|
240
|
+
|
|
241
|
+
const source_el = expression === value
|
|
242
|
+
? closest(el.parentNode, node => node._x_dataStack)
|
|
243
|
+
: el;
|
|
244
|
+
|
|
245
|
+
if (!el._x_dataStack) {
|
|
246
|
+
warn("x-bound directive requires the presence of the x-data directive to bind component properties");
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (!source_el) {
|
|
251
|
+
warn(`x-bound directive cannot find the parent scope where the '${ value }' property is defined`);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const source = {
|
|
256
|
+
get: create_getter(evaluateLater, source_el, expression),
|
|
257
|
+
set: create_setter(evaluateLater, source_el, expression)
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const target = {
|
|
261
|
+
get: create_getter(evaluateLater, el, value),
|
|
262
|
+
set: create_setter(evaluateLater, el, value)
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
switch (modifier) {
|
|
266
|
+
case "in":
|
|
267
|
+
cleanup(watch(() => source.get(), v => target.set(clone(v))));
|
|
268
|
+
break;
|
|
269
|
+
case "out":
|
|
270
|
+
cleanup(watch(() => target.get(), v => source.set(clone(v))));
|
|
271
|
+
break;
|
|
272
|
+
default:
|
|
273
|
+
cleanup(entangle(source, target));
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function process_value() {
|
|
279
|
+
switch (tag_name) {
|
|
280
|
+
case "INPUT":
|
|
281
|
+
case "TEXTAREA":
|
|
282
|
+
// if the value of the bound property is "null" or "undefined",
|
|
283
|
+
// we initialize it with the value from the element.
|
|
284
|
+
is_nullish(get_value()) && update_variable();
|
|
285
|
+
|
|
286
|
+
effect(update_property);
|
|
287
|
+
cleanup(listen(el, "input", update_variable));
|
|
288
|
+
|
|
289
|
+
processed = true;
|
|
290
|
+
break;
|
|
291
|
+
|
|
292
|
+
case "SELECT":
|
|
293
|
+
// WORKAROUND:
|
|
294
|
+
// For the "select" element, there might be a situation
|
|
295
|
+
// where options are generated dynamically using the "x-for" directive,
|
|
296
|
+
// and in this case, attempting to set the "value" property
|
|
297
|
+
// will have no effect since there are no options yet.
|
|
298
|
+
// Therefore, we use a small trick to set the value a bit later
|
|
299
|
+
// when the "x-for" directive has finished its work.
|
|
300
|
+
setTimeout(() => {
|
|
301
|
+
// if the value of the bound property is "null" or "undefined",
|
|
302
|
+
// we initialize it with the value from the element.
|
|
303
|
+
is_nullish(get_value()) && update_variable();
|
|
304
|
+
|
|
305
|
+
effect(() => apply_select_values(el, as_array(get_value() ?? [])));
|
|
306
|
+
cleanup(listen(el, "change", () => set_value(collect_selected_values(el))));
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
processed = true;
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function process_checked() {
|
|
315
|
+
if (is_checkable_input(el)) {
|
|
316
|
+
effect(update_property);
|
|
317
|
+
cleanup(listen(el, "change", update_variable));
|
|
318
|
+
processed = true;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function process_indeterminate() {
|
|
323
|
+
if (el.type === "checkbox") {
|
|
324
|
+
is_nullish(get_value()) && update_variable();
|
|
325
|
+
effect(update_property);
|
|
326
|
+
cleanup(listen(el, "change", update_variable));
|
|
327
|
+
processed = true;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function process_files() {
|
|
332
|
+
if (el.type === "file") {
|
|
333
|
+
get_value() instanceof FileList || update_variable();
|
|
334
|
+
|
|
335
|
+
effect(update_property);
|
|
336
|
+
cleanup(listen(el, "input", update_variable));
|
|
337
|
+
processed = true;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function process_contenteditable() {
|
|
342
|
+
if (el.isContentEditable) {
|
|
343
|
+
is_nullish(get_value()) && update_variable();
|
|
344
|
+
|
|
345
|
+
effect(update_property);
|
|
346
|
+
cleanup(listen(el, "input", update_variable));
|
|
347
|
+
processed = true;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function process_media_resize(name, event_name) {
|
|
352
|
+
if (tag_name === name) {
|
|
353
|
+
update_variable();
|
|
354
|
+
cleanup(listen(el, event_name, update_variable));
|
|
355
|
+
processed = true;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function process_dimensions() {
|
|
360
|
+
cleanup(observe_resize(el, update_variable));
|
|
361
|
+
processed = true;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function process_open_attribute() {
|
|
365
|
+
const [is_details, is_dialog] = [tag_name === "DETAILS", tag_name === "DIALOG"];
|
|
366
|
+
|
|
367
|
+
if (is_details || is_dialog) {
|
|
368
|
+
//
|
|
369
|
+
// <details>:
|
|
370
|
+
// Supports safe two-way binding via the "open" attribute,
|
|
371
|
+
// so we initialize from the element only if the bound value
|
|
372
|
+
// is null or undefined.
|
|
373
|
+
//
|
|
374
|
+
// <dialog>:
|
|
375
|
+
// Directly setting element.open is discouraged by the spec,
|
|
376
|
+
// as it breaks native dialog behavior and the "close" event.
|
|
377
|
+
// Therefore, we always initialize state from the element
|
|
378
|
+
// and treat it as a one-way source of truth.
|
|
379
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/open#value
|
|
380
|
+
//
|
|
381
|
+
(is_dialog || is_nullish(get_value())) && update_variable();
|
|
382
|
+
|
|
383
|
+
//
|
|
384
|
+
// Enable two-way binding only for "<details>"
|
|
385
|
+
//
|
|
386
|
+
is_details && effect(update_property);
|
|
387
|
+
cleanup(listen(el, "toggle", update_variable));
|
|
388
|
+
processed = true;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function process_group() {
|
|
393
|
+
if (is_checkable_input(el)) {
|
|
394
|
+
el.name || mutateDom(() => el.name = expression);
|
|
395
|
+
|
|
396
|
+
effect(() =>
|
|
397
|
+
mutateDom(() =>
|
|
398
|
+
apply_group_values(el, get_value() ?? [])));
|
|
399
|
+
|
|
400
|
+
cleanup(listen(el, "input", () => set_value(collect_group_values(el, get_value()))));
|
|
401
|
+
processed = true;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
});
|
|
447
405
|
}
|
|
448
406
|
|
|
449
|
-
function
|
|
450
|
-
|
|
451
|
-
const placeholder_regex = /{{(?<expr>.+?)}}/g;
|
|
452
|
-
const is_once = has_modifier(modifiers, "once");
|
|
453
|
-
const has_format_attr = el => el.hasAttribute("x-format");
|
|
454
|
-
|
|
455
|
-
process(el);
|
|
456
|
-
|
|
457
|
-
function update(callback) {
|
|
458
|
-
if (is_once) {
|
|
459
|
-
mutateDom(() => callback());
|
|
460
|
-
}
|
|
461
|
-
else {
|
|
462
|
-
effect(() => mutateDom(() => callback()));
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
function process(node) {
|
|
467
|
-
switch (node.nodeType) {
|
|
468
|
-
case Node.TEXT_NODE:
|
|
469
|
-
process_text_node(node);
|
|
470
|
-
break;
|
|
471
|
-
|
|
472
|
-
case Node.ELEMENT_NODE:
|
|
473
|
-
if (node !== el) {
|
|
474
|
-
//
|
|
475
|
-
// When we encounter an element with the "x-data" attribute, its properties
|
|
476
|
-
// are not yet initialized, and the Alpine context is unavailable.
|
|
477
|
-
// Attempting to use these properties will result in
|
|
478
|
-
// an "Alpine Expression Error: [expression] is not defined".
|
|
479
|
-
//
|
|
480
|
-
// Workaround:
|
|
481
|
-
// To avoid this, we manually add our "x-format" directive to the element.
|
|
482
|
-
// Alpine evaluates "x-format" directive once the context is initialized.
|
|
483
|
-
// In the current loop, we skip these elements to defer their processing.
|
|
484
|
-
//
|
|
485
|
-
// This also handles cases where the user manually adds the "x-format" attribute.
|
|
486
|
-
//
|
|
487
|
-
if (node.hasAttribute("x-data") && !has_format_attr(node)) {
|
|
488
|
-
node.setAttribute("x-format", "");
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
if (has_format_attr(node)) {
|
|
492
|
-
break;
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
process_nodes(node);
|
|
498
|
-
process_attributes(node);
|
|
499
|
-
break;
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
function process_text_node(node) {
|
|
504
|
-
const tokens = node.textContent.split(placeholder_regex);
|
|
505
|
-
|
|
506
|
-
if (tokens.length > 1) {
|
|
507
|
-
const fragment = new DocumentFragment();
|
|
508
|
-
|
|
509
|
-
for (let i = 0; i < tokens.length; i++) {
|
|
510
|
-
if ((i % 2) === 0) {
|
|
511
|
-
fragment.appendChild(document.createTextNode(tokens[i]));
|
|
512
|
-
}
|
|
513
|
-
else {
|
|
514
|
-
const get_value = create_getter(evaluateLater, node.parentNode, tokens[i]);
|
|
515
|
-
const text = document.createTextNode("");
|
|
516
|
-
|
|
517
|
-
fragment.append(text);
|
|
518
|
-
update(() => text.textContent = get_value());
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
mutateDom(() =>
|
|
523
|
-
node.parentElement.replaceChild(fragment, node));
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
function process_attributes(node) {
|
|
528
|
-
for (let attr of node.attributes) {
|
|
529
|
-
const matches = [...attr.value.matchAll(placeholder_regex)];
|
|
530
|
-
if (matches.length) {
|
|
531
|
-
const template = attr.value;
|
|
532
|
-
update(() => attr.value = template.replace(placeholder_regex, (_, expr) => create_getter(evaluateLater, node, expr)()));
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
function process_nodes(node) {
|
|
538
|
-
for (let child of node.childNodes) {
|
|
539
|
-
process(child);
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
});
|
|
407
|
+
function to_number(value) {
|
|
408
|
+
return value === "" ? null : +value;
|
|
543
409
|
}
|
|
544
410
|
|
|
545
|
-
function
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
initialize();
|
|
551
|
-
|
|
552
|
-
let nodes = is_template(template)
|
|
553
|
-
? [...template.content.cloneNode(true).childNodes]
|
|
554
|
-
: [template.cloneNode(true)];
|
|
555
|
-
|
|
556
|
-
mutateDom(() => {
|
|
557
|
-
for (let node of nodes) {
|
|
558
|
-
is_element(node) && addScopeToNode(node, scope, el);
|
|
559
|
-
el.parentElement.insertBefore(node, el);
|
|
560
|
-
is_element(node) && initTree(node);
|
|
561
|
-
}
|
|
562
|
-
});
|
|
563
|
-
|
|
564
|
-
el._r_block = {
|
|
565
|
-
template,
|
|
566
|
-
update() {
|
|
567
|
-
mutateDom(() => {
|
|
568
|
-
for (let node of nodes ?? []) {
|
|
569
|
-
el.parentElement.insertBefore(node, el);
|
|
570
|
-
}
|
|
571
|
-
});
|
|
572
|
-
},
|
|
573
|
-
delete() {
|
|
574
|
-
el._r_block = null;
|
|
575
|
-
for (let node of nodes ?? []) {
|
|
576
|
-
node.remove();
|
|
577
|
-
}
|
|
578
|
-
nodes = null;
|
|
579
|
-
}
|
|
580
|
-
};
|
|
581
|
-
|
|
582
|
-
cleanup(() => el._r_block?.delete());
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
function initialize() {
|
|
586
|
-
document.body._r_block ??= (() => {
|
|
587
|
-
const observer = new MutationObserver(mutations => {
|
|
588
|
-
for (let mutation of mutations) {
|
|
589
|
-
for (let node of mutation.addedNodes) {
|
|
590
|
-
node._r_block?.update();
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
});
|
|
594
|
-
|
|
595
|
-
observer.observe(document.body, { childList: true, subtree: true });
|
|
596
|
-
return observer;
|
|
597
|
-
})();
|
|
411
|
+
function apply_select_values(el, values) {
|
|
412
|
+
for (const option of el.options) {
|
|
413
|
+
option.selected = loose_index_of(values, option.value) >= 0;
|
|
414
|
+
}
|
|
598
415
|
}
|
|
599
416
|
|
|
600
|
-
function
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
417
|
+
function collect_selected_values(el) {
|
|
418
|
+
if (el.multiple) {
|
|
419
|
+
return [...el.selectedOptions].map(o => o.value);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return el.value;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function apply_group_values(el, values) {
|
|
426
|
+
el.checked = is_array(values)
|
|
427
|
+
? loose_index_of(values, el.value) >= 0
|
|
428
|
+
: loose_equal(el.value, values);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function collect_group_values(el, values) {
|
|
432
|
+
if (el.type === "radio") {
|
|
433
|
+
return el.value;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
values = as_array(values);
|
|
437
|
+
const index = loose_index_of(values, el.value);
|
|
438
|
+
|
|
439
|
+
if (el.checked) {
|
|
440
|
+
index >= 0 || values.push(el.value);
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
index >= 0 && values.splice(index, 1);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return values;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function plugin$5({ directive, evaluateLater, mutateDom }) {
|
|
450
|
+
directive("format", (el, { modifiers }, { effect }) => {
|
|
451
|
+
const placeholder_regex = /{{(?<expr>.+?)}}/g;
|
|
452
|
+
const is_once = has_modifier(modifiers, "once");
|
|
453
|
+
const has_format_attr = el => el.hasAttribute("x-format");
|
|
454
|
+
|
|
455
|
+
process(el);
|
|
456
|
+
|
|
457
|
+
function update(callback) {
|
|
458
|
+
if (is_once) {
|
|
459
|
+
mutateDom(() => callback());
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
effect(() => mutateDom(() => callback()));
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function process(node) {
|
|
467
|
+
switch (node.nodeType) {
|
|
468
|
+
case Node.TEXT_NODE:
|
|
469
|
+
process_text_node(node);
|
|
470
|
+
break;
|
|
471
|
+
|
|
472
|
+
case Node.ELEMENT_NODE:
|
|
473
|
+
if (node !== el) {
|
|
474
|
+
//
|
|
475
|
+
// When we encounter an element with the "x-data" attribute, its properties
|
|
476
|
+
// are not yet initialized, and the Alpine context is unavailable.
|
|
477
|
+
// Attempting to use these properties will result in
|
|
478
|
+
// an "Alpine Expression Error: [expression] is not defined".
|
|
479
|
+
//
|
|
480
|
+
// Workaround:
|
|
481
|
+
// To avoid this, we manually add our "x-format" directive to the element.
|
|
482
|
+
// Alpine evaluates "x-format" directive once the context is initialized.
|
|
483
|
+
// In the current loop, we skip these elements to defer their processing.
|
|
484
|
+
//
|
|
485
|
+
// This also handles cases where the user manually adds the "x-format" attribute.
|
|
486
|
+
//
|
|
487
|
+
if (node.hasAttribute("x-data") && !has_format_attr(node)) {
|
|
488
|
+
node.setAttribute("x-format", "");
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
if (has_format_attr(node)) {
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
process_nodes(node);
|
|
497
|
+
process_attributes(node);
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function process_text_node(node) {
|
|
503
|
+
const tokens = node.textContent.split(placeholder_regex);
|
|
504
|
+
|
|
505
|
+
if (tokens.length > 1) {
|
|
506
|
+
const fragment = new DocumentFragment();
|
|
507
|
+
|
|
508
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
509
|
+
if ((i % 2) === 0) {
|
|
510
|
+
fragment.appendChild(document.createTextNode(tokens[i]));
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
const get_value = create_getter(evaluateLater, node.parentNode, tokens[i]);
|
|
514
|
+
const text = document.createTextNode("");
|
|
515
|
+
|
|
516
|
+
fragment.append(text);
|
|
517
|
+
update(() => text.textContent = get_value());
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
mutateDom(() =>
|
|
522
|
+
node.parentElement.replaceChild(fragment, node));
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function process_attributes(node) {
|
|
527
|
+
for (let attr of node.attributes) {
|
|
528
|
+
const matches = [...attr.value.matchAll(placeholder_regex)];
|
|
529
|
+
if (matches.length) {
|
|
530
|
+
const template = attr.value;
|
|
531
|
+
update(() => attr.value = template.replace(placeholder_regex, (_, expr) => create_getter(evaluateLater, node, expr)()));
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function process_nodes(node) {
|
|
537
|
+
for (let child of node.childNodes) {
|
|
538
|
+
process(child);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
function anchor_block(el, template, { addScopeToNode, cleanup, initTree, mutateDom, scope = {} }) {
|
|
545
|
+
if (el._r_block) {
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
initialize();
|
|
550
|
+
|
|
551
|
+
let nodes = is_template(template)
|
|
552
|
+
? [...template.content.cloneNode(true).childNodes]
|
|
553
|
+
: [template.cloneNode(true)];
|
|
554
|
+
|
|
555
|
+
mutateDom(() => {
|
|
556
|
+
for (let node of nodes) {
|
|
557
|
+
is_element(node) && addScopeToNode(node, scope, el);
|
|
558
|
+
el.parentElement.insertBefore(node, el);
|
|
559
|
+
is_element(node) && initTree(node);
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
el._r_block = {
|
|
564
|
+
template,
|
|
565
|
+
update() {
|
|
566
|
+
mutateDom(() => {
|
|
567
|
+
for (let node of nodes ?? []) {
|
|
568
|
+
el.parentElement.insertBefore(node, el);
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
},
|
|
572
|
+
delete() {
|
|
573
|
+
el._r_block = null;
|
|
574
|
+
for (let node of nodes ?? []) {
|
|
575
|
+
node.remove();
|
|
576
|
+
}
|
|
577
|
+
nodes = null;
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
cleanup(() => el._r_block?.delete());
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function initialize() {
|
|
585
|
+
document.body._r_block ??= (() => {
|
|
586
|
+
const observer = new MutationObserver(mutations => {
|
|
587
|
+
for (let mutation of mutations) {
|
|
588
|
+
for (let node of mutation.addedNodes) {
|
|
589
|
+
node._r_block?.update();
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
595
|
+
return observer;
|
|
596
|
+
})();
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
function plugin$4({ addScopeToNode, directive, initTree, mutateDom }) {
|
|
600
|
+
directive("fragment", (el, {}, { cleanup }) => {
|
|
601
|
+
if (!is_template(el)) {
|
|
602
|
+
warn("x-fragment can only be used on a 'template' tag");
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
anchor_block(el, el, { addScopeToNode, cleanup, initTree, mutateDom });
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
function plugin$3({ addScopeToNode, directive, initTree, mutateDom }) {
|
|
611
|
+
directive("match", (el, { }, { cleanup, effect, evaluateLater }) => {
|
|
612
|
+
if (!is_template(el)) {
|
|
613
|
+
warn("x-match can only be used on a 'template' tag");
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
const branches = [];
|
|
618
|
+
const has_default_case = () => branches.some(b => b.default);
|
|
619
|
+
|
|
620
|
+
for (let node of el.content.children) {
|
|
621
|
+
const expr = node.getAttribute("x-case");
|
|
622
|
+
if (expr !== null) {
|
|
623
|
+
has_default_case() && warn("The x-case directive cannot be appear after x-default");
|
|
624
|
+
branches.push({ el: node, get_value: create_getter(evaluateLater, expr) });
|
|
625
|
+
}
|
|
626
|
+
else if (node.hasAttribute("x-default")) {
|
|
627
|
+
has_default_case() && warn("Only one x-default directive is allowed");
|
|
628
|
+
branches.push({ el: node, get_value: () => true, default: true });
|
|
629
|
+
}
|
|
630
|
+
else {
|
|
631
|
+
warn("Element has no x-case or x-default directive and will be ignored", node);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
const activate = branch => {
|
|
636
|
+
if (el._r_block?.template !== branch.el) {
|
|
637
|
+
clear();
|
|
638
|
+
anchor_block(el, branch.el, {
|
|
639
|
+
addScopeToNode,
|
|
640
|
+
cleanup,
|
|
641
|
+
initTree,
|
|
642
|
+
mutateDom
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
|
|
647
|
+
const clear = () => el._r_block?.delete();
|
|
648
|
+
|
|
649
|
+
effect(() => {
|
|
650
|
+
let active;
|
|
651
|
+
|
|
652
|
+
for (let branch of branches) {
|
|
653
|
+
if (branch.get_value() && !active) {
|
|
654
|
+
active = branch;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
active ? activate(active) : clear();
|
|
659
|
+
});
|
|
660
|
+
});
|
|
609
661
|
}
|
|
610
662
|
|
|
611
|
-
function plugin$2(
|
|
612
|
-
directive("
|
|
613
|
-
if (
|
|
614
|
-
warn("x-
|
|
615
|
-
return;
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
const
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
const activate = branch => {
|
|
637
|
-
if (el._r_block?.template !== branch.el) {
|
|
638
|
-
clear();
|
|
639
|
-
anchor_block(el, branch.el, {
|
|
640
|
-
addScopeToNode,
|
|
641
|
-
cleanup,
|
|
642
|
-
initTree,
|
|
643
|
-
mutateDom
|
|
644
|
-
});
|
|
645
|
-
}
|
|
646
|
-
};
|
|
647
|
-
|
|
648
|
-
const clear = () => el._r_block?.delete();
|
|
649
|
-
|
|
650
|
-
effect(() => {
|
|
651
|
-
let active;
|
|
652
|
-
|
|
653
|
-
for (let branch of branches) {
|
|
654
|
-
if (branch.get_value() && !active) {
|
|
655
|
-
active = branch;
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
active ? activate(active) : clear();
|
|
660
|
-
});
|
|
661
|
-
});
|
|
663
|
+
function plugin$2(alpine) {
|
|
664
|
+
alpine.directive("template", (el, { expression }) => {
|
|
665
|
+
if (is_template(el)) {
|
|
666
|
+
warn("x-template cannot be used on a 'template' tag");
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
const tpl = document.getElementById(expression);
|
|
671
|
+
|
|
672
|
+
if (!is_template(tpl)) {
|
|
673
|
+
warn("x-template directive can only reference the template tag");
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// Adding a queued task ensures asynchronous content update, allowing Alpine.js
|
|
678
|
+
// to handle context propagation for cloned elements properly.
|
|
679
|
+
// This is important because manipulation can occur within the mutateDom function
|
|
680
|
+
// when mutation observing is disabled, preventing proper context propagation
|
|
681
|
+
// for cloned elements.
|
|
682
|
+
queueMicrotask(() => {
|
|
683
|
+
el.innerHTML = "";
|
|
684
|
+
el.append(tpl.content.cloneNode(true));
|
|
685
|
+
});
|
|
686
|
+
});
|
|
662
687
|
}
|
|
663
688
|
|
|
664
|
-
function plugin$1(
|
|
665
|
-
|
|
666
|
-
if (is_template(el)) {
|
|
667
|
-
warn("x-
|
|
668
|
-
return;
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
const
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
// Adding a queued task ensures asynchronous content update, allowing Alpine.js
|
|
679
|
-
// to handle context propagation for cloned elements properly.
|
|
680
|
-
// This is important because manipulation can occur within the mutateDom function
|
|
681
|
-
// when mutation observing is disabled, preventing proper context propagation
|
|
682
|
-
// for cloned elements.
|
|
683
|
-
queueMicrotask(() => {
|
|
684
|
-
el.innerHTML = "";
|
|
685
|
-
el.append(tpl.content.cloneNode(true));
|
|
686
|
-
});
|
|
687
|
-
});
|
|
689
|
+
function plugin$1({ addScopeToNode, directive, initTree, mutateDom }) {
|
|
690
|
+
directive("when", (el, { expression }, { cleanup, effect, evaluateLater }) => {
|
|
691
|
+
if (!is_template(el)) {
|
|
692
|
+
warn("x-when can only be used on a 'template' tag");
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
const activate = () => anchor_block(el, el, { addScopeToNode, cleanup, initTree, mutateDom });
|
|
697
|
+
const clear = () => el._r_block?.delete();
|
|
698
|
+
|
|
699
|
+
const get = create_getter(evaluateLater, expression);
|
|
700
|
+
effect(() => get() ? activate() : clear());
|
|
701
|
+
});
|
|
688
702
|
}
|
|
689
703
|
|
|
690
|
-
function plugin(
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
const activate = () => anchor_block(el, el, { addScopeToNode, cleanup, initTree, mutateDom });
|
|
698
|
-
const clear = () => el._r_block?.delete();
|
|
699
|
-
|
|
700
|
-
const get = create_getter(evaluateLater, expression);
|
|
701
|
-
effect(() => get() ? activate() : clear());
|
|
702
|
-
});
|
|
704
|
+
function plugin(alpine) {
|
|
705
|
+
plugin$6(alpine);
|
|
706
|
+
plugin$5(alpine);
|
|
707
|
+
plugin$4(alpine);
|
|
708
|
+
plugin$3(alpine);
|
|
709
|
+
plugin$2(alpine);
|
|
710
|
+
plugin$1(alpine);
|
|
703
711
|
}
|
|
704
712
|
|
|
705
|
-
export { plugin$
|
|
713
|
+
export { plugin$6 as bound, plugin as default, plugin$5 as format, plugin$4 as fragment, plugin$3 as match, plugin$2 as template, plugin$1 as when };
|