@oscarpalmer/abydon 0.20.0 → 0.22.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 (40) hide show
  1. package/README.md +2 -0
  2. package/dist/abydon.full.mjs +787 -276
  3. package/dist/attribute/index.d.mts +6 -0
  4. package/dist/{node/attribute → attribute}/index.mjs +10 -19
  5. package/dist/{node/attribute → attribute}/value.d.mts +2 -2
  6. package/dist/attribute/value.mjs +63 -0
  7. package/dist/constants.d.mts +7 -3
  8. package/dist/constants.mjs +12 -8
  9. package/dist/fragment.d.mts +45 -1
  10. package/dist/fragment.mjs +9 -3
  11. package/dist/fragments.d.mts +4 -6
  12. package/dist/fragments.mjs +5 -11
  13. package/dist/helpers/index.d.mts +11 -1
  14. package/dist/helpers/index.mjs +10 -0
  15. package/dist/index.d.mts +5 -4
  16. package/dist/index.mjs +8 -4
  17. package/dist/models.d.mts +43 -1
  18. package/dist/node/event.mjs +9 -4
  19. package/dist/node/index.d.mts +1 -1
  20. package/dist/node/index.mjs +19 -10
  21. package/dist/node/value.d.mts +1 -1
  22. package/dist/node/value.mjs +9 -12
  23. package/dist/parse.d.mts +1 -1
  24. package/dist/parse.mjs +6 -4
  25. package/package.json +8 -7
  26. package/src/{node/attribute → attribute}/index.ts +16 -33
  27. package/src/attribute/value.ts +140 -0
  28. package/src/constants.ts +16 -8
  29. package/src/fragment.ts +10 -5
  30. package/src/fragments.ts +4 -13
  31. package/src/helpers/index.ts +10 -0
  32. package/src/index.ts +16 -3
  33. package/src/node/event.ts +12 -5
  34. package/src/node/index.ts +31 -13
  35. package/src/node/value.ts +10 -25
  36. package/src/parse.ts +14 -4
  37. package/dist/fragment-9qTBAvtR.d.mts +0 -82
  38. package/dist/node/attribute/index.d.mts +0 -6
  39. package/dist/node/attribute/value.mjs +0 -65
  40. package/src/node/attribute/value.ts +0 -158
