@oscarpalmer/abydon 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/abydon.full.js +1153 -0
  2. package/dist/constants.js +10 -0
  3. package/dist/fragment.js +60 -0
  4. package/dist/helpers/dom.js +28 -0
  5. package/dist/helpers/index.js +11 -0
  6. package/dist/index.js +6 -911
  7. package/dist/node/attribute/index.js +39 -0
  8. package/dist/node/attribute/value.js +56 -0
  9. package/dist/node/event.js +30 -0
  10. package/dist/node/index.js +52 -0
  11. package/dist/node/value.js +108 -0
  12. package/dist/parse.js +18 -0
  13. package/package.json +38 -27
  14. package/src/constants.ts +20 -0
  15. package/src/fragment.ts +63 -36
  16. package/src/helpers/dom.ts +5 -4
  17. package/src/helpers/index.ts +0 -9
  18. package/src/index.ts +13 -3
  19. package/src/models.ts +14 -11
  20. package/src/node/attribute/index.ts +28 -22
  21. package/src/node/attribute/value.ts +38 -42
  22. package/src/node/event.ts +12 -13
  23. package/src/node/index.ts +7 -7
  24. package/src/node/value.ts +169 -122
  25. package/src/{html.ts → parse.ts} +15 -17
  26. package/types/constants.d.ts +9 -0
  27. package/types/fragment.d.ts +3 -5
  28. package/types/helpers/index.d.ts +0 -3
  29. package/types/index.d.ts +4 -2
  30. package/types/models.d.ts +7 -9
  31. package/types/node/attribute/index.d.ts +2 -1
  32. package/types/node/attribute/value.d.ts +2 -1
  33. package/types/node/event.d.ts +1 -1
  34. package/types/node/value.d.ts +2 -2
  35. package/types/parse.d.ts +2 -0
  36. package/dist/fragment.mjs +0 -75
  37. package/dist/helpers/dom.mjs +0 -44
  38. package/dist/helpers/index.mjs +0 -25
  39. package/dist/html.mjs +0 -36
  40. package/dist/index.mjs +0 -6
  41. package/dist/node/attribute/index.mjs +0 -40
  42. package/dist/node/attribute/value.mjs +0 -89
  43. package/dist/node/event.mjs +0 -38
  44. package/dist/node/index.mjs +0 -60
  45. package/dist/node/value.mjs +0 -123
  46. package/types/html.d.ts +0 -4
  47. package/types/index.d.cts +0 -26
  48. /package/dist/{models.mjs → models.js} +0 -0
@@ -0,0 +1,1153 @@
1
+ const ACTIVE = {};
2
+ const BATCH = {
3
+ depth: 0,
4
+ handlers: /* @__PURE__ */ new Set()
5
+ };
6
+ const METHODS_AFFECTING_LENGTH = new Set([
7
+ "pop",
8
+ "push",
9
+ "shift",
10
+ "unshift"
11
+ ]);
12
+ const METHODS_UPDATE = new Set([
13
+ ...METHODS_AFFECTING_LENGTH,
14
+ "copyWithin",
15
+ "fill",
16
+ "reverse",
17
+ "sort",
18
+ "splice"
19
+ ]);
20
+ const NAME_ARRAY = "array";
21
+ const NAME_COMPUTED = "computed";
22
+ const NAME_EFFECT = "effect";
23
+ const NAME_SIGNAL = "signal";
24
+ const NAME_STORE = "store";
25
+ const NAMES = new Set([
26
+ NAME_ARRAY,
27
+ NAME_COMPUTED,
28
+ NAME_SIGNAL,
29
+ NAME_STORE
30
+ ]);
31
+
32
+ var Effect = class {
33
+ constructor(callback) {
34
+ Object.defineProperty(this, "$mora", { value: NAME_EFFECT });
35
+ this.state = { callback };
36
+ runEffect(this);
37
+ }
38
+ };
39
+ function runEffect(effect$1) {
40
+ const previousEffect = ACTIVE.effect;
41
+ ACTIVE.effect = effect$1;
42
+ try {
43
+ effect$1.state.callback();
44
+ } finally {
45
+ ACTIVE.effect = previousEffect;
46
+ }
47
+ }
48
+ function effect(callback) {
49
+ return typeof callback === "function" ? new Effect(callback) : void 0;
50
+ }
51
+
52
+ function isArray(value) {
53
+ return isMora(value, NAME_ARRAY);
54
+ }
55
+ function isComputed(value) {
56
+ return isMora(value, NAME_COMPUTED);
57
+ }
58
+ function isEffect(value) {
59
+ return isMora(value, NAME_EFFECT);
60
+ }
61
+ function isMora(value, name) {
62
+ return typeof value === "object" && value != null && "$mora" in value && (typeof name === "string" ? value.$mora === name : name.has(value.$mora));
63
+ }
64
+ function isReactive(value) {
65
+ return isMora(value, NAMES);
66
+ }
67
+ function isSignal(value) {
68
+ return isMora(value, NAME_SIGNAL);
69
+ }
70
+
71
+ function flushHandlers() {
72
+ while (BATCH.depth === 0 && BATCH.handlers.size > 0) {
73
+ const handlers = [...BATCH.handlers];
74
+ BATCH.handlers.clear();
75
+ for (const handler of handlers) if (isEffect(handler)) runEffect(handler);
76
+ else handler.callback(handler.state.value);
77
+ }
78
+ }
79
+ function startBatch() {
80
+ BATCH.depth += 1;
81
+ }
82
+ function stopBatch() {
83
+ if (BATCH.depth > 0) BATCH.depth -= 1;
84
+ flushHandlers();
85
+ }
86
+
87
+ var Subscription = class {
88
+ callback;
89
+ state;
90
+ constructor(state, callback) {
91
+ this.state = state;
92
+ this.callback = callback;
93
+ callback(state.value);
94
+ }
95
+ destroy() {
96
+ this.callback = noop;
97
+ this.state = void 0;
98
+ }
99
+ };
100
+ function noop() {}
101
+ function subscribe(state, callback) {
102
+ if (typeof callback !== "function" || state.subscriptions.has(callback)) return noop;
103
+ state.subscriptions.set(callback, new Subscription(state, callback));
104
+ return () => {
105
+ unsubscribe(state, callback);
106
+ };
107
+ }
108
+ function unsubscribe(state, callback) {
109
+ state.subscriptions.get(callback)?.destroy();
110
+ state.subscriptions.delete(callback);
111
+ }
112
+
113
+ var Reactive = class {
114
+ state = {
115
+ computeds: /* @__PURE__ */ new Set(),
116
+ effects: /* @__PURE__ */ new Set(),
117
+ equal: Object.is,
118
+ subscriptions: /* @__PURE__ */ new Map(),
119
+ value: void 0
120
+ };
121
+ constructor(name, value, options) {
122
+ this.state.value = value;
123
+ if (typeof options === "object" && typeof options.equal === "function") this.state.equal = options.equal;
124
+ Object.defineProperty(this, "$mora", { value: name });
125
+ }
126
+ peek() {
127
+ return this.state.value;
128
+ }
129
+ subscribe(callback) {
130
+ return subscribe(this.state, callback);
131
+ }
132
+ toJSON() {
133
+ return this.get();
134
+ }
135
+ toString() {
136
+ return String(this.get());
137
+ }
138
+ unsubscribe(callback) {
139
+ unsubscribe(this.state, callback);
140
+ }
141
+ };
142
+
143
+ var Computed = class extends Reactive {
144
+ effect = {
145
+ dirty: true,
146
+ instance: void 0
147
+ };
148
+ constructor(callback, options) {
149
+ super(NAME_COMPUTED, void 0, options);
150
+ this.effect.instance = effect(() => {
151
+ if (!this.effect.dirty) return;
152
+ const previousComputed = ACTIVE.computed;
153
+ ACTIVE.computed = this;
154
+ const value = callback();
155
+ ACTIVE.computed = previousComputed;
156
+ if (!this.state.equal(this.state.value, value)) {
157
+ this.state.value = value;
158
+ for (const computed$1 of this.state.computeds) computed$1.effect.dirty = true;
159
+ for (const effect$1 of this.state.effects) BATCH.handlers.add(effect$1);
160
+ for (const [, subscription] of this.state.subscriptions) subscription.callback(value);
161
+ }
162
+ this.effect.dirty = false;
163
+ });
164
+ }
165
+ get() {
166
+ if (ACTIVE.computed != null && this !== ACTIVE.computed) this.state.computeds.add(ACTIVE.computed);
167
+ if (ACTIVE.effect != null && ACTIVE.effect !== this.effect.instance) this.state.effects.add(ACTIVE.effect);
168
+ if (this.effect.dirty && BATCH.depth === 0) runEffect(this.effect.instance);
169
+ return this.state.value;
170
+ }
171
+ };
172
+ function computed(callback, options) {
173
+ return new Computed(callback, options);
174
+ }
175
+
176
+ function emitValue(state) {
177
+ for (const computed of state.computeds) computed.effect.dirty = true;
178
+ for (const effect of state.effects) BATCH.handlers.add(effect);
179
+ for (const [, subscription] of state.subscriptions) BATCH.handlers.add(subscription);
180
+ if (BATCH.depth === 0) flushHandlers();
181
+ }
182
+ function equalArrays(state, first, second) {
183
+ let { length } = first;
184
+ if (length !== second.length) return false;
185
+ let offset = 0;
186
+ if (length >= 100) {
187
+ offset = Math.round(length / 10);
188
+ offset = offset > 25 ? 25 : offset;
189
+ for (let index = 0; index < offset; index += 1) if (!state.equal(first[index], second[index])) return false;
190
+ }
191
+ length -= offset;
192
+ for (let index = offset; index < length; index += 1) if (!state.equal(first[index], second[index])) return false;
193
+ return true;
194
+ }
195
+ function getValue$1(state) {
196
+ if (ACTIVE.computed != null) state.computeds.add(ACTIVE.computed);
197
+ if (ACTIVE.effect != null) state.effects.add(ACTIVE.effect);
198
+ return state.value;
199
+ }
200
+
201
+ var Signal = class extends Reactive {
202
+ constructor(value, options) {
203
+ super(NAME_SIGNAL, value, options);
204
+ }
205
+ get() {
206
+ return getValue$1(this.state);
207
+ }
208
+ set(value) {
209
+ if (!this.state.equal(this.state.value, value)) {
210
+ this.state.value = value;
211
+ emitValue(this.state);
212
+ }
213
+ }
214
+ update(callback) {
215
+ this.set(callback(this.state.value));
216
+ }
217
+ };
218
+ function signal(value, options) {
219
+ return new Signal(value, options);
220
+ }
221
+
222
+ function getReactiveValueInProxy(reactive, mapped, key, isArray) {
223
+ let item = mapped.get(key);
224
+ if (item == null) {
225
+ item = computed(() => {
226
+ const value = reactive.get();
227
+ return isArray ? value.at(key) : value[key];
228
+ });
229
+ mapped.set(key, item);
230
+ }
231
+ return item;
232
+ }
233
+ function setProxyValue(proxy, value) {
234
+ startBatch();
235
+ const proxyKeys = Object.keys(proxy);
236
+ const valueKeys = Object.keys(value);
237
+ let { length } = proxyKeys;
238
+ for (let index = 0; index < length; index += 1) {
239
+ const key = proxyKeys[index];
240
+ proxy[key] = valueKeys.includes(key) ? value[key] : void 0;
241
+ }
242
+ length = valueKeys.length;
243
+ for (let index = 0; index < length; index += 1) {
244
+ const key = valueKeys[index];
245
+ if (!proxyKeys.includes(key)) proxy[key] = value[key];
246
+ }
247
+ stopBatch();
248
+ }
249
+ function setValueInProxy(parameters) {
250
+ const { isArray, length, property, state, target, value } = parameters;
251
+ if (isArray) {
252
+ if (!(!Number.isNaN(Number(property)) || property === "length")) return Reflect.set(target, property, value);
253
+ }
254
+ const previous = Reflect.get(target, property);
255
+ if (!state.equal(previous, value)) {
256
+ Reflect.set(target, property, value);
257
+ emitValue(state);
258
+ if (isArray) length?.set(target.length);
259
+ }
260
+ return true;
261
+ }
262
+
263
+ var ReactiveArray = class extends Reactive {
264
+ #indiced = /* @__PURE__ */ new Map();
265
+ #size = signal(0);
266
+ get length() {
267
+ return this.#size.get();
268
+ }
269
+ set length(value) {
270
+ if (typeof value === "number" && value >= 0 && value !== this.state.value.length) this.get().length = value;
271
+ }
272
+ constructor(value, options) {
273
+ super(NAME_ARRAY, new Proxy(value, {
274
+ get: (target, property) => METHODS_UPDATE.has(property) ? updateArray(property, target, this.state, this.#size) : Reflect.get(target, property),
275
+ set: (target, property, value$1) => setValueInProxy({
276
+ property,
277
+ target,
278
+ value: value$1,
279
+ isArray: true,
280
+ state: this.state,
281
+ length: this.#size
282
+ })
283
+ }), options);
284
+ this.#size.set(value.length);
285
+ }
286
+ clear() {
287
+ this.length = 0;
288
+ }
289
+ filter(callback) {
290
+ return computed(() => this.get().filter(callback));
291
+ }
292
+ get(first) {
293
+ if (typeof first === "number") return getReactiveValueInProxy(this, this.#indiced, first, true).get();
294
+ if (first === "length") return this.length;
295
+ return getValue$1(this.state);
296
+ }
297
+ map(callback) {
298
+ return computed(() => this.get().map(callback));
299
+ }
300
+ notify() {
301
+ emitValue(this.state);
302
+ }
303
+ peek(value) {
304
+ if (value === "length") return this.#size.peek();
305
+ if (typeof value === "number") return this.state.value.at(value);
306
+ return [...this.state.value];
307
+ }
308
+ pop() {
309
+ return this.state.value.pop();
310
+ }
311
+ push(...items) {
312
+ return this.state.value.push(...items);
313
+ }
314
+ set(first, second) {
315
+ if (first == null || Array.isArray(first)) this.state.value.splice(0, this.state.value.length, ...first ?? []);
316
+ else if (first === "length") this.length = second;
317
+ else if (typeof first === "number" && !Number.isNaN(first)) setAtIndex(this.state.value, first, second);
318
+ }
319
+ shift() {
320
+ return this.state.value.shift();
321
+ }
322
+ splice(from, to, ...items) {
323
+ return this.state.value.splice(from, to ?? this.state.value.length, ...items);
324
+ }
325
+ subscribe(first, second) {
326
+ if (typeof first === "number" && typeof second === "function") return getReactiveValueInProxy(this, this.#indiced, first, true).subscribe(second);
327
+ return typeof first === "function" ? subscribe(this.state, first) : noop;
328
+ }
329
+ unshift(...items) {
330
+ return this.state.value.unshift(...items);
331
+ }
332
+ update(callback) {
333
+ const updated = callback(this.state.value);
334
+ if (updated == null || Array.isArray(updated)) this.set(updated);
335
+ }
336
+ };
337
+ function array(value, options) {
338
+ return new ReactiveArray(Array.isArray(value) ? value : [], options);
339
+ }
340
+ function updateArray(type, array$1, state, length) {
341
+ const affectsLength = METHODS_AFFECTING_LENGTH.has(type);
342
+ const previousArray = affectsLength ? [] : [...array$1];
343
+ const previousLength = array$1.length;
344
+ return (...args) => {
345
+ const result = array$1[type](...args);
346
+ if (affectsLength ? array$1.length !== previousLength : !equalArrays(state, previousArray, array$1)) {
347
+ emitValue(state);
348
+ length.set(array$1.length);
349
+ }
350
+ return result;
351
+ };
352
+ }
353
+ function setAtIndex(array$1, index, value) {
354
+ const actual = index < 0 ? array$1.length + index : index;
355
+ if (actual > -1) array$1[actual] = value;
356
+ }
357
+
358
+ function isKey(value) {
359
+ return typeof value === "number" || typeof value === "string";
360
+ }
361
+ function isPlainObject$1(value) {
362
+ if (value === null || typeof value !== "object") return false;
363
+ if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
364
+ const prototype = Object.getPrototypeOf(value);
365
+ return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
366
+ }
367
+
368
+ function getString$1(value) {
369
+ if (typeof value === "string") return value;
370
+ if (value == null) return "";
371
+ if (typeof value !== "object") return String(value);
372
+ const asString = String(value.valueOf?.() ?? value);
373
+ return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
374
+ }
375
+
376
+ function isNullableOrWhitespace(value) {
377
+ return value == null || EXPRESSION_WHITESPACE.test(getString$1(value));
378
+ }
379
+ var EXPRESSION_WHITESPACE = /^\s*$/;
380
+
381
+ var Store = class extends Reactive {
382
+ #keyed = /* @__PURE__ */ new Map();
383
+ constructor(value, options) {
384
+ super(NAME_STORE, new Proxy(value, { set: (target, property, value$1) => setValueInProxy({
385
+ target,
386
+ property,
387
+ value: value$1,
388
+ isArray: false,
389
+ state: this.state
390
+ }) }), options);
391
+ }
392
+ get(key) {
393
+ return isKey(key) ? getReactiveValueInProxy(this, this.#keyed, key, false).get() : getValue$1(this.state);
394
+ }
395
+ peek(key) {
396
+ return isKey(key) ? this.state.value[key] : { ...this.state.value };
397
+ }
398
+ set(first, second) {
399
+ if (isKey(first)) this.state.value[first] = second;
400
+ else if (first == null || isPlainObject$1(first)) setProxyValue(this.state.value, first ?? {});
401
+ }
402
+ subscribe(first, second) {
403
+ if (isKey(first) && typeof second === "function") return getReactiveValueInProxy(this, this.#keyed, first, false).subscribe(second);
404
+ return typeof first === "function" ? subscribe(this.state, first) : noop;
405
+ }
406
+ update(callback) {
407
+ const updated = callback({ ...this.state.value });
408
+ if (updated == null || isPlainObject$1(updated)) setProxyValue(this.state.value, updated ?? {});
409
+ }
410
+ };
411
+ function store(value, options) {
412
+ return new Store(isPlainObject$1(value) ? value : {}, options);
413
+ }
414
+
415
+ function isChildNode(value) {
416
+ return value instanceof Node && CHILD_NODE_TYPES.has(value.nodeType);
417
+ }
418
+ function isHTMLOrSVGElement(value) {
419
+ return value instanceof HTMLElement || value instanceof SVGElement;
420
+ }
421
+ var CHILD_NODE_TYPES = new Set([
422
+ Node.ELEMENT_NODE,
423
+ Node.TEXT_NODE,
424
+ Node.PROCESSING_INSTRUCTION_NODE,
425
+ Node.COMMENT_NODE,
426
+ Node.DOCUMENT_TYPE_NODE
427
+ ]);
428
+
429
+ function getString(value) {
430
+ if (typeof value === "string") return value;
431
+ if (value == null) return "";
432
+ if (typeof value !== "object") return String(value);
433
+ const asString = String(value.valueOf?.() ?? value);
434
+ return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
435
+ }
436
+
437
+ function isPlainObject(value) {
438
+ if (value === null || typeof value !== "object") return false;
439
+ if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
440
+ const prototype = Object.getPrototypeOf(value);
441
+ return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
442
+ }
443
+
444
+ function isAttribute(value) {
445
+ return value instanceof Attr || isPlainObject(value) && typeof value.name === "string" && typeof value.value === "string";
446
+ }
447
+ function isBadAttribute(first, second) {
448
+ return validateAttribute((attribute) => attribute == null || EXPRESSION_ON_PREFIX.test(attribute.name) || EXPRESSION_SOURCE_PREFIX.test(attribute.name) && EXPRESSION_VALUE_PREFIX.test(String(attribute.value)), first, second);
449
+ }
450
+ function isBooleanAttribute(value) {
451
+ return validateAttribute((attribute) => attribute != null && booleanAttributes.includes(attribute.name.toLowerCase()), value, "");
452
+ }
453
+ function isEmptyNonBooleanAttribute(first, second) {
454
+ return validateAttribute((attribute) => attribute != null && !booleanAttributes.includes(attribute.name) && String(attribute.value).trim().length === 0, first, second);
455
+ }
456
+ function isInvalidBooleanAttribute(first, second) {
457
+ return validateAttribute((attribute) => {
458
+ if (attribute == null) return true;
459
+ if (!booleanAttributes.includes(attribute.name)) return false;
460
+ const normalized = String(attribute.value).toLowerCase().trim();
461
+ return !(normalized.length === 0 || normalized === attribute.name);
462
+ }, first, second);
463
+ }
464
+ function isProperty(value) {
465
+ return isPlainObject(value) && typeof value.name === "string";
466
+ }
467
+ function setAttribute$1(element, first, second) {
468
+ updateValue(element, first, second, updateAttribute);
469
+ }
470
+ function setProperty(element, first, second) {
471
+ updateValue(element, first, second, updateProperty$1);
472
+ }
473
+ function updateAttribute(element, name, value) {
474
+ if (booleanAttributes.includes(name.toLowerCase())) updateProperty$1(element, name, value, false);
475
+ else if (value == null) element.removeAttribute(name);
476
+ else element.setAttribute(name, typeof value === "string" ? value : getString(value));
477
+ }
478
+ function updateProperty$1(element, name, value, validate) {
479
+ const actual = validate ?? true ? name.toLowerCase() : name;
480
+ if (actual === "hidden") element.hidden = value === "" || value === true;
481
+ else element[actual] = value === "" || typeof value === "string" && value.toLowerCase() === actual || value === true;
482
+ }
483
+ function updateValue(element, first, second, callback) {
484
+ if (!isHTMLOrSVGElement(element)) return;
485
+ if (isProperty(first)) callback(element, first.name, first.value);
486
+ else if (typeof first === "string") callback(element, first, second);
487
+ }
488
+ function validateAttribute(callback, first, second) {
489
+ let attribute;
490
+ if (isAttribute(first)) attribute = first;
491
+ else if (typeof first === "string" && typeof second === "string") attribute = {
492
+ name: first,
493
+ value: second
494
+ };
495
+ return callback(attribute);
496
+ }
497
+ var EXPRESSION_ON_PREFIX = /^on/i;
498
+ var EXPRESSION_SOURCE_PREFIX = /^(href|src|xlink:href)$/i;
499
+ var EXPRESSION_VALUE_PREFIX = /(data:text\/html|javascript:)/i;
500
+ const booleanAttributes = Object.freeze([
501
+ "async",
502
+ "autofocus",
503
+ "autoplay",
504
+ "checked",
505
+ "controls",
506
+ "default",
507
+ "defer",
508
+ "disabled",
509
+ "formnovalidate",
510
+ "hidden",
511
+ "inert",
512
+ "ismap",
513
+ "itemscope",
514
+ "loop",
515
+ "multiple",
516
+ "muted",
517
+ "nomodule",
518
+ "novalidate",
519
+ "open",
520
+ "playsinline",
521
+ "readonly",
522
+ "required",
523
+ "reversed",
524
+ "selected"
525
+ ]);
526
+
527
+ function getOptions$1(input) {
528
+ const options = isPlainObject(input) ? input : {};
529
+ options.sanitizeBooleanAttributes = typeof options.sanitizeBooleanAttributes === "boolean" ? options.sanitizeBooleanAttributes : true;
530
+ return options;
531
+ }
532
+ function sanitize(value, options) {
533
+ return sanitizeNodes$1(Array.isArray(value) ? value : [value], getOptions$1(options));
534
+ }
535
+ function sanitizeAttributes(element, attributes, options) {
536
+ const { length } = attributes;
537
+ for (let index = 0; index < length; index += 1) {
538
+ const attribute = attributes[index];
539
+ if (isBadAttribute(attribute) || isEmptyNonBooleanAttribute(attribute)) element.removeAttribute(attribute.name);
540
+ else if (options.sanitizeBooleanAttributes && isInvalidBooleanAttribute(attribute)) element.setAttribute(attribute.name, "");
541
+ }
542
+ }
543
+ function sanitizeNodes$1(nodes, options) {
544
+ const actual = nodes.filter((node) => node instanceof Node);
545
+ const { length } = nodes;
546
+ for (let index = 0; index < length; index += 1) {
547
+ const node = actual[index];
548
+ if (node instanceof Element) sanitizeAttributes(node, [...node.attributes], options);
549
+ if (node.hasChildNodes()) sanitizeNodes$1([...node.childNodes], options);
550
+ }
551
+ return nodes;
552
+ }
553
+
554
+ function createTemplate(html$1) {
555
+ const template = document.createElement("template");
556
+ template.innerHTML = html$1;
557
+ templates[html$1] = template;
558
+ return template;
559
+ }
560
+ function getTemplate(value) {
561
+ if (typeof value !== "string" || value.trim().length === 0) return;
562
+ let template = templates[value];
563
+ if (template != null) return template;
564
+ const element = EXPRESSION_ID.test(value) ? document.querySelector(`#${value}`) : null;
565
+ template = element instanceof HTMLTemplateElement ? element : createTemplate(value);
566
+ templates[value] = template;
567
+ return template;
568
+ }
569
+ var html$1 = ((value, sanitization) => {
570
+ if (typeof value !== "string" && !(value instanceof HTMLTemplateElement)) return [];
571
+ let options;
572
+ if (sanitization == null || sanitization === true) options = {};
573
+ else options = sanitization === false ? void 0 : sanitization;
574
+ const template = value instanceof HTMLTemplateElement ? value : getTemplate(value);
575
+ if (template == null) return [];
576
+ const cloned = template.content.cloneNode(true);
577
+ const scripts = cloned.querySelectorAll("script");
578
+ const { length } = scripts;
579
+ for (let index = 0; index < length; index += 1) scripts[index].remove();
580
+ cloned.normalize();
581
+ return options != null ? sanitize([...cloned.childNodes], options) : [...cloned.childNodes];
582
+ });
583
+ html$1.clear = () => {
584
+ templates = {};
585
+ };
586
+ html$1.remove = (template) => {
587
+ if (typeof template === "string") templates[template] = void 0;
588
+ };
589
+ var EXPRESSION_ID = /^[a-z][\w-]*$/i;
590
+ var templates = {};
591
+
592
+ const ABORT_CONTROLLERS = new WeakMap();
593
+ const ATTRIBUTE_CLASS_PREFIX_LENGTH = 6;
594
+ const EXPRESSION_ATTRIBUTE_CLASS = /^class\./;
595
+ const EXPRESSION_ATTRIBUTE_STYLE_FULL = /^style\.([\w-]+)(?:\.([\w-]+))?$/;
596
+ const EXPRESSION_ATTRIBUTE_STYLE_PREFIX = /^style\./;
597
+ const EXPRESSION_COMMENT_FULL = /^<!--abydon\.(\d+)-->$/;
598
+ const EXPRESSION_COMMENT_CONTENT = /^abydon\.(\d+)$/;
599
+ const EXPRESSION_EVENT_NAME = /^@([\w-]+)(?::([a-z:]+))?$/i;
600
+ const REASON_EVENT_REMOVED = 'Event removed as element was removed from document by Abydon';
601
+
602
+ function getController(element) {
603
+ let controller = ABORT_CONTROLLERS.get(element);
604
+ if (controller == null) {
605
+ controller = new AbortController();
606
+ ABORT_CONTROLLERS.set(element, controller);
607
+ }
608
+ return controller;
609
+ }
610
+ function getOptions(options) {
611
+ const parts = options.split(':');
612
+ return {
613
+ capture: parts.includes('c') || parts.includes('capture'),
614
+ once: parts.includes('o') || parts.includes('once'),
615
+ passive: !(parts.includes('a') || parts.includes('active')),
616
+ };
617
+ }
618
+ function mapEvent(element, name, value) {
619
+ element.removeAttribute(name);
620
+ const [, type, options] = EXPRESSION_EVENT_NAME.exec(name) ?? [];
621
+ if (typeof value === 'function' && type != null) {
622
+ element.addEventListener(type, value, {
623
+ ...getOptions(options ?? ''),
624
+ signal: getController(element).signal,
625
+ });
626
+ }
627
+ }
628
+ function removeEvents(element) {
629
+ ABORT_CONTROLLERS.get(element)?.abort(REASON_EVENT_REMOVED);
630
+ ABORT_CONTROLLERS.delete(element);
631
+ }
632
+
633
+ function compareArrays(first, second) {
634
+ const firstIsLarger = first.length > second.length;
635
+ const from = firstIsLarger ? first : second;
636
+ const to = firstIsLarger ? second : first;
637
+ if (!from
638
+ .filter(key => to.includes(key))
639
+ .every((key, index) => to[index] === key)) {
640
+ return 'dissimilar';
641
+ }
642
+ return firstIsLarger ? 'removed' : 'added';
643
+ }
644
+ function isFragment(value) {
645
+ return (typeof value === 'object' &&
646
+ value != null &&
647
+ '$fragment' in value &&
648
+ value.$fragment === true);
649
+ }
650
+
651
+ function createNodes(value) {
652
+ if (isFragment(value)) {
653
+ return value.get();
654
+ }
655
+ if (isChildNode(value)) {
656
+ return [value];
657
+ }
658
+ return [new Text(getString$1(value))];
659
+ }
660
+ function removeNodes(nodes) {
661
+ sanitizeNodes(nodes);
662
+ const { length } = nodes;
663
+ for (let index = 0; index < length; index += 1) {
664
+ nodes[index].remove();
665
+ }
666
+ }
667
+ function replaceNodes(from, to) {
668
+ from[0]?.replaceWith(...to);
669
+ const { length } = from;
670
+ for (let index = 1; index < length; index += 1) {
671
+ from[index].remove();
672
+ }
673
+ }
674
+ function sanitizeNodes(nodes) {
675
+ const { length } = nodes;
676
+ for (let index = 0; index < length; index += 1) {
677
+ const node = nodes[index];
678
+ if (isHTMLOrSVGElement(node)) {
679
+ removeEvents(node);
680
+ }
681
+ if (node.hasChildNodes()) {
682
+ sanitizeNodes([...node.childNodes]);
683
+ }
684
+ }
685
+ }
686
+
687
+ function setAttribute(data, element, name, value) {
688
+ element.removeAttribute(name);
689
+ switch (true) {
690
+ case EXPRESSION_ATTRIBUTE_CLASS.test(name):
691
+ setClasses(data, element, name, value);
692
+ return;
693
+ case EXPRESSION_ATTRIBUTE_STYLE_PREFIX.test(name):
694
+ setStyle(data, element, name, value);
695
+ return;
696
+ default:
697
+ setValue(data, element, name, value);
698
+ break;
699
+ }
700
+ }
701
+ function setClasses(data, element, name, value) {
702
+ function update(value) {
703
+ if (value === true) {
704
+ element.classList.add(...classes);
705
+ }
706
+ else {
707
+ element.classList.remove(...classes);
708
+ }
709
+ }
710
+ const classes = name.slice(ATTRIBUTE_CLASS_PREFIX_LENGTH).split('.');
711
+ if (isReactive(value)) {
712
+ data.mora.subscribers.add(value.subscribe(update));
713
+ }
714
+ else {
715
+ update(value);
716
+ }
717
+ }
718
+ function setStyle(data, element, name, value) {
719
+ const [, property, unit] = EXPRESSION_ATTRIBUTE_STYLE_FULL.exec(name) ?? [];
720
+ if (property == null) {
721
+ return;
722
+ }
723
+ function update(value) {
724
+ if (value == null || value === false || (value === true && unit == null)) {
725
+ element.style.removeProperty(property);
726
+ }
727
+ else {
728
+ element.style.setProperty(property, value === true ? unit : getString$1(value));
729
+ }
730
+ }
731
+ if (isReactive(value)) {
732
+ data.mora.subscribers.add(value.subscribe(update));
733
+ }
734
+ else {
735
+ update(value);
736
+ }
737
+ }
738
+ function setValue(data, element, name, value) {
739
+ let callback;
740
+ if (isBooleanAttribute(name) && name in element) {
741
+ callback = name === 'selected' ? updateSelected : updateProperty;
742
+ }
743
+ else {
744
+ callback = setAttribute$1;
745
+ }
746
+ if (isReactive(value)) {
747
+ data.mora.subscribers.add(value.subscribe(next => {
748
+ callback(element, name, next);
749
+ }));
750
+ }
751
+ else {
752
+ callback(element, name, value);
753
+ }
754
+ }
755
+ function updateProperty(element, name, value) {
756
+ element[name] = value === true;
757
+ }
758
+ function updateSelected(element, name, value) {
759
+ const select = element.closest('select');
760
+ const options = [...(select?.options ?? [])];
761
+ if (select != null && options.includes(element)) {
762
+ select.dispatchEvent(new Event('change', { bubbles: true }));
763
+ }
764
+ updateProperty(element, name, value);
765
+ }
766
+
767
+ function getValue(data, original) {
768
+ const matches = EXPRESSION_COMMENT_FULL.exec(original ?? '');
769
+ return matches == null ? original : data.values[+matches[1]];
770
+ }
771
+ function mapAttributes(data, element) {
772
+ const attributes = [...element.attributes];
773
+ const { length } = attributes;
774
+ for (let index = 0; index < length; index += 1) {
775
+ const { name, value } = attributes[index];
776
+ const actual = getValue(data, value);
777
+ switch (true) {
778
+ case name.startsWith('@'):
779
+ mapEvent(element, name, actual);
780
+ break;
781
+ case name.includes('.') ||
782
+ typeof actual === 'function' ||
783
+ isReactive(actual):
784
+ mapValue$1(data, element, name, actual);
785
+ break;
786
+ case isBooleanAttribute(name):
787
+ setProperty(element, name, value);
788
+ break;
789
+ }
790
+ }
791
+ }
792
+ function mapValue$1(data, element, name, value) {
793
+ if (typeof value === 'function') {
794
+ setComputedAttribute(data, element, name, value);
795
+ }
796
+ else {
797
+ setAttribute(data, element, name, value);
798
+ }
799
+ }
800
+ function setComputedAttribute(data, element, name, callback) {
801
+ const value = computed(callback);
802
+ data.mora.values.add(value);
803
+ setAttribute(data, element, name, value);
804
+ }
805
+
806
+ //
807
+ function addToArray(identifiers, items, nodes, added) {
808
+ let position = nodes[0];
809
+ const before = added && !identifiers.previous.includes(items.templates[0].identifier);
810
+ const next = items.next.flatMap(fragment => fragment.get().flatMap(node => ({
811
+ identifier: fragment.identifier,
812
+ value: node,
813
+ })));
814
+ const { length } = next;
815
+ for (let index = 0; index < length; index += 1) {
816
+ const node = next[index];
817
+ if (!(added && identifiers.previous.includes(node.identifier))) {
818
+ if (index === 0 && before) {
819
+ position.before(node.value);
820
+ }
821
+ else {
822
+ position.after(node.value);
823
+ }
824
+ }
825
+ position = node.value;
826
+ }
827
+ }
828
+ function handleArray(identifiers, items, nodes) {
829
+ const next = items.templates.map(template => items.fragments?.find(fragment => fragment.identifier === template.identifier) ?? template);
830
+ const comparison = compareArrays(items.fragments ?? [], items.templates);
831
+ if (comparison !== 'removed') {
832
+ addToArray(identifiers, { ...items, next }, nodes, comparison === 'added');
833
+ }
834
+ const toRemove = items.fragments?.filter(fragment => !identifiers.next.includes(fragment.identifier)) ?? [];
835
+ const { length } = toRemove;
836
+ for (let index = 0; index < length; index += 1) {
837
+ toRemove[index].remove();
838
+ }
839
+ return {
840
+ fragments: next,
841
+ nodes: next.flatMap(fragment => fragment.get()),
842
+ };
843
+ }
844
+ function removeFragments(fragments) {
845
+ if (fragments != null) {
846
+ const { length } = fragments;
847
+ for (let index = 0; index < length; index += 1) {
848
+ fragments[index].remove();
849
+ }
850
+ }
851
+ }
852
+ function setArray(item, comment, value) {
853
+ if (value.length === 0) {
854
+ return {
855
+ nodes: setText(item, comment, value),
856
+ };
857
+ }
858
+ let templates = value.filter(item => isFragment(item) && item.identifier != null);
859
+ const next = templates.map(fragment => fragment.identifier);
860
+ const previous = item.fragments?.map(fragment => fragment.identifier) ?? [];
861
+ if (new Set(next).size !== templates.length) {
862
+ templates = [];
863
+ }
864
+ const noTemplates = templates.length === 0;
865
+ if (noTemplates ||
866
+ item.nodes == null ||
867
+ previous.some(identifier => identifier == null)) {
868
+ return {
869
+ fragments: noTemplates ? undefined : templates,
870
+ nodes: setNodes(item, comment, noTemplates
871
+ ? value.flatMap(item => createNodes(item))
872
+ : templates.flatMap(template => template.get())),
873
+ };
874
+ }
875
+ return handleArray({
876
+ next,
877
+ previous,
878
+ }, {
879
+ templates,
880
+ fragments: item.fragments ?? [],
881
+ }, item.nodes);
882
+ }
883
+ function setNodes(item, comment, next) {
884
+ if (item.nodes == null) {
885
+ if (comment.parentNode != null) {
886
+ replaceNodes([comment], next);
887
+ }
888
+ else if (item.text?.parentNode != null) {
889
+ replaceNodes([item.text], next);
890
+ }
891
+ }
892
+ else {
893
+ replaceNodes(item.nodes, next);
894
+ }
895
+ removeFragments(item.fragments);
896
+ return next;
897
+ }
898
+ function setReactiveValue(data, comment, reactive) {
899
+ let item = data.items.find(item => item.nodes?.includes(comment));
900
+ item ??= {};
901
+ item.text = new Text();
902
+ data.mora.subscribers.add(reactive.subscribe(value => {
903
+ if (Array.isArray(value)) {
904
+ setReactiveValueForArray(item, comment, value);
905
+ }
906
+ else {
907
+ setReactiveValueForSingle(item, comment, value);
908
+ }
909
+ item.nodes = [...(item.nodes ?? [comment])];
910
+ }));
911
+ }
912
+ function setReactiveValueForArray(item, comment, value) {
913
+ const result = setArray(item, comment, value);
914
+ item.fragments = typeof result === 'boolean' ? undefined : result?.fragments;
915
+ if (typeof result === 'boolean') {
916
+ item.nodes = result ? item.text == null ? [] : [item.text] : undefined;
917
+ }
918
+ else {
919
+ item.nodes = result?.nodes;
920
+ }
921
+ }
922
+ function setReactiveValueForSingle(item, comment, value) {
923
+ const valueIsFragment = isFragment(value);
924
+ item.fragments = valueIsFragment ? [value] : undefined;
925
+ if (valueIsFragment || isChildNode(value)) {
926
+ item.nodes = setNodes(item, comment, createNodes(value));
927
+ }
928
+ else {
929
+ item.nodes = setText(item, comment, value);
930
+ }
931
+ }
932
+ function setText(item, comment, value) {
933
+ const isNullable = isNullableOrWhitespace(value);
934
+ if (item.text != null) {
935
+ item.text.textContent = isNullable ? '' : getString$1(value);
936
+ }
937
+ let result = false;
938
+ if (item.nodes != null) {
939
+ replaceNodes(item.nodes, isNullable ? [comment] : item.text == null ? [] : [item.text]);
940
+ result = !isNullable;
941
+ }
942
+ else if (isNullable && comment.parentNode == null) {
943
+ item.text?.replaceWith(comment);
944
+ }
945
+ else if (!isNullable && item?.text?.parentNode == null) {
946
+ if (item.text != null) {
947
+ comment.replaceWith(item.text);
948
+ }
949
+ result = true;
950
+ }
951
+ removeFragments(item.fragments);
952
+ return result ? item.text == null ? [] : [item.text] : undefined;
953
+ }
954
+
955
+ function mapNode(data, comment) {
956
+ const matches = EXPRESSION_COMMENT_CONTENT.exec(comment.textContent ?? '');
957
+ const value = matches == null ? null : data.values[+matches[1]];
958
+ if (value != null) {
959
+ mapValue(data, comment, value);
960
+ }
961
+ }
962
+ function mapNodes(data, nodes) {
963
+ const { length } = nodes;
964
+ for (let index = 0; index < length; index += 1) {
965
+ const node = nodes[index];
966
+ if (node instanceof Comment) {
967
+ mapNode(data, node);
968
+ continue;
969
+ }
970
+ if (isHTMLOrSVGElement(node)) {
971
+ mapAttributes(data, node);
972
+ }
973
+ if (node.hasChildNodes()) {
974
+ mapNodes(data, [...node.childNodes]);
975
+ }
976
+ }
977
+ }
978
+ function mapValue(data, comment, value) {
979
+ switch (true) {
980
+ case typeof value === 'function':
981
+ setComputedValue(data, comment, value);
982
+ break;
983
+ case isReactive(value):
984
+ setReactiveValue(data, comment, value);
985
+ break;
986
+ default:
987
+ replaceComment(data, comment, value);
988
+ break;
989
+ }
990
+ }
991
+ function replaceComment(data, comment, value) {
992
+ const item = data.items.find(item => item.nodes?.includes(comment));
993
+ const nodes = createNodes(value);
994
+ if (item != null) {
995
+ item.fragments = isFragment(value) ? [value] : undefined;
996
+ item.nodes = nodes;
997
+ }
998
+ comment.replaceWith(...nodes);
999
+ }
1000
+ function setComputedValue(data, comment, callback) {
1001
+ const value = computed(callback);
1002
+ data.mora.values.add(value);
1003
+ setReactiveValue(data, comment, value);
1004
+ }
1005
+
1006
+ function handleExpression(data, prefix, expression) {
1007
+ if (Array.isArray(expression)) {
1008
+ const { length } = expression;
1009
+ let expressions = '';
1010
+ for (let index = 0; index < length; index += 1) {
1011
+ expressions += handleExpression(data, '', expression[index]);
1012
+ }
1013
+ return `${prefix}${expressions}`;
1014
+ }
1015
+ if (typeof expression === 'function' ||
1016
+ (typeof expression === 'object' && expression != null)) {
1017
+ const index = data.values.push(expression) - 1;
1018
+ return `${prefix}<!--abydon.${index}-->`;
1019
+ }
1020
+ return isNullableOrWhitespace(expression) ? prefix : `${prefix}${expression}`;
1021
+ }
1022
+ function parse(data) {
1023
+ if (data.template != null) {
1024
+ return data.template;
1025
+ }
1026
+ const { length } = data.strings;
1027
+ data.template = '';
1028
+ for (let index = 0; index < length; index += 1) {
1029
+ data.template += handleExpression(data, data.strings[index], data.expressions[index]);
1030
+ }
1031
+ data.expressions = [];
1032
+ data.strings = [];
1033
+ return data.template;
1034
+ }
1035
+
1036
+ function calculate() {
1037
+ return new Promise((resolve) => {
1038
+ const values = [];
1039
+ let last;
1040
+ function step(now) {
1041
+ if (last != null) values.push(now - last);
1042
+ last = now;
1043
+ if (values.length >= CALCULATION_TOTAL) resolve(values.sort().slice(2, -2).reduce((first, second) => first + second, 0) / (values.length - CALCULATION_TRIM));
1044
+ else requestAnimationFrame(step);
1045
+ }
1046
+ requestAnimationFrame(step);
1047
+ });
1048
+ }
1049
+ var CALCULATION_TOTAL = 10;
1050
+ var CALCULATION_TRIM = 4;
1051
+ calculate().then((value) => {
1052
+ });
1053
+
1054
+ class Fragment {
1055
+ #data;
1056
+ #configuration = {
1057
+ identifier: undefined,
1058
+ ignoreCache: false,
1059
+ };
1060
+ get identifier() {
1061
+ return this.#configuration.identifier;
1062
+ }
1063
+ constructor(strings, expressions) {
1064
+ this.#data = {
1065
+ expressions,
1066
+ strings,
1067
+ items: [],
1068
+ mora: {
1069
+ subscribers: new Set(),
1070
+ values: new Set(),
1071
+ },
1072
+ values: [],
1073
+ };
1074
+ Object.defineProperty(this, '$fragment', {
1075
+ value: true,
1076
+ });
1077
+ }
1078
+ /**
1079
+ * Appends the fragment to the given element
1080
+ */
1081
+ appendTo(element) {
1082
+ element.append(...this.get());
1083
+ }
1084
+ configure(configuration) {
1085
+ const actual = isPlainObject$1(configuration) ? configuration : {};
1086
+ if (actual.identifier !== undefined) {
1087
+ this.#configuration.identifier = actual.identifier;
1088
+ }
1089
+ if (typeof actual.ignoreCache === 'boolean') {
1090
+ this.#configuration.ignoreCache = actual.ignoreCache;
1091
+ }
1092
+ return this;
1093
+ }
1094
+ /**
1095
+ * Gets a list of the fragment's nodes
1096
+ */
1097
+ get() {
1098
+ const data = this.#data;
1099
+ if (data.items.length === 0) {
1100
+ const parsed = parse(data);
1101
+ const templated = html$1(parsed, {
1102
+ sanitizeBooleanAttributes: false,
1103
+ });
1104
+ if (this.#configuration.ignoreCache) {
1105
+ html$1.remove(parsed);
1106
+ }
1107
+ data.items.splice(0, data.items.length, ...templated.map(node => ({
1108
+ nodes: [node],
1109
+ })));
1110
+ mapNodes(data, data.items.flatMap(item => item.fragments?.flatMap(fragment => fragment.get()) ?? item.nodes ?? []));
1111
+ }
1112
+ return [
1113
+ ...data.items.flatMap(item => item.fragments?.flatMap(fragment => fragment.get()) ?? item.nodes ?? []),
1114
+ ];
1115
+ }
1116
+ identify(identifier) {
1117
+ this.#configuration.identifier = identifier;
1118
+ return this;
1119
+ }
1120
+ /**
1121
+ * Removes the fragment from the DOM
1122
+ */
1123
+ remove() {
1124
+ removeFragment(this.#data);
1125
+ }
1126
+ }
1127
+ function removeFragment(data) {
1128
+ removeMora(data);
1129
+ const { length } = data.items;
1130
+ for (let index = 0; index < length; index += 1) {
1131
+ const { fragments, nodes } = data.items[index];
1132
+ const length = fragments?.length ?? 0;
1133
+ for (let index = 0; index < length; index += 1) {
1134
+ fragments?.[index]?.remove();
1135
+ }
1136
+ removeNodes(nodes ?? []);
1137
+ }
1138
+ data.items.length = 0;
1139
+ }
1140
+ function removeMora(data) {
1141
+ const unsubscribers = [...data.mora.subscribers];
1142
+ data.mora.subscribers.clear();
1143
+ data.mora.values.clear();
1144
+ for (const unsubscribe of unsubscribers) {
1145
+ unsubscribe();
1146
+ }
1147
+ }
1148
+
1149
+ function html(strings, ...values) {
1150
+ return new Fragment(strings, values);
1151
+ }
1152
+
1153
+ export { array, computed, effect, html, isArray, isComputed, isEffect, isReactive, isSignal, signal, startBatch, stopBatch, store };