@@ -156,6 +156,11 @@ function unsubscribe(state, callback) {
156
156
  //#endregion
157
157
  //#region node_modules/@oscarpalmer/mora/dist/value/reactive.mjs
158
158
  var Reactive = class {
159
+ /**
160
+ * Internal state of the reactive value
161
+ *
162
+ * @internal
163
+ */
159
164
  state = {
160
165
  computeds: /* @__PURE__ */ new Set(),
161
166
  effects: /* @__PURE__ */ new Set(),
@@ -215,18 +220,10 @@ var Computed = class extends Reactive {
215
220
  constructor(callback, options) {
216
221
  super(NAME_COMPUTED, void 0, options);
217
222
  this.effect.instance = effect(() => {
218
- if (!this.effect.dirty) return;
219
- const previousComputed = ACTIVE.computed;
220
- ACTIVE.computed = this;
221
- const value = callback();
222
- ACTIVE.computed = previousComputed;
223
- if (!this.state.equal(this.state.value, value)) {
224
- this.state.value = value;
225
- for (const computed of this.state.computeds) computed.effect.dirty = true;
226
- for (const effect of this.state.effects) BATCH.handlers.add(effect);
227
- for (const [, subscription] of this.state.subscriptions) subscription.callback(value);
223
+ if (this.effect.dirty) {
224
+ setValue$2(this, this.state, callback);
225
+ this.effect.dirty = false;
228
226
  }
229
- this.effect.dirty = false;
230
227
  });
231
228
  }
232
229
  /**
@@ -248,6 +245,72 @@ var Computed = class extends Reactive {
248
245
  function computed(callback, options) {
249
246
  return new Computed(callback, options);
250
247
  }
248
+ function setAndEmit$1(state, value) {
249
+ if (state.equal(state.value, value)) return;
250
+ state.value = value;
251
+ for (const computed of state.computeds) computed.effect.dirty = true;
252
+ for (const effect of state.effects) BATCH.handlers.add(effect);
253
+ for (const [, subscription] of state.subscriptions) subscription.callback(value);
254
+ flushHandlers();
255
+ }
256
+ function setValue$2(instance, state, callback) {
257
+ const previousComputed = ACTIVE.computed;
258
+ ACTIVE.computed = instance;
259
+ try {
260
+ const value = callback();
261
+ if (value instanceof Promise) {
262
+ state.promise = value;
263
+ value.then((resolvedValue) => {
264
+ if (state.promise === value) {
265
+ state.promise = void 0;
266
+ setAndEmit$1(state, resolvedValue);
267
+ }
268
+ }).catch(() => {
269
+ if (state.promise === value) state.promise = void 0;
270
+ });
271
+ } else setAndEmit$1(state, value);
272
+ } finally {
273
+ ACTIVE.computed = previousComputed;
274
+ }
275
+ }
276
+ //#endregion
277
+ //#region node_modules/@oscarpalmer/mora/node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
278
+ /**
279
+ * Is the value a key?
280
+ * @param value Value to check
281
+ * @returns `true` if the value is a `Key` _(`number` or `string`)_, otherwise `false`
282
+ */
283
+ function isKey(value) {
284
+ return typeof value === "number" || typeof value === "string";
285
+ }
286
+ /**
287
+ * Is the value a plain object?
288
+ * @param value Value to check
289
+ * @returns `true` if the value is a plain object, otherwise `false`
290
+ */
291
+ function isPlainObject$1(value) {
292
+ if (value === null || typeof value !== "object") return false;
293
+ if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
294
+ const prototype = Object.getPrototypeOf(value);
295
+ return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
296
+ }
297
+ //#endregion
298
+ //#region node_modules/@oscarpalmer/mora/node_modules/@oscarpalmer/atoms/dist/math.mjs
299
+ /**
300
+ * Round a number
301
+ * @param value Number to round
302
+ * @param decimals Number of decimal places to round to _(defaults to `0`)_
303
+ * @returns Rounded number, or `NaN` if the value if unable to be rounded
304
+ */
305
+ function round(value, decimals) {
306
+ return roundNumber(Math.round, value, decimals);
307
+ }
308
+ function roundNumber(callback, value, decimals) {
309
+ if (typeof value !== "number") return NaN;
310
+ if (typeof decimals !== "number" || decimals < 1) return callback(value);
311
+ const mod = 10 ** decimals;
312
+ return callback((value + Number.EPSILON) * mod) / mod;
313
+ }
251
314
  //#endregion
252
315
  //#region node_modules/@oscarpalmer/mora/dist/helpers/value.mjs
253
316
  function emitValue(state) {
@@ -261,7 +324,7 @@ function equalArrays(state, first, second) {
261
324
  if (length !== second.length) return false;
262
325
  let offset = 0;
263
326
  if (length >= 100) {
264
- offset = Math.round(length / 10);
327
+ offset = round(length / 10);
265
328
  offset = offset > 25 ? 25 : offset;
266
329
  for (let index = 0; index < offset; index += 1) if (!state.equal(first[index], second[index])) return false;
267
330
  }
@@ -291,10 +354,7 @@ var Signal = class extends Reactive {
291
354
  * @param value New value
292
355
  */
293
356
  set(value) {
294
- if (!this.state.equal(this.state.value, value)) {
295
- this.state.value = value;
296
- emitValue(this.state);
297
- }
357
+ setValue$1(this.state, value);
298
358
  }
299
359
  /**
300
360
  * Update the value _(based on the current value)_
@@ -304,14 +364,33 @@ var Signal = class extends Reactive {
304
364
  this.set(callback(this.state.value));
305
365
  }
306
366
  };
307
- /**
308
- * Create a reactive value
309
- * @param value Initial value
310
- * @param options Reactivity options
311
- * @returns Reactive value
312
- */
367
+ function setAndEmit(state, value) {
368
+ if (!state.equal(state.value, value)) {
369
+ state.value = value;
370
+ emitValue(state);
371
+ }
372
+ }
373
+ function setValue$1(state, value) {
374
+ try {
375
+ let actual = value;
376
+ if (typeof value === "function") actual = value();
377
+ if (actual instanceof Promise) {
378
+ state.promise = actual;
379
+ actual.then((value) => {
380
+ if (actual === state.promise) {
381
+ state.promise = void 0;
382
+ setAndEmit(state, value);
383
+ }
384
+ }).catch(() => {
385
+ if (actual === state.promise) state.promise = void 0;
386
+ });
387
+ } else setAndEmit(state, actual);
388
+ } catch {}
389
+ }
313
390
  function signal(value, options) {
314
- return new Signal(value, options);
391
+ const instance = new Signal(void 0, options);
392
+ instance.set(value);
393
+ return instance;
315
394
  }
316
395
  //#endregion
317
396
  //#region node_modules/@oscarpalmer/mora/dist/helpers/proxy.mjs
@@ -329,21 +408,44 @@ function getReactiveValueInProxy(reactive, mapped, key, isArray) {
329
408
  }
330
409
  return item;
331
410
  }
332
- function setProxyValue(proxy, value) {
333
- startBatch();
334
- const proxyKeys = Object.keys(proxy);
335
- const valueKeys = Object.keys(value);
336
- let { length } = proxyKeys;
337
- for (let index = 0; index < length; index += 1) {
338
- const key = proxyKeys[index];
339
- proxy[key] = valueKeys.includes(key) ? value[key] : void 0;
411
+ function setProxyValue(array, state, isObject, isProperty, setObject, setProperty, first, second) {
412
+ if (array && first === "length") {
413
+ state.value.length = second;
414
+ return;
340
415
  }
341
- length = valueKeys.length;
342
- for (let index = 0; index < length; index += 1) {
343
- const key = valueKeys[index];
344
- if (!proxyKeys.includes(key)) proxy[key] = value[key];
416
+ if (isObject(first)) {
417
+ setObject(state, first);
418
+ return;
345
419
  }
346
- stopBatch();
420
+ const property = isProperty(first);
421
+ if (array && property && Number.isNaN(first)) return;
422
+ let actual = property ? second : first;
423
+ if (typeof actual === "function") try {
424
+ actual = actual();
425
+ } catch {
426
+ return;
427
+ }
428
+ if (actual instanceof Promise) {
429
+ if (property) {
430
+ state.promises ??= /* @__PURE__ */ new Map();
431
+ state.promises.set(first, actual);
432
+ } else state.promise = actual;
433
+ actual.then((value) => {
434
+ if (property && state.promises.get(first) === actual) {
435
+ state.promises.delete(first);
436
+ setProperty(state, first, value);
437
+ return;
438
+ }
439
+ if (!property && isObject(value) && state.promise === actual) {
440
+ state.promise = void 0;
441
+ setObject(state, value);
442
+ }
443
+ }).catch(() => {
444
+ if (property && state.promises.get(first) === actual) state.promises.delete(first);
445
+ else if (!property && state.promise === actual) state.promise = void 0;
446
+ });
447
+ } else if (property) setProperty(state, first, actual);
448
+ else if (isObject(actual)) setObject(state, actual);
347
449
  }
348
450
  function setValueInProxy(parameters) {
349
451
  const { isArray, length, property, state, target, value } = parameters;
@@ -426,7 +528,7 @@ var ReactiveArray = class extends Reactive {
426
528
  }
427
529
  peek(value) {
428
530
  if (value === "length") return this.#size.peek();
429
- return typeof value === "number" ? this.state.value.at(value) : [...this.state.value];
531
+ return typeof value === "number" ? this.state.value.at(value) : this.state.value.slice();
430
532
  }
431
533
  /**
432
534
  * Remove and return the last item of the array
@@ -444,9 +546,7 @@ var ReactiveArray = class extends Reactive {
444
546
  return this.state.value.push(...items);
445
547
  }
446
548
  set(first, second) {
447
- if (first == null || Array.isArray(first)) this.state.value.splice(0, this.state.value.length, ...first ?? []);
448
- else if (first === "length") this.length = second;
449
- else if (typeof first === "number" && !Number.isNaN(first)) setAtIndex(this.state.value, first, second);
549
+ setProxyValue(true, this.state, isArrayValue, isArrayIndex, setArray$1, setAtIndex, first, second);
450
550
  }
451
551
  /**
452
552
  * Remove and return the first item of the array
@@ -486,18 +586,20 @@ var ReactiveArray = class extends Reactive {
486
586
  if (updated == null || Array.isArray(updated)) this.set(updated);
487
587
  }
488
588
  };
489
- /**
490
- * Create a reactive array
491
- * @param value Initial array of items
492
- * @param options Reactivity options
493
- * @returns Reactive array
494
- */
495
589
  function array(value, options) {
496
- return new ReactiveArray(Array.isArray(value) ? value : [], options);
590
+ const instance = new ReactiveArray([], options);
591
+ instance.set(value);
592
+ return instance;
593
+ }
594
+ function isArrayIndex(value) {
595
+ return typeof value === "number";
596
+ }
597
+ function isArrayValue(value) {
598
+ return value == null || Array.isArray(value);
497
599
  }
498
600
  function updateArray(type, array, state, length) {
499
601
  const affectsLength = METHODS_AFFECTING_LENGTH.has(type);
500
- const previousArray = affectsLength ? [] : [...array];
602
+ const previousArray = affectsLength ? [] : array.slice();
501
603
  const previousLength = array.length;
502
604
  return (...args) => {
503
605
  const result = array[type](...args);
@@ -508,57 +610,13 @@ function updateArray(type, array, state, length) {
508
610
  return result;
509
611
  };
510
612
  }
511
- function setAtIndex(array, index, value) {
512
- const actual = index < 0 ? array.length + index : index;
513
- if (actual > -1) array[actual] = value;
514
- }
515
- //#endregion
516
- //#region node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
517
- /**
518
- * Is the value a key?
519
- * @param value Value to check
520
- * @returns `true` if the value is a `Key` _(`number` or `string`)_, otherwise `false`
521
- */
522
- function isKey(value) {
523
- return typeof value === "number" || typeof value === "string";
524
- }
525
- /**
526
- * Is the value a plain object?
527
- * @param value Value to check
528
- * @returns `true` if the value is a plain object, otherwise `false`
529
- */
530
- function isPlainObject(value) {
531
- if (value === null || typeof value !== "object") return false;
532
- if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
533
- const prototype = Object.getPrototypeOf(value);
534
- return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
535
- }
536
- //#endregion
537
- //#region node_modules/@oscarpalmer/atoms/dist/internal/string.mjs
538
- /**
539
- * Get the string value from any value
540
- * @param value Original value
541
- * @returns String representation of the value
542
- */
543
- function getString(value) {
544
- if (typeof value === "string") return value;
545
- if (value == null) return "";
546
- if (typeof value === "function") return getString(value());
547
- if (typeof value !== "object") return String(value);
548
- const asString = String(value.valueOf?.() ?? value);
549
- return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
613
+ function setArray$1(state, value) {
614
+ state.value.splice(0, state.value.length, ...value ?? []);
550
615
  }
551
- //#endregion
552
- //#region node_modules/@oscarpalmer/atoms/dist/is.mjs
553
- /**
554
- * Is the value `undefined`, `null`, or a whitespace-only string?
555
- * @param value Value to check
556
- * @returns `true` if the value is nullable or a whitespace-only string, otherwise `false`
557
- */
558
- function isNullableOrWhitespace(value) {
559
- return value == null || EXPRESSION_WHITESPACE$1.test(getString(value));
616
+ function setAtIndex(state, index, value) {
617
+ const actual = index < 0 ? state.value.length + index : index;
618
+ if (actual > -1) state.value[actual] = value;
560
619
  }
561
- const EXPRESSION_WHITESPACE$1 = /^\s*$/;
562
620
  //#endregion
563
621
  //#region node_modules/@oscarpalmer/mora/dist/value/store.mjs
564
622
  var Store = class extends Reactive {
@@ -588,8 +646,7 @@ var Store = class extends Reactive {
588
646
  return isKey(key) ? this.state.value[key] : { ...this.state.value };
589
647
  }
590
648
  set(first, second) {
591
- if (isKey(first)) this.state.value[first] = second;
592
- else if (first == null || isPlainObject(first)) setProxyValue(this.state.value, first ?? {});
649
+ setProxyValue(false, this.state, isStoreObject, isKey, setObject, setProperty, first, second);
593
650
  }
594
651
  subscribe(first, second) {
595
652
  if (isKey(first) && typeof second === "function") return getReactiveValueInProxy(this, this.#keyed, first, false).subscribe(second);
@@ -600,19 +657,114 @@ var Store = class extends Reactive {
600
657
  * @param callback Callback to update the value
601
658
  */
602
659
  update(callback) {
603
- const updated = callback({ ...this.state.value });
604
- if (updated == null || isPlainObject(updated)) setProxyValue(this.state.value, updated ?? {});
660
+ const updated = callback(this.state.value);
661
+ if (updated == null || isPlainObject$1(updated)) setObject(this.state, updated);
605
662
  }
606
663
  };
664
+ function isStoreObject(value) {
665
+ return value == null || isPlainObject$1(value);
666
+ }
667
+ function setObject(state, value) {
668
+ startBatch();
669
+ const actual = value ?? {};
670
+ const proxy = state.value;
671
+ const proxyKeys = Object.keys(proxy);
672
+ const actualKeys = Object.keys(actual);
673
+ let { length } = proxyKeys;
674
+ for (let index = 0; index < length; index += 1) {
675
+ const key = proxyKeys[index];
676
+ proxy[key] = actualKeys.includes(key) ? actual[key] : void 0;
677
+ }
678
+ length = actualKeys.length;
679
+ for (let index = 0; index < length; index += 1) {
680
+ const key = actualKeys[index];
681
+ if (!proxyKeys.includes(key)) proxy[key] = actual[key];
682
+ }
683
+ stopBatch();
684
+ }
685
+ function setProperty(state, key, value) {
686
+ state.value[key] = value;
687
+ }
688
+ function store(value, options) {
689
+ const instance = new Store({}, options);
690
+ instance.set(value);
691
+ return instance;
692
+ }
693
+ //#endregion
694
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
607
695
  /**
608
- * Create a reactive store
609
- * @param value Initial object value
610
- * @param options Reactivity options
611
- * @returns Reactive store
696
+ * Is the value a number?
697
+ * @param value Value to check
698
+ * @returns `true` if the value is a `number`, otherwise `false`
612
699
  */
613
- function store(value, options) {
614
- return new Store(isPlainObject(value) ? value : {}, options);
700
+ function isNumber(value) {
701
+ return typeof value === "number" && !Number.isNaN(value);
615
702
  }
703
+ /**
704
+ * Is the value a plain object?
705
+ * @param value Value to check
706
+ * @returns `true` if the value is a plain object, otherwise `false`
707
+ */
708
+ function isPlainObject(value) {
709
+ if (value === null || typeof value !== "object") return false;
710
+ if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
711
+ const prototype = Object.getPrototypeOf(value);
712
+ return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
713
+ }
714
+ //#endregion
715
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/string.mjs
716
+ /**
717
+ * Get the string value from any value
718
+ * @param value Original value
719
+ * @returns String representation of the value
720
+ */
721
+ function getString(value) {
722
+ if (typeof value === "string") return value;
723
+ if (value == null) return "";
724
+ if (typeof value === "function") return getString(value());
725
+ if (typeof value !== "object") return String(value);
726
+ const asString = String(value.valueOf?.() ?? value);
727
+ return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
728
+ }
729
+ /**
730
+ * Join an array of values into a string _(while ignoring empty values)_
731
+ *
732
+ * _(`null`, `undefined`, and any values that become whitespace-only strings are considered empty)_
733
+ * @param array Array of values
734
+ * @param delimiter Delimiter to use between values
735
+ * @returns Joined string
736
+ */
737
+ function join(array, delimiter) {
738
+ if (!Array.isArray(array)) return "";
739
+ const { length } = array;
740
+ if (length === 0) return "";
741
+ const values = [];
742
+ for (let index = 0; index < length; index += 1) {
743
+ const item = getString(array[index]);
744
+ if (item.trim().length > 0) values.push(item);
745
+ }
746
+ return values.join(typeof delimiter === "string" ? delimiter : "");
747
+ }
748
+ /**
749
+ * Split a string into words _(and other readable parts)_
750
+ * @param value Original string
751
+ * @returns Array of words found in the string
752
+ */
753
+ function words(value) {
754
+ return typeof value === "string" ? value.match(EXPRESSION_WORDS) ?? [] : [];
755
+ }
756
+ const EXPRESSION_WORDS = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
757
+ //#endregion
758
+ //#region node_modules/@oscarpalmer/atoms/dist/is.mjs
759
+ /**
760
+ * Is the value `undefined`, `null`, or stringified as a whitespace-only string?
761
+ * @param value Value to check
762
+ * @returns `true` if the value is nullable or matches a whitespace-only string, otherwise `false`
763
+ */
764
+ function isNullableOrWhitespace(value) {
765
+ return value == null || EXPRESSION_WHITESPACE$1.test(getString(value));
766
+ }
767
+ const EXPRESSION_WHITESPACE$1 = /^\s*$/;
616
768
  //#endregion
617
769
  //#region node_modules/@oscarpalmer/toretto/dist/internal/is.mjs
618
770
  /**
@@ -649,16 +801,280 @@ const CHILD_NODE_TYPES = new Set([
649
801
  Node.DOCUMENT_TYPE_NODE
650
802
  ]);
651
803
  //#endregion
804
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/number.mjs
805
+ /**
806
+ * Clamp a number between a minimum and maximum value
807
+ * @param value Value to clamp
808
+ * @param minimum Minimum value
809
+ * @param maximum Maximum value
810
+ * @param loop If `true`, the value will loop around when smaller than the minimum or larger than the maximum _(defaults to `false`)_
811
+ * @returns Clamped value
812
+ */
813
+ function clamp(value, minimum, maximum, loop) {
814
+ if (![
815
+ value,
816
+ minimum,
817
+ maximum
818
+ ].every(isNumber)) return NaN;
819
+ if (value < minimum) return loop === true ? maximum : minimum;
820
+ return value > maximum ? loop === true ? minimum : maximum : value;
821
+ }
822
+ //#endregion
823
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/sized.mjs
824
+ function getSizedMaximum(first, second) {
825
+ let actual;
826
+ if (typeof first === "number") actual = first;
827
+ else actual = typeof second === "number" ? second : MAXIMUM_DEFAULT;
828
+ return clamp(actual, 1, MAXIMUM_ABSOLUTE);
829
+ }
830
+ const MAXIMUM_ABSOLUTE = 16777216;
831
+ const MAXIMUM_DEFAULT = 1048576;
832
+ //#endregion
833
+ //#region node_modules/@oscarpalmer/atoms/dist/sized/map.mjs
834
+ /**
835
+ * A Map with a maximum size
836
+ *
837
+ * Behavior is similar to a _LRU_-cache, where the least recently used entries are removed
838
+ */
839
+ var SizedMap = class extends Map {
840
+ /**
841
+ * The maximum size of the Map
842
+ */
843
+ #maximumSize;
844
+ /**
845
+ * Is the Map full?
846
+ */
847
+ get full() {
848
+ return super.size >= this.#maximumSize;
849
+ }
850
+ get maximum() {
851
+ return this.#maximumSize;
852
+ }
853
+ constructor(first, second) {
854
+ const maximum = getSizedMaximum(first, second);
855
+ super();
856
+ this.#maximumSize = maximum;
857
+ if (Array.isArray(first)) {
858
+ const { length } = first;
859
+ if (length <= maximum) for (let index = 0; index < length; index += 1) this.set(...first[index]);
860
+ else for (let index = 0; index < maximum; index += 1) this.set(...first[length - maximum + index]);
861
+ }
862
+ }
863
+ /**
864
+ * @inheritdoc
865
+ */
866
+ get(key) {
867
+ if (super.has(key)) {
868
+ const value = super.get(key);
869
+ this.#setValue(key, value, true);
870
+ return value;
871
+ }
872
+ }
873
+ /**
874
+ * @inheritdoc
875
+ */
876
+ set(key, value) {
877
+ return this.#setValue(key, value, super.has(key));
878
+ }
879
+ #setValue(key, value, has) {
880
+ if (has) super.delete(key);
881
+ else if (super.size >= this.#maximumSize) super.delete(super.keys().next().value);
882
+ super.set(key, value);
883
+ return this;
884
+ }
885
+ };
886
+ //#endregion
887
+ //#region node_modules/@oscarpalmer/atoms/dist/function/memoize.mjs
888
+ /**
889
+ * A memoized function, caching and retrieving results based on the its parameters _(or a custom cache key)_
890
+ */
891
+ var Memoized = class {
892
+ #state;
893
+ /**
894
+ * Maximum cache size
895
+ */
896
+ get maximum() {
897
+ return this.#state.cache?.maximum ?? NaN;
898
+ }
899
+ /**
900
+ * Current cache size
901
+ */
902
+ get size() {
903
+ return this.#state.cache?.size ?? NaN;
904
+ }
905
+ constructor(callback, options) {
906
+ const cache = new SizedMap(options.cacheSize);
907
+ const getter = (...parameters) => {
908
+ const key = options.cacheKey?.(...parameters) ?? (parameters.length === 1 ? parameters[0] : join(parameters.map(getString), SEPARATOR));
909
+ if (cache.has(key)) return cache.get(key);
910
+ const value = callback(...parameters);
911
+ cache.set(key, value);
912
+ return value;
913
+ };
914
+ this.#state = {
915
+ cache,
916
+ getter
917
+ };
918
+ }
919
+ /**
920
+ * Clear the cache
921
+ */
922
+ clear() {
923
+ this.#state.cache?.clear();
924
+ }
925
+ /**
926
+ * Delete a result from the cache
927
+ * @param key Key to delete
928
+ * @returns `true` if the key existed and was removed, otherwise `false`
929
+ */
930
+ delete(key) {
931
+ return this.#state.cache?.delete(key) ?? false;
932
+ }
933
+ /**
934
+ * Destroy the instance _(clearing its cache and removing its callback)_
935
+ */
936
+ destroy() {
937
+ this.#state.cache?.clear();
938
+ this.#state.cache = void 0;
939
+ this.#state.getter = void 0;
940
+ }
941
+ /**
942
+ * Get a result from the cache
943
+ * @param key Key to get
944
+ * @returns Cached result or `undefined` if it does not exist
945
+ */
946
+ get(key) {
947
+ return this.#state.cache?.get(key);
948
+ }
949
+ /**
950
+ * Does the result exist?
951
+ * @param key Key to check
952
+ * @returns `true` if the result exists, otherwise `false`
953
+ */
954
+ has(key) {
955
+ return this.#state.cache?.has(key) ?? false;
956
+ }
957
+ /**
958
+ * Run the callback with the provided parameters
959
+ * @param parameters Parameters to pass to the callback
960
+ * @returns Cached or computed _(then cached)_ result
961
+ */
962
+ run(...parameters) {
963
+ if (this.#state.cache == null || this.#state.getter == null) throw new Error("The Memoized instance has been destroyed");
964
+ return this.#state.getter(...parameters);
965
+ }
966
+ };
967
+ function getMemoizationOptions(input) {
968
+ const { cacheKey, cacheSize } = isPlainObject(input) ? input : {};
969
+ return {
970
+ cacheKey: typeof cacheKey === "function" ? cacheKey : void 0,
971
+ cacheSize: typeof cacheSize === "number" && cacheSize > 0 ? cacheSize : DEFAULT_CACHE_SIZE
972
+ };
973
+ }
974
+ /**
975
+ * Memoize a function, caching and retrieving results based on the first parameter
976
+ * @param callback Callback to memoize
977
+ * @param options Memoization options
978
+ * @returns Memoized instance
979
+ */
980
+ function memoize(callback, options) {
981
+ return new Memoized(callback, getMemoizationOptions(options));
982
+ }
983
+ const DEFAULT_CACHE_SIZE = 1024;
984
+ const SEPARATOR = "_";
985
+ //#endregion
986
+ //#region node_modules/@oscarpalmer/atoms/dist/string/case.mjs
987
+ /**
988
+ * Convert a string to camel case _(thisIsCamelCase)_
989
+ * @param value String to convert
990
+ * @returns Camel-cased string
991
+ */
992
+ function camelCase(value) {
993
+ return toCase(CASE_CAMEL, value, true, false);
994
+ }
995
+ /**
996
+ * Capitalize the first letter of a string _(and lowercase the rest)_
997
+ * @param value String to capitalize
998
+ * @returns Capitalized string
999
+ */
1000
+ function capitalize(value) {
1001
+ if (typeof value !== "string" || value.length === 0) return "";
1002
+ memoizedCapitalize ??= memoize((v) => v.length === 1 ? v.toLocaleUpperCase() : `${v.charAt(0).toLocaleUpperCase()}${v.slice(1).toLocaleLowerCase()}`);
1003
+ return memoizedCapitalize.run(value);
1004
+ }
1005
+ /**
1006
+ * Convert a string to kebab case _(this-is-kebab-case)_
1007
+ * @param value String to convert
1008
+ * @returns Kebab-cased string
1009
+ */
1010
+ function kebabCase(value) {
1011
+ return toCase(CASE_KEBAB, value, false, false);
1012
+ }
1013
+ function toCase(type, value, capitalizeAny, capitalizeFirst) {
1014
+ caseMemoizers[type] ??= memoize(toCaseCallback.bind({
1015
+ type,
1016
+ capitalizeAny,
1017
+ capitalizeFirst
1018
+ }));
1019
+ return caseMemoizers[type].run(value);
1020
+ }
1021
+ function toCaseCallback(value) {
1022
+ if (typeof value !== "string") return "";
1023
+ if (value.length < 1) return value;
1024
+ const { capitalizeAny, capitalizeFirst, type } = this;
1025
+ const parts = words(value);
1026
+ const partsLength = parts.length;
1027
+ const cased = [];
1028
+ for (let partIndex = 0; partIndex < partsLength; partIndex += 1) {
1029
+ const items = parts[partIndex].replace(EXPRESSION_ACRONYM, (full, one, two, three) => three === S ? full : `${one}-${two}${three}`).replace(EXPRESSION_CAMEL_CASE, REPLACEMENT_CAMEL_CASE).split("-");
1030
+ const itemsLength = items.length;
1031
+ const partResult = [];
1032
+ let itemCount = 0;
1033
+ for (let itemIndex = 0; itemIndex < itemsLength; itemIndex += 1) {
1034
+ const item = items[itemIndex];
1035
+ if (item.length === 0) continue;
1036
+ if (!capitalizeAny || itemCount === 0 && partIndex === 0 && !capitalizeFirst) partResult.push(item.toLocaleLowerCase());
1037
+ else partResult.push(capitalize(item));
1038
+ itemCount += 1;
1039
+ }
1040
+ cased.push(join(partResult, delimiters[type]));
1041
+ }
1042
+ return join(cased, delimiters[type]);
1043
+ }
1044
+ const CASE_CAMEL = "camel";
1045
+ const CASE_KEBAB = "kebab";
1046
+ const CASE_PASCAL = "pascal";
1047
+ const CASE_SNAKE = "snake";
1048
+ const DELIMTER_EMPTY = "";
1049
+ const DELIMITER_HYPHEN = "-";
1050
+ const DELIMITER_UNDERSCORE = "_";
1051
+ const EXPRESSION_CAMEL_CASE = /(\p{Ll})(\p{Lu})/gu;
1052
+ const EXPRESSION_ACRONYM = /(\p{Lu}*)(\p{Lu})(\p{Ll}+)/gu;
1053
+ const REPLACEMENT_CAMEL_CASE = "$1-$2";
1054
+ const S = "s";
1055
+ const caseMemoizers = {};
1056
+ const delimiters = {
1057
+ [CASE_CAMEL]: DELIMTER_EMPTY,
1058
+ [CASE_KEBAB]: DELIMITER_HYPHEN,
1059
+ [CASE_PASCAL]: DELIMTER_EMPTY,
1060
+ [CASE_SNAKE]: DELIMITER_UNDERSCORE
1061
+ };
1062
+ let memoizedCapitalize;
1063
+ //#endregion
652
1064
  //#region node_modules/@oscarpalmer/toretto/dist/internal/element-value.mjs
653
- function setElementValue(element, first, second, third, callback) {
1065
+ function normalizeKey(key, style) {
1066
+ return style && key.startsWith(CSS_VARIABLE_PREFIX) ? key : kebabCase(key);
1067
+ }
1068
+ function setElementValue(element, first, second, third, callback, style) {
654
1069
  if (!isHTMLOrSVGElement(element)) return;
655
- if (typeof first === "string") setElementValues(element, first, second, third, callback);
656
- else if (isAttribute(first)) setElementValues(element, first.name, first.value, third, callback);
1070
+ if (typeof first === "string") setElementValues(element, first, second, third, callback, style);
1071
+ else if (isAttribute(first)) setElementValues(element, first.name, first.value, third, callback, style);
657
1072
  }
658
- function setElementValues(element, first, second, third, callback) {
1073
+ function setElementValues(element, first, second, third, callback, style) {
659
1074
  if (!isHTMLOrSVGElement(element)) return;
1075
+ const dispatch = third !== false;
660
1076
  if (typeof first === "string") {
661
- callback(element, first, second, third);
1077
+ callback(element, normalizeKey(first, style), second, dispatch);
662
1078
  return;
663
1079
  }
664
1080
  const isArray = Array.isArray(first);
@@ -670,13 +1086,36 @@ function setElementValues(element, first, second, third, callback) {
670
1086
  const { length } = entries;
671
1087
  for (let index = 0; index < length; index += 1) {
672
1088
  const entry = entries[index];
673
- if (typeof entry === "object" && typeof entry?.name === "string") callback(element, entry.name, entry.value, third);
1089
+ if (typeof entry === "object" && typeof entry?.name === "string") callback(element, normalizeKey(entry.name, style), entry.value, dispatch);
674
1090
  }
675
1091
  }
676
1092
  function updateElementValue(element, key, value, set, remove, isBoolean, json) {
677
1093
  if (isBoolean ? value == null : isNullableOrWhitespace(value)) remove.call(element, key);
678
1094
  else set.call(element, key, json ? JSON.stringify(value) : String(value));
679
1095
  }
1096
+ const CSS_VARIABLE_PREFIX = "--";
1097
+ //#endregion
1098
+ //#region node_modules/@oscarpalmer/toretto/dist/internal/property.mjs
1099
+ function updateProperty(element, name, value, dispatch) {
1100
+ let property = name;
1101
+ if (!(property in element)) property = camelCase(name);
1102
+ if (!(property in element) || Object.is(element[property], value)) return;
1103
+ element[property] = value;
1104
+ const event = dispatch && elementEvents[element.tagName]?.[property];
1105
+ if (typeof event === "string") element.dispatchEvent(new Event(event, {
1106
+ bubbles: true,
1107
+ cancelable: true
1108
+ }));
1109
+ }
1110
+ const elementEvents = {
1111
+ DETAILS: { open: "toggle" },
1112
+ INPUT: {
1113
+ checked: "change",
1114
+ value: "input"
1115
+ },
1116
+ SELECT: { value: "change" },
1117
+ TEXTAREA: { value: "input" }
1118
+ };
680
1119
  //#endregion
681
1120
  //#region node_modules/@oscarpalmer/toretto/dist/internal/attribute.mjs
682
1121
  function badAttributeHandler(name, value) {
@@ -707,6 +1146,7 @@ function handleAttribute(callback, decode, first, second) {
707
1146
  name = first;
708
1147
  value = second;
709
1148
  }
1149
+ if (name != null) name = kebabCase(name);
710
1150
  if (decode && value != null) value = decodeAttribute(value);
711
1151
  return callback(name, value?.replace(EXPRESSION_WHITESPACE, ""));
712
1152
  }
@@ -716,12 +1156,6 @@ function isAttribute(value) {
716
1156
  function _isBadAttribute(first, second, decode) {
717
1157
  return handleAttribute(badAttributeHandler, decode, first, second);
718
1158
  }
719
- function _isBooleanAttribute(first, decode) {
720
- return handleAttribute((name) => booleanAttributesSet.has(name?.toLowerCase()), decode, first, "");
721
- }
722
- function _isEmptyNonBooleanAttribute(first, second, decode) {
723
- return handleAttribute((name, value) => name != null && value != null && !booleanAttributesSet.has(name) && value.trim().length === 0, decode, first, second);
724
- }
725
1159
  function _isInvalidBooleanAttribute(first, second, decode) {
726
1160
  return handleAttribute(booleanAttributeHandler, decode, first, second);
727
1161
  }
@@ -729,18 +1163,12 @@ function isValidSourceAttribute(name, value) {
729
1163
  return EXPRESSION_SOURCE_NAME.test(name) && EXPRESSION_SOURCE_VALUE.test(value);
730
1164
  }
731
1165
  function updateAttribute(element, name, value, dispatch) {
732
- const normalizedName = name.toLowerCase();
733
- const isBoolean = booleanAttributesSet.has(normalizedName);
734
- const next = isBoolean ? value === true || typeof value === "string" && (value === "" || value.toLowerCase() === normalizedName) : value == null ? "" : value;
735
- if (name in element) updateProperty$1(element, normalizedName, next, dispatch);
1166
+ const lowerCaseName = name.toLowerCase();
1167
+ const isBoolean = booleanAttributesSet.has(lowerCaseName);
1168
+ const next = isBoolean ? value === true || typeof value === "string" && (value === "" || value.toLowerCase() === lowerCaseName) : value == null ? "" : value;
1169
+ if (isBoolean || dispatchedAttributes.has(name)) updateProperty(element, name, next, dispatch);
736
1170
  updateElementValue(element, name, isBoolean ? next ? "" : null : value, element.setAttribute, element.removeAttribute, isBoolean, false);
737
1171
  }
738
- function updateProperty$1(element, name, value, dispatch) {
739
- if (Object.is(element[name], value)) return;
740
- element[name] = value;
741
- const event = dispatch !== false && elementEvents[element.tagName]?.[name];
742
- if (typeof event === "string") element.dispatchEvent(new Event(event, { bubbles: true }));
743
- }
744
1172
  const EXPRESSION_CLOBBERED_NAME = /^(id|name)$/i;
745
1173
  const EXPRESSION_DATA_OR_SCRIPT = /^(?:data|\w+script):/i;
746
1174
  const EXPRESSION_EVENT_NAME$1 = /^on/i;
@@ -779,19 +1207,15 @@ const booleanAttributes = Object.freeze([
779
1207
  "selected"
780
1208
  ]);
781
1209
  const booleanAttributesSet = new Set(booleanAttributes);
782
- const elementEvents = {
783
- DETAILS: { open: "toggle" },
784
- INPUT: {
785
- checked: "change",
786
- value: "input"
787
- },
788
- SELECT: { value: "change" },
789
- TEXTAREA: { value: "input" }
790
- };
1210
+ const dispatchedAttributes = new Set([
1211
+ "checked",
1212
+ "open",
1213
+ "value"
1214
+ ]);
791
1215
  const formElement = document.createElement("form");
792
1216
  let textArea;
793
1217
  //#endregion
794
- //#region node_modules/@oscarpalmer/toretto/dist/attribute/set.mjs
1218
+ //#region node_modules/@oscarpalmer/toretto/dist/attribute/set.attribute.mjs
795
1219
  function setAttribute$1(element, first, second, third) {
796
1220
  setElementValue(element, first, second, third, updateAttribute);
797
1221
  }
@@ -799,8 +1223,9 @@ function setAttribute$1(element, first, second, third) {
799
1223
  //#region node_modules/@oscarpalmer/toretto/dist/html/sanitize.mjs
800
1224
  function handleElement(element, depth) {
801
1225
  if (depth === 0) {
802
- const removable = element.querySelectorAll(REMOVE_SELECTOR);
803
- for (const item of removable) item.remove();
1226
+ const removable = [...element.querySelectorAll(REMOVE_SELECTOR)];
1227
+ const { length } = removable;
1228
+ for (let index = 0; index < length; index += 1) removable[index].remove();
804
1229
  }
805
1230
  sanitizeAttributes(element, [...element.attributes]);
806
1231
  }
@@ -819,7 +1244,7 @@ function sanitizeAttributes(element, attributes) {
819
1244
  const { length } = attributes;
820
1245
  for (let index = 0; index < length; index += 1) {
821
1246
  const { name, value } = attributes[index];
822
- if (_isBadAttribute(name, value, false) || _isEmptyNonBooleanAttribute(name, value, false)) element.removeAttribute(name);
1247
+ if (_isBadAttribute(name, value, false)) element.removeAttribute(name);
823
1248
  else if (_isInvalidBooleanAttribute(name, value, false)) setAttribute$1(element, name, true);
824
1249
  }
825
1250
  }
@@ -865,16 +1290,22 @@ function createHtml(value) {
865
1290
  function createTemplate(value, options) {
866
1291
  const template = document.createElement(TEMPLATE_TAG);
867
1292
  template.innerHTML = createHtml(value);
868
- if (typeof value === "string" && options.cache) templates[value] = template;
1293
+ if (typeof value === "string" && options.cache) templates.set(value, template);
869
1294
  return template;
870
1295
  }
1296
+ function getComment(index) {
1297
+ return COMMENT_TEMPLATE.replace(COMMENT_INDEX, String(index));
1298
+ }
871
1299
  function getHtml(value) {
872
1300
  return `${TEMPORARY_ELEMENT}${typeof value === "string" ? value : value.innerHTML}${TEMPORARY_ELEMENT}`;
873
1301
  }
874
- function getNodes(value, options) {
1302
+ function getNodes(value, options, nodes) {
875
1303
  if (typeof value !== "string" && !(value instanceof HTMLTemplateElement)) return [];
876
1304
  const template = getTemplate(value, options);
877
- return template == null ? [] : [...template.content.cloneNode(true).childNodes];
1305
+ if (template == null) return [];
1306
+ const cloned = [...template.content.cloneNode(true).childNodes];
1307
+ if (nodes != null) replaceComments(cloned, nodes);
1308
+ return cloned;
878
1309
  }
879
1310
  function getOptions$1(input) {
880
1311
  const options = isPlainObject(input) ? input : {};
@@ -885,42 +1316,102 @@ function getParser() {
885
1316
  parser ??= new DOMParser();
886
1317
  return parser;
887
1318
  }
1319
+ function getTagged(strings, values) {
1320
+ const tagged = {
1321
+ nodes: [],
1322
+ template: ""
1323
+ };
1324
+ const stringsLength = strings.length;
1325
+ let nodeIndex = 0;
1326
+ for (let stringIndex = 0; stringIndex < stringsLength; stringIndex += 1) {
1327
+ const value = values[stringIndex];
1328
+ tagged.template += strings[stringIndex];
1329
+ if (value instanceof Node) {
1330
+ tagged.nodes.push(value);
1331
+ tagged.template += getComment(nodeIndex);
1332
+ nodeIndex += 1;
1333
+ } else if (hasNodes(value)) {
1334
+ const items = [...value];
1335
+ const itemsLength = items.length;
1336
+ for (let itemIndex = 0; itemIndex < itemsLength; itemIndex += 1) {
1337
+ const item = items[itemIndex];
1338
+ if (item instanceof Node) {
1339
+ tagged.nodes.push(item);
1340
+ tagged.template += getComment(nodeIndex);
1341
+ nodeIndex += 1;
1342
+ } else tagged.template += getString(item);
1343
+ }
1344
+ } else if (Array.isArray(value)) {
1345
+ const valueLength = value.length;
1346
+ for (let valueIndex = 0; valueIndex < valueLength; valueIndex += 1) tagged.template += getString(value[valueIndex]);
1347
+ } else tagged.template += getString(value);
1348
+ }
1349
+ return tagged;
1350
+ }
888
1351
  function getTemplate(value, options) {
889
1352
  if (value instanceof HTMLTemplateElement) return createTemplate(value, options);
890
1353
  if (value.trim().length === 0) return;
891
- let template = templates[value];
1354
+ let template = templates.get(value);
892
1355
  if (template != null) return template;
893
1356
  const element = EXPRESSION_ID.test(value) ? document.querySelector(`#${value}`) : null;
894
1357
  return createTemplate(element instanceof HTMLTemplateElement ? element : value, options);
895
1358
  }
896
- const html$1 = ((value, options) => {
897
- return getNodes(value, getOptions$1(options));
898
- });
1359
+ function hasNodes(value) {
1360
+ if (value instanceof HTMLCollection || value instanceof NodeList) return true;
1361
+ return Array.isArray(value) && value.some((item) => item instanceof Node);
1362
+ }
1363
+ function html$1(first, ...second) {
1364
+ if (isTagged(first)) {
1365
+ const tagged = getTagged(first, second);
1366
+ return getNodes(tagged.template, getOptions$1(), tagged.nodes);
1367
+ }
1368
+ return getNodes(first, getOptions$1(second[0]));
1369
+ }
1370
+ /**
1371
+ * Clear cache of template elements
1372
+ */
899
1373
  html$1.clear = () => {
900
- templates = {};
1374
+ templates.clear();
901
1375
  };
1376
+ /**
1377
+ * Remove cached template element for an HTML string or id
1378
+ * @param template HTML string or id for a template element
1379
+ */
902
1380
  html$1.remove = (template) => {
903
- if (typeof template !== "string" || templates[template] == null) return;
904
- const keys = Object.keys(templates);
905
- const { length } = keys;
906
- const updated = {};
907
- for (let index = 0; index < length; index += 1) {
908
- const key = keys[index];
909
- if (key !== template) updated[key] = templates[key];
910
- }
911
- templates = updated;
1381
+ templates.delete(template);
912
1382
  };
1383
+ function isTagged(value) {
1384
+ return Array.isArray(value) && Array.isArray(value.raw);
1385
+ }
1386
+ function replaceComments(origin, replacements) {
1387
+ const nodes = [...origin];
1388
+ const { length } = nodes;
1389
+ for (let nodeIndex = 0; nodeIndex < length; nodeIndex += 1) {
1390
+ const node = nodes[nodeIndex];
1391
+ if (node instanceof Comment) {
1392
+ const [, index] = EXPRESSION_COMMENT.exec(node.textContent) ?? [];
1393
+ if (index != null) node.replaceWith(replacements[Number(index)]);
1394
+ continue;
1395
+ }
1396
+ if (node.hasChildNodes()) replaceComments(node.childNodes, replacements);
1397
+ }
1398
+ }
1399
+ const COMMENT_INDEX = "<index>";
1400
+ const COMMENT_TEMPLATE = `<!--toretto.node:${COMMENT_INDEX}-->`;
1401
+ const EXPRESSION_COMMENT = /^toretto\.node:(\d+)$/;
913
1402
  const EXPRESSION_ID = /^[a-z][\w-]*$/i;
914
1403
  const PARSE_TYPE_HTML = "text/html";
915
1404
  const TEMPLATE_TAG = "template";
916
1405
  const TEMPORARY_ELEMENT = "<toretto-temporary></toretto-temporary>";
1406
+ const templates = new SizedMap(128);
917
1407
  let parser;
918
- let templates = {};
1408
+ window.templates = templates;
919
1409
  //#endregion
920
1410
  //#region src/constants.ts
921
1411
  const ARRAY_COMPARISON_ADDED = "added";
922
1412
  const ARRAY_COMPARISON_DISSIMILAR = "dissimilar";
923
1413
  const ARRAY_COMPARISON_REMOVED = "removed";
1414
+ const CHANGE_INPUTS = new Set(["checkbox", "radio"]);
924
1415
  const ERROR_FRAGMENT = "Fragment function must return a Fragment instance";
925
1416
  const ERROR_IDENTIFIER_DUPLICATE = "Duplicate identifier found: '<id>'";
926
1417
  const ERROR_IDENTIFIER_TYPE = "Identifier cannot be null or undefined";
@@ -935,39 +1426,23 @@ const EVENT_DEFAULTS = {
935
1426
  SELECT: EVENT_CHANGE,
936
1427
  TEXTAREA: EVENT_INPUT
937
1428
  };
938
- const EXPRESSION_ABYDON_ATTRIBUTE_FULL = /(@?[\w-]+)="<!--abydon.(\d+)-->"/g;
939
- const EXPRESSION_ABYDON_ATTRIBUTE_PREFIX = /^_/;
940
- const EXPRESSION_ABYDON_CONTENT = /^@?abydon\.(\d+)@?$/;
1429
+ const EXPRESSION_ABYDON_ATTRIBUTE_FULL = /(@?[\w-.]+(?::[a-z:]+)?)="<!--abydon.(\d+)-->"/g;
1430
+ const EXPRESSION_ABYDON_ATTRIBUTE_PREFIX = /^abydon-/;
1431
+ const EXPRESSION_ABYDON_CONTENT = /^abydon\.(\d+)$/;
941
1432
  const EXPRESSION_ATTRIBUTE_CLASS = /^class\./;
942
1433
  const EXPRESSION_ATTRIBUTE_STYLE_FULL = /^style\.([\w-]+)(?:\.([\w-]+))?$/;
943
1434
  const EXPRESSION_ATTRIBUTE_STYLE_PREFIX = /^style\./;
944
- const EXPRESSION_EVENT_CHANGE_TYPES = /^(checkbox|radio)$/;
945
- const EXPRESSION_EVENT_NAME = /^@([\w-]+)(?::([a-z:]+))?$/i;
1435
+ const EXPRESSION_ATTRIBUTE_STYLE_PROPERTY = /^style\.--/;
1436
+ const EXPRESSION_EVENT_ATTRIBUTE = /^@([\w-]+)(?::([a-z:]+))?="$/i;
1437
+ const EXPRESSION_EVENT_NAME = /^@?([\w-]+)(?::([a-z:]+))?$/i;
946
1438
  const EXPRESSION_EVENT_OPTIONS_ACTIVE = /^a(ctive)$/i;
947
1439
  const EXPRESSION_EVENT_OPTIONS_CAPTURE = /^c(apture)$/i;
948
1440
  const EXPRESSION_EVENT_OPTIONS_ONCE = /^o(nce)$/i;
949
1441
  const EXPRESSION_EVENT_PREFIX = /^@/;
950
- const EXPRESSION_PERIOD = /\./;
951
- const EXPRESSION_TEXTAREA_VALUE = /<!--abydon\.(\d+)-->/;
1442
+ const EXPRESSION_TEXTAREA_VALUE = /(?:<|&lt;)!--abydon\.(\d+)--(?:>|&gt;)/;
952
1443
  const NAME_FRAGMENT = "$fragment";
953
1444
  const NAME_FRAGMENTS = "$fragments";
954
- const PROPERTY_CHECKED = "checked";
955
- const PROPERTY_VALUE = "value";
956
- //#endregion
957
- //#region node_modules/@oscarpalmer/atoms/dist/string/index.mjs
958
- /**
959
- * Parse a JSON string into its proper value _(or `undefined` if it fails)_
960
- * @param value JSON string to parse
961
- * @param reviver Reviver function to transform the parsed values
962
- * @returns Parsed value or `undefined` if parsing fails
963
- */
964
- function parse$1(value, reviver) {
965
- try {
966
- return JSON.parse(value, reviver);
967
- } catch {
968
- return;
969
- }
970
- }
1445
+ const WHITESPACE = /\s+/g;
971
1446
  //#endregion
972
1447
  //#region src/helpers/index.ts
973
1448
  function compareArrays(first, second) {
@@ -977,9 +1452,19 @@ function compareArrays(first, second) {
977
1452
  if (!from.filter((key) => to.includes(key)).every((key, index) => to[index] === key)) return ARRAY_COMPARISON_DISSIMILAR;
978
1453
  return firstIsLarger ? ARRAY_COMPARISON_REMOVED : ARRAY_COMPARISON_ADDED;
979
1454
  }
1455
+ /**
1456
+ * Is the value a Fragment?
1457
+ * @param value Value to check
1458
+ * @returns `true` if the value is a Fragment, otherwise `false`
1459
+ */
980
1460
  function isFragment(value) {
981
1461
  return isNamed(value, NAME_FRAGMENT);
982
1462
  }
1463
+ /**
1464
+ * Is the value a Fragments?
1465
+ * @param value Value to check
1466
+ * @returns `true` if the value is a Fragments, otherwise `false`
1467
+ */
983
1468
  function isFragments(value) {
984
1469
  return isNamed(value, NAME_FRAGMENTS);
985
1470
  }
@@ -990,12 +1475,6 @@ function isNamed(value, name) {
990
1475
  //#region src/fragments.ts
991
1476
  var Fragments = class {
992
1477
  #state;
993
- /**
994
- * Fragment items
995
- */
996
- get items() {
997
- return this.#state.mapped;
998
- }
999
1478
  constructor(items, identify, fragment) {
1000
1479
  Object.defineProperty(this, NAME_FRAGMENTS, { value: true });
1001
1480
  this.#state = {
@@ -1006,13 +1485,13 @@ var Fragments = class {
1006
1485
  mapped: array([]),
1007
1486
  subscriber: void 0
1008
1487
  };
1009
- states.set(this, this.#state);
1488
+ fragmentsStates.set(this, this.#state);
1010
1489
  initializeFragments(this.#state);
1011
1490
  }
1012
1491
  };
1013
1492
  function handleFragments(item, remove) {
1014
- const state = isFragments(item) ? states.get(item) : item;
1015
- if (state != null) (remove ? removeFragments$1 : initializeFragments)(state);
1493
+ const state = isFragments(item) ? fragmentsStates.get(item) : item;
1494
+ (remove ? removeFragments$1 : initializeFragments)(state);
1016
1495
  }
1017
1496
  function handleItems(state, items) {
1018
1497
  const keys = /* @__PURE__ */ new Set();
@@ -1060,7 +1539,7 @@ function updateFragments(state, active) {
1060
1539
  state.instances = next;
1061
1540
  active?.clear();
1062
1541
  }
1063
- const states = /* @__PURE__ */ new WeakMap();
1542
+ const fragmentsStates = /* @__PURE__ */ new WeakMap();
1064
1543
  //#endregion
1065
1544
  //#region src/helpers/dom.ts
1066
1545
  function createNodes(value) {
@@ -1104,7 +1583,14 @@ function delegatedEventHandler(event) {
1104
1583
  const key = `${EVENT_PREFIX}${event.type}${this ? EVENT_SUFFIX_PASSIVE : EVENT_SUFFIX_ACTIVE}`;
1105
1584
  const items = event.composedPath();
1106
1585
  const { length } = items;
1586
+ let cancelled = false;
1107
1587
  let target = items[0];
1588
+ const originalStopPropagation = event.stopPropagation;
1589
+ event.stopPropagation = function() {
1590
+ cancelled = true;
1591
+ originalStopPropagation.call(event);
1592
+ };
1593
+ event.stopImmediatePropagation = event.stopPropagation.bind(event);
1108
1594
  Object.defineProperties(event, {
1109
1595
  currentTarget: {
1110
1596
  configurable: true,
@@ -1124,7 +1610,7 @@ function delegatedEventHandler(event) {
1124
1610
  target = item;
1125
1611
  for (const listener of listeners) {
1126
1612
  listener.call(item, event);
1127
- if (event.cancelBubble) return;
1613
+ if (cancelled) return;
1128
1614
  }
1129
1615
  }
1130
1616
  }
@@ -1208,89 +1694,106 @@ function getOptions(options) {
1208
1694
  function getType(element, type) {
1209
1695
  if (type !== "on") return type;
1210
1696
  if (element instanceof HTMLInputElement) {
1211
- if (EXPRESSION_EVENT_CHANGE_TYPES.test(element.type)) return EVENT_CHANGE;
1697
+ if (CHANGE_INPUTS.has(element.type)) return EVENT_CHANGE;
1212
1698
  return element.type === "submit" ? EVENT_SUBMIT : EVENT_INPUT;
1213
1699
  }
1214
1700
  return EVENT_DEFAULTS[element.tagName] ?? type;
1215
1701
  }
1216
1702
  function mapEvent(element, name, value) {
1217
- const [, type, options] = EXPRESSION_EVENT_NAME.exec(name) ?? [];
1218
- if (type != null && typeof value === "function") on(element, getType(element, type), value, getOptions(options ?? ""));
1703
+ const [, type, options] = EXPRESSION_EVENT_NAME.exec(name);
1704
+ const values = Array.isArray(value) ? value : [value];
1705
+ const { length } = values;
1706
+ for (let index = 0; index < length; index += 1) {
1707
+ const item = values[index];
1708
+ if (typeof item === "function") on(element, getType(element, type), item, getOptions(options ?? ""));
1709
+ }
1219
1710
  }
1220
1711
  //#endregion
1221
- //#region node_modules/@oscarpalmer/toretto/dist/attribute/index.mjs
1222
- function isBooleanAttribute(first) {
1223
- return _isBooleanAttribute(first, true);
1224
- }
1712
+ //#region node_modules/@oscarpalmer/toretto/dist/style.mjs
1713
+ /**
1714
+ * Set a style on an element
1715
+ * @param element Element to set the style on
1716
+ * @param property Style name
1717
+ * @param value Style value
1718
+ */
1719
+ function setStyle(element, property, value) {
1720
+ setElementValues(element, property, value, null, updateStyleProperty, true);
1721
+ }
1722
+ function updateStyleProperty(element, key, value) {
1723
+ updateElementValue(element, key, value, function(property, style) {
1724
+ if (property.startsWith(VARIABLE_PREFIX)) this.style.setProperty(property, String(style));
1725
+ else this.style[property] = String(style);
1726
+ }, function(property) {
1727
+ if (property.startsWith(VARIABLE_PREFIX)) this.style.removeProperty(property);
1728
+ else this.style[property] = "";
1729
+ if (this.getAttribute(ATTRIBUTE_STYLE) === "") this.removeAttribute(ATTRIBUTE_STYLE);
1730
+ }, false, false);
1731
+ }
1732
+ const ATTRIBUTE_STYLE = "style";
1733
+ const VARIABLE_PREFIX = "--";
1225
1734
  //#endregion
1226
- //#region src/node/attribute/value.ts
1227
- function getCallback(element, name) {
1228
- if (isBooleanAttribute(name) && name in element) return name === "checked" ? updateChecked : updateProperty;
1229
- return name === "value" ? updateValue : setAttribute$1;
1735
+ //#region src/attribute/value.ts
1736
+ function getStyleValue(value, unit, isProperty) {
1737
+ if (removeStyleValue(value, unit, isProperty)) return;
1738
+ return value === true || value === "true" ? unit : `${getString(value)}${unit ?? ""}`;
1739
+ }
1740
+ function removeStyleValue(value, unit, isProperty) {
1741
+ if (value == null || value === false || isProperty && isNullableOrWhitespace(value)) return true;
1742
+ return unit == null && (value === true || value === "true");
1230
1743
  }
1231
1744
  function setAttribute(data, element, name, value) {
1232
1745
  switch (true) {
1233
1746
  case EXPRESSION_ATTRIBUTE_CLASS.test(name):
1234
- setClasses(data, element, name, value);
1747
+ setClassValues(data, element, name, value);
1235
1748
  return;
1236
1749
  case EXPRESSION_ATTRIBUTE_STYLE_PREFIX.test(name):
1237
- setStyle(data, element, name, value);
1750
+ setStyleValues(data, element, name, value);
1238
1751
  return;
1239
1752
  default:
1240
1753
  setValue(data, element, name, value);
1241
1754
  break;
1242
1755
  }
1243
1756
  }
1244
- function setClasses(data, element, name, value) {
1757
+ function setClassValues(data, element, name, value) {
1245
1758
  function update(value) {
1246
- if (value === true) element.classList.add(...classes);
1759
+ if (value === true || value === "true") element.classList.add(...classes);
1247
1760
  else element.classList.remove(...classes);
1248
1761
  }
1249
1762
  const classes = name.slice(6).split(".");
1250
1763
  if (isReactive(value)) data.mora.subscribers.add(value.subscribe(update));
1251
1764
  else update(value);
1252
1765
  }
1253
- function setStyle(data, element, name, value) {
1254
- const [, property, unit] = EXPRESSION_ATTRIBUTE_STYLE_FULL.exec(name) ?? [];
1255
- if (property == null) return;
1766
+ function setStyleValues(data, element, name, value) {
1767
+ let [, property, unit] = EXPRESSION_ATTRIBUTE_STYLE_FULL.exec(name);
1768
+ const isProperty = EXPRESSION_ATTRIBUTE_STYLE_PROPERTY.test(name);
1769
+ property = camelCase(property);
1770
+ if (isProperty) property = `--${property}`;
1256
1771
  function update(value) {
1257
- if (value == null || value === false || value === true && unit == null) element.style.removeProperty(property);
1258
- else element.style.setProperty(property, value === true ? unit : String(value));
1772
+ setStyle(element, property, getStyleValue(value, unit, isProperty));
1259
1773
  }
1260
1774
  if (isReactive(value)) data.mora.subscribers.add(value.subscribe(update));
1261
1775
  else update(value);
1262
1776
  }
1263
1777
  function setValue(data, element, name, value) {
1264
- const callback = getCallback(element, name);
1265
- if (isReactive(value)) data.mora.subscribers.add(value.subscribe((next) => {
1266
- callback(element, name, next);
1778
+ const isReactiveValue = isReactive(value);
1779
+ unsetValue(element, name, isReactiveValue ? value.peek() : value);
1780
+ if (isReactiveValue) data.mora.subscribers.add(value.subscribe((next) => {
1781
+ setAttribute$1(element, name, next);
1267
1782
  }));
1268
- else callback(element, name, value);
1269
- }
1270
- function updateChecked(element, name, value) {
1271
- updateElement(EVENT_CHANGE, PROPERTY_CHECKED, element, name, value, value === true);
1272
- }
1273
- function updateElement(event, property, element, name, value, next) {
1274
- if (!(property in element) || element[property] === next) return;
1275
- setAttribute$1(element, name, value);
1276
- if (element[property] === next) return;
1277
- element[property] = next;
1278
- element.dispatchEvent(new Event(event, { bubbles: true }));
1783
+ else setAttribute$1(element, name, value);
1279
1784
  }
1280
- function updateProperty(element, name, value) {
1281
- setAttribute$1(element, name, value === true);
1282
- }
1283
- function updateValue(element, name, value) {
1284
- updateElement(element instanceof HTMLSelectElement ? EVENT_CHANGE : EVENT_INPUT, PROPERTY_VALUE, element, name, value, String(value));
1785
+ function unsetValue(element, name, value) {
1786
+ if (name === "checked") element.checked = !(value === true || value === "true");
1787
+ if (name === "value") element.value = element.value === "" ? "_" : "";
1285
1788
  }
1286
1789
  //#endregion
1287
- //#region src/node/attribute/index.ts
1790
+ //#region src/attribute/index.ts
1288
1791
  function getValue(data, original) {
1289
- const matches = EXPRESSION_ABYDON_CONTENT.exec(original ?? "");
1792
+ const matches = EXPRESSION_ABYDON_CONTENT.exec(original);
1290
1793
  return matches == null ? original : data.values[+matches[1]];
1291
1794
  }
1292
1795
  function mapAttributes(data, element) {
1293
- const attributes = [...element.attributes];
1796
+ const attributes = [...element.attributes].sort((first, second) => first.name.localeCompare(second.name));
1294
1797
  const { length } = attributes;
1295
1798
  for (let index = 0; index < length; index += 1) {
1296
1799
  const { name, value } = attributes[index];
@@ -1301,25 +1804,17 @@ function mapAttributes(data, element) {
1301
1804
  case EXPRESSION_EVENT_PREFIX.test(actualName):
1302
1805
  mapEvent(element, actualName, actualValue);
1303
1806
  break;
1304
- case EXPRESSION_PERIOD.test(actualName):
1305
- case typeof actualValue === "function":
1306
- case isReactive(actualValue):
1807
+ default:
1307
1808
  mapValue$1(data, element, actualName, actualValue);
1308
1809
  break;
1309
- default: break;
1310
1810
  }
1311
1811
  }
1312
1812
  }
1313
1813
  function mapValue$1(data, element, name, value) {
1314
1814
  if (typeof value === "function") setComputedAttribute(data, element, name, value);
1315
1815
  else setAttribute(data, element, name, value);
1316
- if (!isInputElement(element) || !isSignal(value)) return;
1317
- let property;
1318
- if (name === "checked" && element.type === "checkbox") property = PROPERTY_CHECKED;
1319
- else if (name === "value") property = PROPERTY_VALUE;
1320
- if (property != null) mapEvent(element, "@on", () => {
1321
- const next = element[property];
1322
- value.set(parse$1(String(next)) ?? next);
1816
+ if (isInputElement(element) && isSignal(value) && name in element) mapEvent(element, "on", () => {
1817
+ value.set(element[name]);
1323
1818
  });
1324
1819
  }
1325
1820
  function setComputedAttribute(data, element, name, callback) {
@@ -1376,14 +1871,15 @@ function setArray(item, comment, value) {
1376
1871
  let templates = value.filter((item) => isFragment(item) && item.identifier != null);
1377
1872
  const next = templates.map((fragment) => fragment.identifier);
1378
1873
  const previous = item.fragments?.map((fragment) => fragment.identifier) ?? [];
1379
- if (new Set(next).size !== templates.length) templates = [];
1874
+ const nextSet = new Set(next);
1875
+ if (nextSet.size !== templates.length) templates = [];
1380
1876
  const noTemplates = templates.length === 0;
1381
1877
  if (noTemplates || item.nodes == null || previous.some((identifier) => identifier == null)) return {
1382
1878
  fragments: noTemplates ? void 0 : templates,
1383
1879
  nodes: setNodes(item, comment, noTemplates ? value.flatMap((item) => createNodes(item)) : templates.flatMap((template) => template.get()))
1384
1880
  };
1385
1881
  return handleArray({
1386
- next: new Set(next),
1882
+ next: nextSet,
1387
1883
  previous: new Set(previous)
1388
1884
  }, {
1389
1885
  templates,
@@ -1391,10 +1887,8 @@ function setArray(item, comment, value) {
1391
1887
  }, item.nodes);
1392
1888
  }
1393
1889
  function setNodes(item, comment, next) {
1394
- if (item.nodes == null) {
1395
- if (comment.parentNode != null) replaceNodes([comment], next);
1396
- else if (item.text?.parentNode != null) replaceNodes([item.text], next);
1397
- } else replaceNodes(item.nodes, next);
1890
+ if (item.nodes == null) replaceNodes([comment], next);
1891
+ else replaceNodes(item.nodes, next);
1398
1892
  removeFragments(item.fragments);
1399
1893
  return next;
1400
1894
  }
@@ -1405,15 +1899,13 @@ function setReactiveValue(data, comment, reactive) {
1405
1899
  data.mora.subscribers.add(reactive.subscribe((value) => {
1406
1900
  if (Array.isArray(value)) setReactiveValueForArray(item, comment, value);
1407
1901
  else setReactiveValueForSingle(item, comment, value);
1408
- item.nodes = [...item.nodes ?? [comment]];
1902
+ item.nodes ??= [comment];
1409
1903
  }));
1410
1904
  }
1411
1905
  function setReactiveValueForArray(item, comment, value) {
1412
- const result = setArray(item, comment, value);
1413
- item.fragments = typeof result === "boolean" ? void 0 : result?.fragments;
1414
- if (typeof result === "boolean") if (result) item.nodes = item.text == null ? [] : [item.text];
1415
- else item.nodes = void 0;
1416
- else item.nodes = result?.nodes;
1906
+ const { fragments, nodes } = setArray(item, comment, value);
1907
+ item.fragments = fragments;
1908
+ item.nodes = nodes;
1417
1909
  }
1418
1910
  function setReactiveValueForSingle(item, comment, value) {
1419
1911
  const valueIsFragment = isFragment(value);
@@ -1439,7 +1931,7 @@ function setText(item, comment, value) {
1439
1931
  //#endregion
1440
1932
  //#region src/node/index.ts
1441
1933
  function mapNode(data, comment) {
1442
- const matches = EXPRESSION_ABYDON_CONTENT.exec(comment.textContent ?? "");
1934
+ const matches = EXPRESSION_ABYDON_CONTENT.exec(comment.textContent);
1443
1935
  const value = matches == null ? null : data.values[+matches[1]];
1444
1936
  if (value != null) mapValue(data, comment, value);
1445
1937
  }
@@ -1457,23 +1949,27 @@ function mapNodes(data, nodes) {
1457
1949
  }
1458
1950
  }
1459
1951
  function mapTextarea(data, element) {
1460
- const [, index] = EXPRESSION_TEXTAREA_VALUE.exec(element.value) ?? [];
1952
+ const [, index] = EXPRESSION_TEXTAREA_VALUE.exec(element.textContent) ?? EXPRESSION_TEXTAREA_VALUE.exec(element.value) ?? [];
1461
1953
  if (index == null) return;
1954
+ element.textContent = "";
1462
1955
  element.value = "";
1463
1956
  const value = data.values[Number.parseInt(index, 10)];
1464
1957
  if (isSignal(value)) {
1465
- element.value = String(value.peek());
1466
- mapEvent(element, "@on", () => {
1958
+ element.value = getString(value.peek());
1959
+ mapEvent(element, "on", () => {
1467
1960
  value.set(element.value);
1468
1961
  });
1962
+ data.mora.subscribers.add(value.subscribe((value) => {
1963
+ element.value = getString(value);
1964
+ }));
1469
1965
  return;
1470
1966
  }
1471
1967
  let reactive;
1472
1968
  if (typeof value === "function") reactive = computed(value);
1473
1969
  else if (isComputed(value)) reactive = value;
1474
- if (reactive == null) element.value = String(value);
1970
+ if (reactive == null) element.value = "";
1475
1971
  else data.mora.subscribers.add(reactive.subscribe((value) => {
1476
- element.value = String(value);
1972
+ element.value = getString(value);
1477
1973
  }));
1478
1974
  }
1479
1975
  function mapValue(data, comment, value) {
@@ -1482,8 +1978,7 @@ function mapValue(data, comment, value) {
1482
1978
  setComputedValue(data, comment, value);
1483
1979
  break;
1484
1980
  case isFragments(value):
1485
- handleFragments(value, false);
1486
- setReactiveValue(data, comment, value.items);
1981
+ setFragmentsValue(data, comment, value);
1487
1982
  break;
1488
1983
  case isReactive(value):
1489
1984
  setReactiveValue(data, comment, value);
@@ -1507,17 +2002,24 @@ function setComputedValue(data, comment, callback) {
1507
2002
  data.mora.values.add(value);
1508
2003
  setReactiveValue(data, comment, value);
1509
2004
  }
2005
+ function setFragmentsValue(data, comment, fragments) {
2006
+ const state = fragmentsStates.get(fragments);
2007
+ handleFragments(state, false);
2008
+ setReactiveValue(data, comment, state.mapped);
2009
+ }
1510
2010
  //#endregion
1511
2011
  //#region src/parse.ts
1512
2012
  function handleExpression(data, prefix, expression) {
1513
2013
  if (Array.isArray(expression)) {
2014
+ if (EXPRESSION_EVENT_ATTRIBUTE.test(prefix.split(WHITESPACE).at(-1))) return transformExpression(prefix, data.values.push(expression) - 1);
1514
2015
  const { length } = expression;
1515
2016
  let expressions = "";
1516
2017
  for (let index = 0; index < length; index += 1) expressions += handleExpression(data, "", expression[index]);
1517
2018
  return `${prefix}${expressions}`;
1518
2019
  }
1519
2020
  if (typeof expression === "function" || typeof expression === "object" && expression != null) return transformExpression(prefix, data.values.push(expression) - 1);
1520
- return isNullableOrWhitespace(expression) ? prefix : `${prefix}${expression}`;
2021
+ const asString = getString(expression);
2022
+ return asString.trim().length === 0 ? prefix : `${prefix}${asString}`;
1521
2023
  }
1522
2024
  function parse(data) {
1523
2025
  if (data.template != null) return data.template;
@@ -1530,7 +2032,7 @@ function parse(data) {
1530
2032
  return data.template;
1531
2033
  }
1532
2034
  function transformAttribute(_, name, index) {
1533
- return `_${name}="@abydon.${index}@"`;
2035
+ return `abydon-${name}="abydon.${index}"`;
1534
2036
  }
1535
2037
  function transformExpression(prefix, index) {
1536
2038
  return `${prefix}<!--abydon.${index}-->`;
@@ -1544,6 +2046,12 @@ var Fragment = class {
1544
2046
  cache: true
1545
2047
  };
1546
2048
  /**
2049
+ * Is template caching enabled?
2050
+ */
2051
+ get caching() {
2052
+ return this.#configuration.cache;
2053
+ }
2054
+ /**
1547
2055
  * Fragment identifier
1548
2056
  */
1549
2057
  get identifier() {
@@ -1589,9 +2097,9 @@ var Fragment = class {
1589
2097
  if (data.items.length === 0) {
1590
2098
  const templated = html$1(parse(data), { cache: this.#configuration.cache });
1591
2099
  data.items.splice(0, data.items.length, ...templated.map((node) => ({ nodes: [node] })));
1592
- mapNodes(data, data.items.flatMap((item) => item.fragments?.flatMap((fragment) => fragment.get()) ?? item.nodes ?? []));
2100
+ mapNodes(data, data.items.flatMap((item) => item.nodes));
1593
2101
  }
1594
- return data.items.flatMap((item) => item.fragments?.flatMap((fragment) => fragment.get()) ?? item.nodes ?? []);
2102
+ return data.items.flatMap((item) => item.fragments?.flatMap((fragment) => fragment.get()) ?? item.nodes);
1595
2103
  }
1596
2104
  /**
1597
2105
  * Set an identifier for the fragment
@@ -1619,7 +2127,7 @@ function removeFragment(data) {
1619
2127
  const { fragments, nodes } = data.items[index];
1620
2128
  const fragmentsLength = fragments?.length ?? 0;
1621
2129
  for (let fragmentIndex = 0; fragmentIndex < fragmentsLength; fragmentIndex += 1) fragments?.[fragmentIndex]?.remove();
1622
- removeNodes(nodes ?? []);
2130
+ removeNodes(nodes);
1623
2131
  }
1624
2132
  data.items.length = 0;
1625
2133
  length = data.values.length;
@@ -1637,21 +2145,24 @@ function removeMora(data) {
1637
2145
  //#endregion
1638
2146
  //#region src/index.ts
1639
2147
  /**
1640
- * Create Fragments from a reactive array
2148
+ * Create a Fragments from a reactive array
1641
2149
  * @param array Reactive array
1642
2150
  * @param identify Function to identify item
1643
2151
  * @param fragment Function to create fragment from item
1644
2152
  * @returns Fragments
1645
2153
  */
1646
2154
  function fragments(array, identify, fragment) {
2155
+ if (!isArray(array)) throw new TypeError("Fragments array must be a reactive array");
2156
+ if (typeof identify !== "function") throw new TypeError("Fragments identify must be a function");
2157
+ if (typeof fragment !== "function") throw new TypeError("Fragments fragment must be a function");
1647
2158
  return new Fragments(array, identify, fragment);
1648
2159
  }
1649
2160
  /**
1650
- * Create Fragment from a template
2161
+ * Create a Fragment from a template
1651
2162
  * @returns Fragment
1652
2163
  */
1653
2164
  function html(template, ...values) {
1654
2165
  return new Fragment(template, values);
1655
2166
  }
1656
2167
  //#endregion
1657
- export { array, computed, effect, fragments, html, isArray, isComputed, isEffect, isReactive, isSignal, signal, startBatch, stopBatch, store };
2168
+ export { array, computed, effect, fragments, html, isArray, isComputed, isEffect, isFragment, isFragments, isReactive, isSignal, signal, startBatch, stopBatch, store };