@oscarpalmer/abydon 0.15.0 → 0.16.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.
@@ -20,18 +20,18 @@ const METHODS_UPDATE = new Set([
20
20
  const NAME_ARRAY = "array";
21
21
  const NAME_COMPUTED = "computed";
22
22
  const NAME_EFFECT = "effect";
23
+ const NAME_MORA = "$mora";
23
24
  const NAME_SIGNAL = "signal";
24
25
  const NAME_STORE = "store";
25
- const NAMES = new Set([
26
+ const NAME_ALL = new Set([
26
27
  NAME_ARRAY,
27
28
  NAME_COMPUTED,
28
29
  NAME_SIGNAL,
29
30
  NAME_STORE
30
31
  ]);
31
-
32
32
  var Effect = class {
33
33
  constructor(callback) {
34
- Object.defineProperty(this, "$mora", { value: NAME_EFFECT });
34
+ Object.defineProperty(this, NAME_MORA, { value: NAME_EFFECT });
35
35
  this.state = { callback };
36
36
  runEffect(this);
37
37
  }
@@ -48,7 +48,6 @@ function runEffect(effect$1) {
48
48
  function effect(callback) {
49
49
  return typeof callback === "function" ? new Effect(callback) : void 0;
50
50
  }
51
-
52
51
  function isArray(value) {
53
52
  return isMora(value, NAME_ARRAY);
54
53
  }
@@ -59,15 +58,14 @@ function isEffect(value) {
59
58
  return isMora(value, NAME_EFFECT);
60
59
  }
61
60
  function isMora(value, name) {
62
- return typeof value === "object" && value != null && "$mora" in value && (typeof name === "string" ? value.$mora === name : name.has(value.$mora));
61
+ return typeof value === "object" && value != null && "$mora" in value && (typeof name === "string" ? value["$mora"] === name : name.has(value["$mora"]));
63
62
  }
64
63
  function isReactive(value) {
65
- return isMora(value, NAMES);
64
+ return isMora(value, NAME_ALL);
66
65
  }
67
66
  function isSignal(value) {
68
67
  return isMora(value, NAME_SIGNAL);
69
68
  }
70
-
71
69
  function flushHandlers() {
72
70
  while (BATCH.depth === 0 && BATCH.handlers.size > 0) {
73
71
  const handlers = [...BATCH.handlers];
@@ -83,7 +81,6 @@ function stopBatch() {
83
81
  if (BATCH.depth > 0) BATCH.depth -= 1;
84
82
  flushHandlers();
85
83
  }
86
-
87
84
  var Subscription = class {
88
85
  callback;
89
86
  state;
@@ -93,13 +90,13 @@ var Subscription = class {
93
90
  callback(state.value);
94
91
  }
95
92
  destroy() {
96
- this.callback = noop;
93
+ this.callback = noop$1;
97
94
  this.state = void 0;
98
95
  }
99
96
  };
100
- function noop() {}
97
+ function noop$1() {}
101
98
  function subscribe(state, callback) {
102
- if (typeof callback !== "function" || state.subscriptions.has(callback)) return noop;
99
+ if (typeof callback !== "function" || state.subscriptions.has(callback)) return noop$1;
103
100
  state.subscriptions.set(callback, new Subscription(state, callback));
104
101
  return () => {
105
102
  unsubscribe(state, callback);
@@ -109,7 +106,6 @@ function unsubscribe(state, callback) {
109
106
  state.subscriptions.get(callback)?.destroy();
110
107
  state.subscriptions.delete(callback);
111
108
  }
112
-
113
109
  var Reactive = class {
114
110
  state = {
115
111
  computeds: /* @__PURE__ */ new Set(),
@@ -121,7 +117,7 @@ var Reactive = class {
121
117
  constructor(name, value, options) {
122
118
  this.state.value = value;
123
119
  if (typeof options === "object" && typeof options.equal === "function") this.state.equal = options.equal;
124
- Object.defineProperty(this, "$mora", { value: name });
120
+ Object.defineProperty(this, NAME_MORA, { value: name });
125
121
  }
126
122
  peek() {
127
123
  return this.state.value;
@@ -139,7 +135,6 @@ var Reactive = class {
139
135
  unsubscribe(this.state, callback);
140
136
  }
141
137
  };
142
-
143
138
  var Computed = class extends Reactive {
144
139
  effect = {
145
140
  dirty: true,
@@ -172,10 +167,9 @@ var Computed = class extends Reactive {
172
167
  function computed(callback, options) {
173
168
  return new Computed(callback, options);
174
169
  }
175
-
176
170
  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);
171
+ for (const computed$1 of state.computeds) computed$1.effect.dirty = true;
172
+ for (const effect$1 of state.effects) BATCH.handlers.add(effect$1);
179
173
  for (const [, subscription] of state.subscriptions) BATCH.handlers.add(subscription);
180
174
  if (BATCH.depth === 0) flushHandlers();
181
175
  }
@@ -197,7 +191,6 @@ function getValue$1(state) {
197
191
  if (ACTIVE.effect != null) state.effects.add(ACTIVE.effect);
198
192
  return state.value;
199
193
  }
200
-
201
194
  var Signal = class extends Reactive {
202
195
  constructor(value, options) {
203
196
  super(NAME_SIGNAL, value, options);
@@ -218,14 +211,16 @@ var Signal = class extends Reactive {
218
211
  function signal(value, options) {
219
212
  return new Signal(value, options);
220
213
  }
221
-
222
- function getReactiveValueInProxy(reactive, mapped, key, isArray) {
214
+ function emityProxyValues(state, mapped) {
215
+ const values = [...mapped.values()];
216
+ const { length } = values;
217
+ for (let index = 0; index < length; index += 1) values[index].effect.dirty = true;
218
+ emitValue(state);
219
+ }
220
+ function getReactiveValueInProxy(reactive, mapped, key, isArray$1) {
223
221
  let item = mapped.get(key);
224
222
  if (item == null) {
225
- item = computed(() => {
226
- const value = reactive.get();
227
- return isArray ? value.at(key) : value[key];
228
- });
223
+ item = computed(() => isArray$1 ? reactive.get().at(key) : reactive.get()[key]);
229
224
  mapped.set(key, item);
230
225
  }
231
226
  return item;
@@ -247,19 +242,18 @@ function setProxyValue(proxy, value) {
247
242
  stopBatch();
248
243
  }
249
244
  function setValueInProxy(parameters) {
250
- const { isArray, length, property, state, target, value } = parameters;
251
- if (isArray) {
245
+ const { isArray: isArray$1, length, property, state, target, value } = parameters;
246
+ if (isArray$1) {
252
247
  if (!(!Number.isNaN(Number(property)) || property === "length")) return Reflect.set(target, property, value);
253
248
  }
254
249
  const previous = Reflect.get(target, property);
255
250
  if (!state.equal(previous, value)) {
256
251
  Reflect.set(target, property, value);
257
252
  emitValue(state);
258
- if (isArray) length?.set(target.length);
253
+ if (isArray$1) length?.set(target.length);
259
254
  }
260
255
  return true;
261
256
  }
262
-
263
257
  var ReactiveArray = class extends Reactive {
264
258
  #indiced = /* @__PURE__ */ new Map();
265
259
  #size = signal(0);
@@ -291,19 +285,17 @@ var ReactiveArray = class extends Reactive {
291
285
  }
292
286
  get(first) {
293
287
  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);
288
+ return first === "length" ? this.length : getValue$1(this.state);
296
289
  }
297
290
  map(callback) {
298
291
  return computed(() => this.get().map(callback));
299
292
  }
300
293
  notify() {
301
- emitValue(this.state);
294
+ emityProxyValues(this.state, this.#indiced);
302
295
  }
303
296
  peek(value) {
304
297
  if (value === "length") return this.#size.peek();
305
- if (typeof value === "number") return this.state.value.at(value);
306
- return [...this.state.value];
298
+ return typeof value === "number" ? this.state.value.at(value) : [...this.state.value];
307
299
  }
308
300
  pop() {
309
301
  return this.state.value.pop();
@@ -324,7 +316,7 @@ var ReactiveArray = class extends Reactive {
324
316
  }
325
317
  subscribe(first, second) {
326
318
  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;
319
+ return typeof first === "function" ? subscribe(this.state, first) : noop$1;
328
320
  }
329
321
  unshift(...items) {
330
322
  return this.state.value.unshift(...items);
@@ -354,30 +346,28 @@ function setAtIndex(array$1, index, value) {
354
346
  const actual = index < 0 ? array$1.length + index : index;
355
347
  if (actual > -1) array$1[actual] = value;
356
348
  }
357
-
358
349
  function isKey(value) {
359
350
  return typeof value === "number" || typeof value === "string";
360
351
  }
361
- function isPlainObject(value) {
352
+ function isPlainObject$2(value) {
362
353
  if (value === null || typeof value !== "object") return false;
363
354
  if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
364
355
  const prototype = Object.getPrototypeOf(value);
365
356
  return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
366
357
  }
367
-
368
- function getString(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(value));
378
- }
379
- var EXPRESSION_WHITESPACE = /^\s*$/;
380
-
358
+ new Set([
359
+ Int8Array,
360
+ Uint8Array,
361
+ Uint8ClampedArray,
362
+ Int16Array,
363
+ Uint16Array,
364
+ Int32Array,
365
+ Uint32Array,
366
+ Float32Array,
367
+ Float64Array,
368
+ BigInt64Array,
369
+ BigUint64Array
370
+ ]);
381
371
  var Store = class extends Reactive {
382
372
  #keyed = /* @__PURE__ */ new Map();
383
373
  constructor(value, options) {
@@ -392,96 +382,166 @@ var Store = class extends Reactive {
392
382
  get(key) {
393
383
  return isKey(key) ? getReactiveValueInProxy(this, this.#keyed, key, false).get() : getValue$1(this.state);
394
384
  }
385
+ notify() {
386
+ emityProxyValues(this.state, this.#keyed);
387
+ }
395
388
  peek(key) {
396
389
  return isKey(key) ? this.state.value[key] : { ...this.state.value };
397
390
  }
398
391
  set(first, second) {
399
392
  if (isKey(first)) this.state.value[first] = second;
400
- else if (first == null || isPlainObject(first)) setProxyValue(this.state.value, first ?? {});
393
+ else if (first == null || isPlainObject$2(first)) setProxyValue(this.state.value, first ?? {});
401
394
  }
402
395
  subscribe(first, second) {
403
396
  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;
397
+ return typeof first === "function" ? subscribe(this.state, first) : noop$1;
405
398
  }
406
399
  update(callback) {
407
400
  const updated = callback({ ...this.state.value });
408
- if (updated == null || isPlainObject(updated)) setProxyValue(this.state.value, updated ?? {});
401
+ if (updated == null || isPlainObject$2(updated)) setProxyValue(this.state.value, updated ?? {});
409
402
  }
410
403
  };
411
404
  function store(value, options) {
412
- return new Store(isPlainObject(value) ? value : {}, options);
405
+ return new Store(isPlainObject$2(value) ? value : {}, options);
413
406
  }
414
-
415
- function isChildNode(value) {
416
- return value instanceof Node && CHILD_NODE_TYPES.has(value.nodeType);
407
+ function isPlainObject$1(value) {
408
+ if (value === null || typeof value !== "object") return false;
409
+ if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
410
+ const prototype = Object.getPrototypeOf(value);
411
+ return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
412
+ }
413
+ new Set([
414
+ Int8Array,
415
+ Uint8Array,
416
+ Uint8ClampedArray,
417
+ Int16Array,
418
+ Uint16Array,
419
+ Int32Array,
420
+ Uint32Array,
421
+ Float32Array,
422
+ Float64Array,
423
+ BigInt64Array,
424
+ BigUint64Array
425
+ ]);
426
+ function getString$1(value) {
427
+ if (typeof value === "string") return value;
428
+ if (value == null) return "";
429
+ if (typeof value === "function") return getString$1(value());
430
+ if (typeof value !== "object") return String(value);
431
+ const asString = String(value.valueOf?.() ?? value);
432
+ return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
433
+ }
434
+ function isNullableOrWhitespace(value) {
435
+ return value == null || EXPRESSION_WHITESPACE$1.test(getString$1(value));
436
+ }
437
+ var EXPRESSION_WHITESPACE$1 = /^\s*$/;
438
+ function isEventTarget(value) {
439
+ return typeof value === "object" && value != null && typeof value.addEventListener === "function" && typeof value.removeEventListener === "function" && typeof value.dispatchEvent === "function";
417
440
  }
418
441
  function isHTMLOrSVGElement(value) {
419
442
  return value instanceof HTMLElement || value instanceof SVGElement;
420
443
  }
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
444
+ function getString(value) {
445
+ if (typeof value === "string") return value;
446
+ if (value == null) return "";
447
+ if (typeof value === "function") return getString(value());
448
+ if (typeof value !== "object") return String(value);
449
+ const asString = String(value.valueOf?.() ?? value);
450
+ return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
451
+ }
452
+ function isPlainObject(value) {
453
+ if (value === null || typeof value !== "object") return false;
454
+ if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
455
+ const prototype = Object.getPrototypeOf(value);
456
+ return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
457
+ }
458
+ new Set([
459
+ Int8Array,
460
+ Uint8Array,
461
+ Uint8ClampedArray,
462
+ Int16Array,
463
+ Uint16Array,
464
+ Int32Array,
465
+ Uint32Array,
466
+ Float32Array,
467
+ Float64Array,
468
+ BigInt64Array,
469
+ BigUint64Array
427
470
  ]);
428
-
471
+ function badAttributeHandler(name, value) {
472
+ if (name == null || value == null) return true;
473
+ if (EXPRESSION_CLOBBERED_NAME.test(name) && (value in document || value in formElement) || EXPRESSION_EVENT_NAME$1.test(name)) return true;
474
+ if (EXPRESSION_SKIP_NAME.test(name) || EXPRESSION_URI_VALUE.test(value) || isValidSourceAttribute(name, value)) return false;
475
+ return EXPRESSION_DATA_OR_SCRIPT.test(value);
476
+ }
477
+ function booleanAttributeHandler(name, value) {
478
+ if (name == null || value == null) return true;
479
+ if (!booleanAttributesSet.has(name)) return false;
480
+ const normalized = value.toLowerCase().trim();
481
+ return !(normalized.length === 0 || normalized === name);
482
+ }
483
+ function decodeAttribute(value) {
484
+ textArea ??= document.createElement("textarea");
485
+ textArea.innerHTML = value;
486
+ return decodeURIComponent(textArea.value);
487
+ }
488
+ function handleAttribute(callback, decode, first, second) {
489
+ let name;
490
+ let value;
491
+ if (isAttribute(first)) {
492
+ name = first.name;
493
+ value = String(first.value);
494
+ } else if (typeof first === "string" && typeof second === "string") {
495
+ name = first;
496
+ value = second;
497
+ }
498
+ if (decode && value != null) value = decodeAttribute(value);
499
+ return callback(name, value?.replace(EXPRESSION_WHITESPACE, ""));
500
+ }
429
501
  function isAttribute(value) {
430
502
  return value instanceof Attr || isPlainObject(value) && typeof value.name === "string" && typeof value.value === "string";
431
503
  }
432
- function isBadAttribute(first, second) {
433
- 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);
504
+ function _isBadAttribute(first, second, decode) {
505
+ return handleAttribute(badAttributeHandler, decode, first, second);
434
506
  }
435
- function isBooleanAttribute(value) {
436
- return validateAttribute((attribute) => attribute != null && booleanAttributes.includes(attribute.name.toLowerCase()), value, "");
507
+ function _isBooleanAttribute(first, decode) {
508
+ return handleAttribute((name) => booleanAttributesSet.has(name?.toLowerCase()), decode, first, "");
437
509
  }
438
- function isEmptyNonBooleanAttribute(first, second) {
439
- return validateAttribute((attribute) => attribute != null && !booleanAttributes.includes(attribute.name) && String(attribute.value).trim().length === 0, first, second);
510
+ function _isEmptyNonBooleanAttribute(first, second, decode) {
511
+ return handleAttribute((name, value) => name != null && value != null && !booleanAttributesSet.has(name) && value.trim().length === 0, decode, first, second);
440
512
  }
441
- function isInvalidBooleanAttribute(first, second) {
442
- return validateAttribute((attribute) => {
443
- if (attribute == null) return true;
444
- if (!booleanAttributes.includes(attribute.name)) return false;
445
- const normalized = String(attribute.value).toLowerCase().trim();
446
- return !(normalized.length === 0 || normalized === attribute.name);
447
- }, first, second);
513
+ function _isInvalidBooleanAttribute(first, second, decode) {
514
+ return handleAttribute(booleanAttributeHandler, decode, first, second);
448
515
  }
449
516
  function isProperty(value) {
450
517
  return isPlainObject(value) && typeof value.name === "string";
451
518
  }
452
- function setAttribute$1(element, first, second) {
453
- updateValue(element, first, second, updateAttribute);
454
- }
455
- function setProperty(element, first, second) {
456
- updateValue(element, first, second, updateProperty$1);
519
+ function isValidSourceAttribute(name, value) {
520
+ return EXPRESSION_SOURCE_NAME.test(name) && EXPRESSION_SOURCE_VALUE.test(value);
457
521
  }
458
522
  function updateAttribute(element, name, value) {
459
- if (booleanAttributes.includes(name.toLowerCase())) updateProperty$1(element, name, value, false);
460
- else if (value == null) element.removeAttribute(name);
461
- else element.setAttribute(name, typeof value === "string" ? value : getString(value));
523
+ const isBoolean = booleanAttributesSet.has(name.toLowerCase());
524
+ if (isBoolean) updateProperty$1(element, name, value);
525
+ if (isBoolean ? value !== true : value == null) element.removeAttribute(name);
526
+ else element.setAttribute(name, isBoolean ? "" : getString(value));
462
527
  }
463
- function updateProperty$1(element, name, value, validate) {
464
- const actual = validate ?? true ? name.toLowerCase() : name;
465
- if (actual === "hidden") element.hidden = value === "" || value === true;
466
- else element[actual] = value === "" || typeof value === "string" && value.toLowerCase() === actual || value === true;
528
+ function updateProperty$1(element, name, value) {
529
+ const actual = name.toLowerCase();
530
+ element[actual] = value === "" || typeof value === "string" && value.toLowerCase() === actual || value === true;
467
531
  }
468
- function updateValue(element, first, second, callback) {
532
+ function updateValue$1(element, first, second) {
469
533
  if (!isHTMLOrSVGElement(element)) return;
470
- if (isProperty(first)) callback(element, first.name, first.value);
471
- else if (typeof first === "string") callback(element, first, second);
472
- }
473
- function validateAttribute(callback, first, second) {
474
- let attribute;
475
- if (isAttribute(first)) attribute = first;
476
- else if (typeof first === "string" && typeof second === "string") attribute = {
477
- name: first,
478
- value: second
479
- };
480
- return callback(attribute);
481
- }
482
- var EXPRESSION_ON_PREFIX = /^on/i;
483
- var EXPRESSION_SOURCE_PREFIX = /^(href|src|xlink:href)$/i;
484
- var EXPRESSION_VALUE_PREFIX = /(data:text\/html|javascript:)/i;
534
+ if (isProperty(first)) updateAttribute(element, first.name, first.value);
535
+ else if (typeof first === "string") updateAttribute(element, first, second);
536
+ }
537
+ var EXPRESSION_CLOBBERED_NAME = /^(id|name)$/i;
538
+ var EXPRESSION_DATA_OR_SCRIPT = /^(?:data|\w+script):/i;
539
+ var EXPRESSION_EVENT_NAME$1 = /^on/i;
540
+ var EXPRESSION_SKIP_NAME = /^(aria-[-\w]+|data-[-\w.\u00B7-\uFFFF]+)$/i;
541
+ var EXPRESSION_SOURCE_NAME = /^src$/i;
542
+ var EXPRESSION_SOURCE_VALUE = /^data:/i;
543
+ var EXPRESSION_URI_VALUE = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i;
544
+ var EXPRESSION_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g;
485
545
  const booleanAttributes = Object.freeze([
486
546
  "async",
487
547
  "autofocus",
@@ -508,62 +568,106 @@ const booleanAttributes = Object.freeze([
508
568
  "reversed",
509
569
  "selected"
510
570
  ]);
511
-
512
- function sanitizeAttributes(element, attributes, options) {
571
+ var booleanAttributesSet = new Set(booleanAttributes);
572
+ var formElement = document.createElement("form");
573
+ var textArea;
574
+ function setAttribute$1(element, first, second) {
575
+ updateValue$1(element, first, second);
576
+ }
577
+ function setProperty(element, first, second) {
578
+ updateValue$1(element, first, second);
579
+ }
580
+ function handleElement(element, depth) {
581
+ if (depth === 0) {
582
+ const removable = element.querySelectorAll(REMOVE_SELECTOR);
583
+ for (const item of removable) item.remove();
584
+ }
585
+ sanitizeAttributes(element, [...element.attributes]);
586
+ }
587
+ function isClobbered(value) {
588
+ return value instanceof HTMLFormElement && (typeof value.nodeName !== "string" || typeof value.textContent !== "string" || typeof value.removeChild !== "function" || !(value.attributes instanceof NamedNodeMap) || typeof value.removeAttribute !== "function" || typeof value.setAttribute !== "function" || typeof value.namespaceURI !== "string" || typeof value.insertBefore !== "function" || typeof value.hasChildNodes !== "function");
589
+ }
590
+ function removeNode(node) {
591
+ if (typeof node.remove === "function") node.remove();
592
+ }
593
+ function sanitizeAttributes(element, attributes) {
513
594
  const { length } = attributes;
514
595
  for (let index = 0; index < length; index += 1) {
515
- const attribute = attributes[index];
516
- if (isBadAttribute(attribute) || isEmptyNonBooleanAttribute(attribute)) element.removeAttribute(attribute.name);
517
- else if (options.sanitizeBooleanAttributes && isInvalidBooleanAttribute(attribute)) element.setAttribute(attribute.name, "");
596
+ const { name, value } = attributes[index];
597
+ if (_isBadAttribute(name, value, false) || _isEmptyNonBooleanAttribute(name, value, false)) element.removeAttribute(name);
598
+ else if (_isInvalidBooleanAttribute(name, value, false)) setAttribute$1(element, name, true);
518
599
  }
519
600
  }
520
- function sanitizeNodes$1(nodes, options) {
601
+ function sanitizeNodes(nodes, depth) {
521
602
  const actual = nodes.filter((node) => node instanceof Node);
522
- const { length } = nodes;
603
+ let { length } = nodes;
523
604
  for (let index = 0; index < length; index += 1) {
524
605
  const node = actual[index];
525
- if (node instanceof Element) {
526
- const scripts = node.querySelectorAll("script");
527
- for (const script of scripts) script.remove();
528
- sanitizeAttributes(node, [...node.attributes], options);
606
+ let remove = isClobbered(node);
607
+ if (!remove) switch (node.nodeType) {
608
+ case Node.ELEMENT_NODE:
609
+ handleElement(node, depth);
610
+ break;
611
+ case Node.COMMENT_NODE:
612
+ remove = COMMENT_HARMFUL.test(node.data);
613
+ break;
614
+ case Node.DOCUMENT_TYPE_NODE:
615
+ case Node.PROCESSING_INSTRUCTION_NODE:
616
+ remove = true;
617
+ break;
618
+ }
619
+ if (remove) {
620
+ removeNode(node);
621
+ actual.splice(index, 1);
622
+ index -= 1;
623
+ length -= 1;
624
+ continue;
529
625
  }
530
- if (node.hasChildNodes()) sanitizeNodes$1([...node.childNodes], options);
626
+ if (node.hasChildNodes()) sanitizeNodes([...node.childNodes], depth + 1);
531
627
  }
532
628
  return nodes;
533
629
  }
534
-
535
- function createTemplate(html$1, ignore) {
536
- const template = document.createElement("template");
537
- template.innerHTML = html$1;
538
- if (!ignore) templates[html$1] = template;
630
+ var COMMENT_HARMFUL = /<[/\w]/g;
631
+ var REMOVE_SELECTOR = "script, toretto-temporary";
632
+ function createHtml(value) {
633
+ const parsed = getParser().parseFromString(getHtml(value), PARSE_TYPE_HTML);
634
+ parsed.body.normalize();
635
+ sanitizeNodes([parsed.body], 0);
636
+ return parsed.body.innerHTML;
637
+ }
638
+ function createTemplate(value, options) {
639
+ const template = document.createElement(TEMPLATE_TAG);
640
+ template.innerHTML = createHtml(value);
641
+ if (typeof value === "string" && options.cache) templates[value] = template;
539
642
  return template;
540
643
  }
541
- function getHtml(value, options) {
644
+ function getHtml(value) {
645
+ return `${TEMPORARY_ELEMENT}${typeof value === "string" ? value : value.innerHTML}${TEMPORARY_ELEMENT}`;
646
+ }
647
+ function getNodes(value, options) {
542
648
  if (typeof value !== "string" && !(value instanceof HTMLTemplateElement)) return [];
543
- const template = value instanceof HTMLTemplateElement ? value : getTemplate(value, options.ignoreCache);
544
- if (template == null) return [];
545
- const cloned = template.content.cloneNode(true);
546
- const scripts = cloned.querySelectorAll("script");
547
- for (const script of scripts) script.remove();
548
- cloned.normalize();
549
- return sanitizeNodes$1([...cloned.childNodes], options);
649
+ const template = getTemplate(value, options);
650
+ return template == null ? [] : [...template.content.cloneNode(true).childNodes];
550
651
  }
551
652
  function getOptions$1(input) {
552
653
  const options = isPlainObject(input) ? input : {};
553
- options.ignoreCache = typeof options.ignoreCache === "boolean" ? options.ignoreCache : false;
554
- options.sanitizeBooleanAttributes = typeof options.sanitizeBooleanAttributes === "boolean" ? options.sanitizeBooleanAttributes : true;
654
+ options.cache = typeof options.cache === "boolean" ? options.cache : true;
555
655
  return options;
556
656
  }
557
- function getTemplate(value, ignore) {
558
- if (typeof value !== "string" || value.trim().length === 0) return;
657
+ function getParser() {
658
+ parser ??= new DOMParser();
659
+ return parser;
660
+ }
661
+ function getTemplate(value, options) {
662
+ if (value instanceof HTMLTemplateElement) return createTemplate(value, options);
663
+ if (value.trim().length === 0) return;
559
664
  let template = templates[value];
560
665
  if (template != null) return template;
561
666
  const element = EXPRESSION_ID.test(value) ? document.querySelector(`#${value}`) : null;
562
- template = element instanceof HTMLTemplateElement ? element : createTemplate(value, ignore);
563
- return template;
667
+ return createTemplate(element instanceof HTMLTemplateElement ? element : value, options);
564
668
  }
565
669
  var html$1 = ((value, options) => {
566
- return getHtml(value, getOptions$1(options));
670
+ return getNodes(value, getOptions$1(options));
567
671
  });
568
672
  html$1.clear = () => {
569
673
  templates = {};
@@ -580,695 +684,639 @@ html$1.remove = (template) => {
580
684
  templates = updated;
581
685
  };
582
686
  var EXPRESSION_ID = /^[a-z][\w-]*$/i;
687
+ var PARSE_TYPE_HTML = "text/html";
688
+ var TEMPLATE_TAG = "template";
689
+ var TEMPORARY_ELEMENT = "<toretto-temporary></toretto-temporary>";
690
+ var parser;
583
691
  var templates = {};
584
-
692
+ const ATTRIBUTE_CLASS_PREFIX_LENGTH = 6;
693
+ const EVENT_DEFAULTS = {
694
+ A: "click",
695
+ BUTTON: "click",
696
+ DETAILS: "toggle",
697
+ FORM: "submit",
698
+ SELECT: "change",
699
+ TEXTAREA: "input"
700
+ };
701
+ const EXPRESSION_ABYDON_ATTRIBUTE_FULL = /(@?\w+)="<!--abydon.(\d+)-->"/g;
702
+ const EXPRESSION_ABYDON_ATTRIBUTE_PREFIX = /^_/;
703
+ const EXPRESSION_ABYDON_CONTENT = /^@?abydon\.(\d+)@?$/;
704
+ const EXPRESSION_ATTRIBUTE_CLASS = /^class\./;
705
+ const EXPRESSION_ATTRIBUTE_STYLE_FULL = /^style\.([\w-]+)(?:\.([\w-]+))?$/;
706
+ const EXPRESSION_ATTRIBUTE_STYLE_PREFIX = /^style\./;
707
+ const EXPRESSION_EVENT_CHANGE_TYPES = /^(checkbox|radio)$/;
708
+ const EXPRESSION_EVENT_NAME = /^@([\w-]+)(?::([a-z:]+))?$/i;
709
+ const EXPRESSION_EVENT_OPTIONS_ACTIVE = /^a(ctive)$/i;
710
+ const EXPRESSION_EVENT_OPTIONS_CAPTURE = /^c(apture)$/i;
711
+ const EXPRESSION_EVENT_OPTIONS_ONCE = /^o(nce)$/i;
712
+ const EXPRESSION_EVENT_PREFIX = /^@/;
713
+ const EXPRESSION_PERIOD = /\./;
714
+ const NAME_FRAGMENT = "$fragment";
715
+ const NAME_FRAGMENTS = "$fragments";
585
716
  function compareArrays(first, second) {
586
- const firstIsLarger = first.length > second.length;
587
- const from = firstIsLarger ? first : second;
588
- const to = firstIsLarger ? second : first;
589
- if (!from
590
- .filter(key => to.includes(key))
591
- .every((key, index) => to[index] === key)) {
592
- return 'dissimilar';
593
- }
594
- return firstIsLarger ? 'removed' : 'added';
717
+ const firstIsLarger = first.length > second.length;
718
+ const from = firstIsLarger ? first : second;
719
+ const to = firstIsLarger ? second : first;
720
+ if (!from.filter((key) => to.includes(key)).every((key, index) => to[index] === key)) return COMPARISON_DISSIMILAR;
721
+ return firstIsLarger ? COMPARISON_REMOVED : COMPARISON_ADDED;
595
722
  }
596
723
  function isFragment(value) {
597
- return (typeof value === 'object' &&
598
- value != null &&
599
- '$fragment' in value &&
600
- value.$fragment === true);
724
+ return isNamed(value, NAME_FRAGMENT);
601
725
  }
602
726
  function isFragments(value) {
603
- return (typeof value === 'object' &&
604
- value != null &&
605
- '$fragments' in value &&
606
- value.$fragments === true);
607
- }
608
-
609
- class Fragments {
610
- #state;
611
- /**
612
- * Fragment items
613
- */
614
- get items() {
615
- return this.#state.mapped;
616
- }
617
- constructor(items, identify, fragment) {
618
- Object.defineProperty(this, '$fragments', {
619
- value: true,
620
- });
621
- this.#state = {
622
- fragment,
623
- identify,
624
- array: items,
625
- instances: {},
626
- mapped: array([]),
627
- subscriber: undefined,
628
- };
629
- states.set(this, this.#state);
630
- initializeFragments(this.#state);
631
- }
632
- }
727
+ return isNamed(value, NAME_FRAGMENTS);
728
+ }
729
+ function isNamed(value, name) {
730
+ return typeof value === "object" && value != null && name in value && value[name] === true;
731
+ }
732
+ const COMPARISON_ADDED = "added";
733
+ const COMPARISON_DISSIMILAR = "dissimilar";
734
+ const COMPARISON_REMOVED = "removed";
735
+ var Fragments = class {
736
+ #state;
737
+ get items() {
738
+ return this.#state.mapped;
739
+ }
740
+ constructor(items, identify, fragment) {
741
+ Object.defineProperty(this, NAME_FRAGMENTS, { value: true });
742
+ this.#state = {
743
+ fragment,
744
+ identify,
745
+ array: items,
746
+ instances: {},
747
+ mapped: array([]),
748
+ subscriber: void 0
749
+ };
750
+ states.set(this, this.#state);
751
+ initializeFragments(this.#state);
752
+ }
753
+ };
633
754
  function handleFragments(item, remove) {
634
- const state = isFragments(item) ? states.get(item) : item;
635
- if (state != null) {
636
- (remove ? removeFragments$1 : initializeFragments)(state);
637
- }
755
+ const state = isFragments(item) ? states.get(item) : item;
756
+ if (state != null) (remove ? removeFragments$1 : initializeFragments)(state);
638
757
  }
639
758
  function handleItems(state, items) {
640
- const keys = new Set();
641
- const mapped = [];
642
- const { length } = items;
643
- for (let index = 0; index < length; index += 1) {
644
- const item = items[index];
645
- const identifier = state.identify(item);
646
- if (identifier == null) {
647
- throw new Error('Identifier cannot be null or undefined');
648
- }
649
- const key = getString(identifier);
650
- if (keys.has(key)) {
651
- throw new Error(`Duplicate identifier found: "${key}"`);
652
- }
653
- let instance = state.instances[key];
654
- if (instance == null) {
655
- instance = state.fragment(item);
656
- if (!isFragment(instance)) {
657
- throw new Error('Fragment function must return a Fragment instance');
658
- }
659
- }
660
- instance.identify(key);
661
- state.instances[key] = instance;
662
- keys.add(key);
663
- mapped.push(instance);
664
- }
665
- state.mapped.set(mapped);
666
- updateFragments(state, keys);
759
+ const keys = /* @__PURE__ */ new Set();
760
+ const mapped = [];
761
+ const { length } = items;
762
+ for (let index = 0; index < length; index += 1) {
763
+ const item = items[index];
764
+ const identifier = state.identify(item);
765
+ if (identifier == null) throw new Error("Identifier cannot be null or undefined");
766
+ const key = getString$1(identifier);
767
+ if (keys.has(key)) throw new Error(`Duplicate identifier found: "${key}"`);
768
+ let instance = state.instances[key];
769
+ if (instance == null) {
770
+ instance = state.fragment(item);
771
+ if (!isFragment(instance)) throw new Error("Fragment function must return a Fragment instance");
772
+ }
773
+ instance.identify(key);
774
+ state.instances[key] = instance;
775
+ keys.add(key);
776
+ mapped.push(instance);
777
+ }
778
+ state.mapped.set(mapped);
779
+ updateFragments(state, keys);
667
780
  }
668
781
  function initializeFragments(state) {
669
- state.subscriber ??= state.array.subscribe(items => {
670
- handleItems(state, items);
671
- });
782
+ state.subscriber ??= state.array.subscribe((items) => {
783
+ handleItems(state, items);
784
+ });
672
785
  }
673
786
  function removeFragments$1(state) {
674
- state.subscriber?.();
675
- updateFragments(state);
676
- state.subscriber = undefined;
787
+ state.subscriber?.();
788
+ updateFragments(state);
789
+ state.subscriber = void 0;
677
790
  }
678
791
  function updateFragments(state, active) {
679
- const next = {};
680
- const previous = { ...state.instances };
681
- const keys = Object.keys(previous);
682
- const { length } = keys;
683
- for (let index = 0; index < length; index += 1) {
684
- const key = keys[index];
685
- if (active?.has(key)) {
686
- next[key] = previous[key];
687
- }
688
- else {
689
- previous[key].remove();
690
- }
691
- }
692
- state.instances = next;
693
- active?.clear();
694
- }
695
- //
696
- const states = new WeakMap();
697
-
698
- const ABORT_CONTROLLERS = new WeakMap();
699
- const ATTRIBUTE_CLASS_PREFIX_LENGTH = 6;
700
- const EXPRESSION_ATTRIBUTE_CLASS = /^class\./;
701
- const EXPRESSION_ATTRIBUTE_STYLE_FULL = /^style\.([\w-]+)(?:\.([\w-]+))?$/;
702
- const EXPRESSION_ATTRIBUTE_STYLE_PREFIX = /^style\./;
703
- const EXPRESSION_COMMENT_FULL = /^<!--abydon\.(\d+)-->$/;
704
- const EXPRESSION_COMMENT_CONTENT = /^abydon\.(\d+)$/;
705
- const EXPRESSION_EVENT_NAME = /^@([\w-]+)(?::([a-z:]+))?$/i;
706
- const REASON_EVENT_REMOVED = 'Event removed as element was removed from document by Abydon';
707
-
708
- function getController(element) {
709
- let controller = ABORT_CONTROLLERS.get(element);
710
- if (controller == null) {
711
- controller = new AbortController();
712
- ABORT_CONTROLLERS.set(element, controller);
713
- }
714
- return controller;
792
+ const next = {};
793
+ const previous = { ...state.instances };
794
+ const keys = Object.keys(previous);
795
+ const { length } = keys;
796
+ for (let index = 0; index < length; index += 1) {
797
+ const key = keys[index];
798
+ if (active?.has(key)) next[key] = previous[key];
799
+ else previous[key].remove();
800
+ }
801
+ state.instances = next;
802
+ active?.clear();
715
803
  }
716
- function getOptions(options) {
717
- const parts = options.split(':');
718
- return {
719
- capture: parts.includes('c') || parts.includes('capture'),
720
- once: parts.includes('o') || parts.includes('once'),
721
- passive: !(parts.includes('a') || parts.includes('active')),
722
- };
804
+ const states = /* @__PURE__ */ new WeakMap();
805
+ function isChildNode(value) {
806
+ return value instanceof Node && CHILD_NODE_TYPES.has(value.nodeType);
723
807
  }
724
- function mapEvent(element, name, value) {
725
- element.removeAttribute(name);
726
- const [, type, options] = EXPRESSION_EVENT_NAME.exec(name) ?? [];
727
- if (typeof value === 'function' && type != null) {
728
- element.addEventListener(type, value, {
729
- ...getOptions(options ?? ''),
730
- signal: getController(element).signal,
731
- });
732
- }
733
- }
734
- function removeEvents(element) {
735
- ABORT_CONTROLLERS.get(element)?.abort(REASON_EVENT_REMOVED);
736
- ABORT_CONTROLLERS.delete(element);
737
- }
738
-
808
+ var CHILD_NODE_TYPES = new Set([
809
+ Node.ELEMENT_NODE,
810
+ Node.TEXT_NODE,
811
+ Node.PROCESSING_INSTRUCTION_NODE,
812
+ Node.COMMENT_NODE,
813
+ Node.DOCUMENT_TYPE_NODE
814
+ ]);
739
815
  function createNodes(value) {
740
- if (isFragment(value)) {
741
- return value.get();
742
- }
743
- if (isChildNode(value)) {
744
- return [value];
745
- }
746
- return [new Text(getString(value))];
816
+ if (isFragment(value)) return value.get();
817
+ if (isChildNode(value)) return [value];
818
+ return [new Text(getString$1(value))];
747
819
  }
748
820
  function removeNodes(nodes) {
749
- sanitizeNodes(nodes);
750
- const { length } = nodes;
751
- for (let index = 0; index < length; index += 1) {
752
- nodes[index].remove();
753
- }
821
+ const { length } = nodes;
822
+ for (let index = 0; index < length; index += 1) nodes[index].remove();
754
823
  }
755
824
  function replaceNodes(from, to) {
756
- from[0]?.replaceWith(...to);
757
- const { length } = from;
758
- for (let index = 1; index < length; index += 1) {
759
- from[index].remove();
760
- }
761
- }
762
- function sanitizeNodes(nodes) {
763
- const { length } = nodes;
764
- for (let index = 0; index < length; index += 1) {
765
- const node = nodes[index];
766
- if (isHTMLOrSVGElement(node)) {
767
- removeEvents(node);
768
- }
769
- if (node.hasChildNodes()) {
770
- sanitizeNodes([...node.childNodes]);
771
- }
772
- }
773
- }
774
-
825
+ from[0]?.replaceWith(...to);
826
+ const { length } = from;
827
+ for (let index = 1; index < length; index += 1) from[index].remove();
828
+ }
829
+ function getBoolean(value, defaultValue) {
830
+ return typeof value === "boolean" ? value : defaultValue ?? false;
831
+ }
832
+ function addDelegatedHandler(doc, type, name, passive) {
833
+ if (DELEGATED.has(name)) return;
834
+ DELEGATED.add(name);
835
+ doc.addEventListener(type, passive ? HANDLER_PASSIVE : HANDLER_ACTIVE, { passive });
836
+ }
837
+ function addDelegatedListener(target, type, name, listener, passive) {
838
+ target[name] ??= /* @__PURE__ */ new Set();
839
+ target[name].add(listener);
840
+ addDelegatedHandler(document, type, name, passive);
841
+ return () => {
842
+ removeDelegatedListener(target, name, listener);
843
+ };
844
+ }
845
+ function delegatedEventHandler(event) {
846
+ const key = `${EVENT_PREFIX}${event.type}${this ? EVENT_SUFFIX_PASSIVE : EVENT_SUFFIX_ACTIVE}`;
847
+ const items = event.composedPath();
848
+ const { length } = items;
849
+ let target = items[0];
850
+ Object.defineProperties(event, {
851
+ currentTarget: {
852
+ configurable: true,
853
+ get() {
854
+ return target;
855
+ }
856
+ },
857
+ target: {
858
+ configurable: true,
859
+ value: target
860
+ }
861
+ });
862
+ for (let index = 0; index < length; index += 1) {
863
+ const item = items[index];
864
+ const listeners = item[key];
865
+ if (item.disabled || listeners == null) continue;
866
+ target = item;
867
+ for (const listener of listeners) {
868
+ listener.call(item, event);
869
+ if (event.cancelBubble) return;
870
+ }
871
+ }
872
+ }
873
+ function getDelegatedName(target, type, options) {
874
+ if (isEventTarget(target) && EVENT_TYPES.has(type) && !options.capture && !options.once && options.signal == null) return `${EVENT_PREFIX}${type}${options.passive ? EVENT_SUFFIX_PASSIVE : EVENT_SUFFIX_ACTIVE}`;
875
+ }
876
+ function removeDelegatedListener(target, name, listener) {
877
+ const handlers = target[name];
878
+ if (handlers == null || !handlers.has(listener)) return false;
879
+ handlers.delete(listener);
880
+ if (handlers.size === 0) target[name] = void 0;
881
+ return true;
882
+ }
883
+ var DELEGATED = /* @__PURE__ */ new Set();
884
+ var EVENT_PREFIX = "@";
885
+ var EVENT_SUFFIX_ACTIVE = ":active";
886
+ var EVENT_SUFFIX_PASSIVE = ":passive";
887
+ var EVENT_TYPES = new Set([
888
+ "beforeinput",
889
+ "click",
890
+ "dblclick",
891
+ "contextmenu",
892
+ "focusin",
893
+ "focusout",
894
+ "input",
895
+ "keydown",
896
+ "keyup",
897
+ "mousedown",
898
+ "mousemove",
899
+ "mouseout",
900
+ "mouseover",
901
+ "mouseup",
902
+ "pointerdown",
903
+ "pointermove",
904
+ "pointerout",
905
+ "pointerover",
906
+ "pointerup",
907
+ "touchend",
908
+ "touchmove",
909
+ "touchstart"
910
+ ]);
911
+ var HANDLER_ACTIVE = delegatedEventHandler.bind(false);
912
+ var HANDLER_PASSIVE = delegatedEventHandler.bind(true);
913
+ function noop() {}
914
+ function calculate() {
915
+ return new Promise((resolve) => {
916
+ const values = [];
917
+ let last;
918
+ function step(now) {
919
+ if (last != null) values.push(now - last);
920
+ last = now;
921
+ if (values.length >= CALCULATION_TOTAL) resolve(values.sort().slice(CALCULATION_TRIM_PART, -CALCULATION_TRIM_PART).reduce((first, second) => first + second, 0) / (values.length - CALCULATION_TRIM_TOTAL));
922
+ else requestAnimationFrame(step);
923
+ }
924
+ requestAnimationFrame(step);
925
+ });
926
+ }
927
+ var CALCULATION_TOTAL = 10;
928
+ var CALCULATION_TRIM_PART = 2;
929
+ var CALCULATION_TRIM_TOTAL = 4;
930
+ calculate().then((value) => {});
931
+ function createEventOptions(options) {
932
+ return {
933
+ capture: getBoolean(options?.capture),
934
+ once: getBoolean(options?.once),
935
+ passive: getBoolean(options?.passive, true),
936
+ signal: options?.signal instanceof AbortSignal ? options.signal : void 0
937
+ };
938
+ }
939
+ function on(target, type, listener, options) {
940
+ if (!isEventTarget(target) || typeof type !== "string" || typeof listener !== "function") return noop;
941
+ const extended = createEventOptions(options);
942
+ const delegated = getDelegatedName(target, type, extended);
943
+ if (delegated != null) return addDelegatedListener(target, type, delegated, listener, extended.passive);
944
+ target.addEventListener(type, listener, extended);
945
+ if (extended.once) return noop;
946
+ return () => {
947
+ target.removeEventListener(type, listener, extended);
948
+ };
949
+ }
950
+ function getOptions(options) {
951
+ const parts = options.split(":");
952
+ return {
953
+ capture: parts.some((part) => EXPRESSION_EVENT_OPTIONS_CAPTURE.test(part)),
954
+ once: parts.some((part) => EXPRESSION_EVENT_OPTIONS_ONCE.test(part)),
955
+ passive: !parts.some((part) => EXPRESSION_EVENT_OPTIONS_ACTIVE.test(part))
956
+ };
957
+ }
958
+ function getType(element, type) {
959
+ if (type !== "on") return type;
960
+ if (element instanceof HTMLInputElement) {
961
+ if (EXPRESSION_EVENT_CHANGE_TYPES.test(element.type)) return "change";
962
+ return element.type === "submit" ? "submit" : "input";
963
+ }
964
+ return EVENT_DEFAULTS[element.tagName] ?? type;
965
+ }
966
+ function mapEvent(element, name, value) {
967
+ const [, type, options] = EXPRESSION_EVENT_NAME.exec(name) ?? [];
968
+ if (type != null && typeof value === "function") on(element, getType(element, type), value, getOptions(options ?? ""));
969
+ }
970
+ function isBooleanAttribute(first) {
971
+ return _isBooleanAttribute(first, true);
972
+ }
973
+ function getCallback(element, name) {
974
+ if (isBooleanAttribute(name) && name in element) return name === "checked" ? updateChecked : updateProperty;
975
+ return name === "value" ? updateValue : setAttribute$1;
976
+ }
775
977
  function setAttribute(data, element, name, value) {
776
- element.removeAttribute(name);
777
- switch (true) {
778
- case EXPRESSION_ATTRIBUTE_CLASS.test(name):
779
- setClasses(data, element, name, value);
780
- return;
781
- case EXPRESSION_ATTRIBUTE_STYLE_PREFIX.test(name):
782
- setStyle(data, element, name, value);
783
- return;
784
- default:
785
- setValue(data, element, name, value);
786
- break;
787
- }
978
+ switch (true) {
979
+ case EXPRESSION_ATTRIBUTE_CLASS.test(name):
980
+ setClasses(data, element, name, value);
981
+ return;
982
+ case EXPRESSION_ATTRIBUTE_STYLE_PREFIX.test(name):
983
+ setStyle(data, element, name, value);
984
+ return;
985
+ default:
986
+ setValue(data, element, name, value);
987
+ break;
988
+ }
788
989
  }
789
990
  function setClasses(data, element, name, value) {
790
- function update(value) {
791
- if (value === true) {
792
- element.classList.add(...classes);
793
- }
794
- else {
795
- element.classList.remove(...classes);
796
- }
797
- }
798
- const classes = name.slice(ATTRIBUTE_CLASS_PREFIX_LENGTH).split('.');
799
- if (isReactive(value)) {
800
- data.mora.subscribers.add(value.subscribe(update));
801
- }
802
- else {
803
- update(value);
804
- }
991
+ function update(value$1) {
992
+ if (value$1 === true) element.classList.add(...classes);
993
+ else element.classList.remove(...classes);
994
+ }
995
+ const classes = name.slice(ATTRIBUTE_CLASS_PREFIX_LENGTH).split(".");
996
+ if (isReactive(value)) data.mora.subscribers.add(value.subscribe(update));
997
+ else update(value);
805
998
  }
806
999
  function setStyle(data, element, name, value) {
807
- const [, property, unit] = EXPRESSION_ATTRIBUTE_STYLE_FULL.exec(name) ?? [];
808
- if (property == null) {
809
- return;
810
- }
811
- function update(value) {
812
- if (value == null || value === false || (value === true && unit == null)) {
813
- element.style.removeProperty(property);
814
- }
815
- else {
816
- element.style.setProperty(property, value === true ? unit : getString(value));
817
- }
818
- }
819
- if (isReactive(value)) {
820
- data.mora.subscribers.add(value.subscribe(update));
821
- }
822
- else {
823
- update(value);
824
- }
1000
+ const [, property, unit] = EXPRESSION_ATTRIBUTE_STYLE_FULL.exec(name) ?? [];
1001
+ if (property == null) return;
1002
+ function update(value$1) {
1003
+ if (value$1 == null || value$1 === false || value$1 === true && unit == null) element.style.removeProperty(property);
1004
+ else element.style.setProperty(property, value$1 === true ? unit : String(value$1));
1005
+ }
1006
+ if (isReactive(value)) data.mora.subscribers.add(value.subscribe(update));
1007
+ else update(value);
825
1008
  }
826
1009
  function setValue(data, element, name, value) {
827
- let callback;
828
- if (isBooleanAttribute(name) && name in element) {
829
- callback = name === 'selected' ? updateSelected : updateProperty;
830
- }
831
- else {
832
- callback = setAttribute$1;
833
- }
834
- if (isReactive(value)) {
835
- data.mora.subscribers.add(value.subscribe(next => {
836
- callback(element, name, next);
837
- }));
838
- }
839
- else {
840
- callback(element, name, value);
841
- }
1010
+ const callback = getCallback(element, name);
1011
+ if (isReactive(value)) data.mora.subscribers.add(value.subscribe((next) => {
1012
+ callback(element, name, next);
1013
+ }));
1014
+ else callback(element, name, value);
1015
+ }
1016
+ function updateChecked(element, name, value) {
1017
+ updateElement("change", "checked", element, name, value, value === true);
1018
+ }
1019
+ function updateElement(event, property, element, name, value, next) {
1020
+ if (!(property in element) || element[property] === next) return;
1021
+ setAttribute$1(element, name, value);
1022
+ element[property] = next;
1023
+ element.dispatchEvent(new Event(event, { bubbles: true }));
842
1024
  }
843
1025
  function updateProperty(element, name, value) {
844
- element[name] = value === true;
1026
+ setProperty(element, name, value === true);
845
1027
  }
846
- function updateSelected(element, name, value) {
847
- const select = element.closest('select');
848
- const options = [...(select?.options ?? [])];
849
- if (select != null && options.includes(element)) {
850
- select.dispatchEvent(new Event('change', { bubbles: true }));
851
- }
852
- updateProperty(element, name, value);
1028
+ function updateValue(element, name, value) {
1029
+ updateElement(element instanceof HTMLSelectElement ? "change" : "input", "value", element, name, value, String(value));
853
1030
  }
854
-
855
1031
  function getValue(data, original) {
856
- const matches = EXPRESSION_COMMENT_FULL.exec(original ?? '');
857
- return matches == null ? original : data.values[+matches[1]];
1032
+ const matches = EXPRESSION_ABYDON_CONTENT.exec(original ?? "");
1033
+ return matches == null ? original : data.values[+matches[1]];
858
1034
  }
859
1035
  function mapAttributes(data, element) {
860
- const attributes = [...element.attributes];
861
- const { length } = attributes;
862
- for (let index = 0; index < length; index += 1) {
863
- const { name, value } = attributes[index];
864
- const actual = getValue(data, value);
865
- switch (true) {
866
- case name.startsWith('@'):
867
- mapEvent(element, name, actual);
868
- break;
869
- case name.includes('.') ||
870
- typeof actual === 'function' ||
871
- isReactive(actual):
872
- mapValue$1(data, element, name, actual);
873
- break;
874
- case isBooleanAttribute(name):
875
- setProperty(element, name, value);
876
- break;
877
- }
878
- }
1036
+ const attributes = [...element.attributes];
1037
+ const { length } = attributes;
1038
+ for (let index = 0; index < length; index += 1) {
1039
+ const { name, value } = attributes[index];
1040
+ const actualName = name.replace(EXPRESSION_ABYDON_ATTRIBUTE_PREFIX, "");
1041
+ const actualValue = getValue(data, value);
1042
+ if (actualName !== name) element.removeAttribute(name);
1043
+ switch (true) {
1044
+ case EXPRESSION_EVENT_PREFIX.test(actualName):
1045
+ mapEvent(element, actualName, actualValue);
1046
+ break;
1047
+ case EXPRESSION_PERIOD.test(actualName):
1048
+ case typeof actualValue === "function":
1049
+ case isReactive(actualValue):
1050
+ mapValue$1(data, element, actualName, actualValue);
1051
+ break;
1052
+ default: break;
1053
+ }
1054
+ }
879
1055
  }
880
1056
  function mapValue$1(data, element, name, value) {
881
- if (typeof value === 'function') {
882
- setComputedAttribute(data, element, name, value);
883
- }
884
- else {
885
- setAttribute(data, element, name, value);
886
- }
1057
+ if (typeof value === "function") setComputedAttribute(data, element, name, value);
1058
+ else setAttribute(data, element, name, value);
887
1059
  }
888
1060
  function setComputedAttribute(data, element, name, callback) {
889
- const value = computed(callback);
890
- data.mora.values.add(value);
891
- setAttribute(data, element, name, value);
1061
+ const value = computed(callback);
1062
+ data.mora.values.add(value);
1063
+ setAttribute(data, element, name, value);
892
1064
  }
893
-
894
- //
895
1065
  function addToArray(identifiers, items, nodes, added) {
896
- let position = nodes[0];
897
- const before = added && !identifiers.previous.includes(items.templates[0].identifier);
898
- const next = items.next.flatMap(fragment => fragment.get().flatMap(node => ({
899
- identifier: fragment.identifier,
900
- value: node,
901
- })));
902
- const { length } = next;
903
- for (let index = 0; index < length; index += 1) {
904
- const node = next[index];
905
- if (!(added && identifiers.previous.includes(node.identifier))) {
906
- if (index === 0 && before) {
907
- position.before(node.value);
908
- }
909
- else {
910
- position.after(node.value);
911
- }
912
- }
913
- position = node.value;
914
- }
1066
+ let position = nodes[0];
1067
+ const before = added && !identifiers.previous.has(items.templates[0].identifier);
1068
+ const next = items.next.flatMap((fragment) => fragment.get().flatMap((node) => ({
1069
+ identifier: fragment.identifier,
1070
+ value: node
1071
+ })));
1072
+ const { length } = next;
1073
+ for (let index = 0; index < length; index += 1) {
1074
+ const node = next[index];
1075
+ if (!(added && identifiers.previous.has(node.identifier))) if (index === 0 && before) position.before(node.value);
1076
+ else position.after(node.value);
1077
+ position = node.value;
1078
+ }
915
1079
  }
916
1080
  function handleArray(identifiers, items, nodes) {
917
- const next = items.templates.map(template => items.fragments?.find(fragment => fragment.identifier === template.identifier) ?? template);
918
- const comparison = compareArrays(items.fragments ?? [], items.templates);
919
- if (comparison !== 'removed') {
920
- addToArray(identifiers, { ...items, next }, nodes, comparison === 'added');
921
- }
922
- const toRemove = items.fragments?.filter(fragment => !identifiers.next.includes(fragment.identifier)) ?? [];
923
- const { length } = toRemove;
924
- for (let index = 0; index < length; index += 1) {
925
- toRemove[index].remove();
926
- }
927
- return {
928
- fragments: next,
929
- nodes: next.flatMap(fragment => fragment.get()),
930
- };
931
- }
932
- function removeFragments(fragments) {
933
- if (fragments != null) {
934
- const { length } = fragments;
935
- for (let index = 0; index < length; index += 1) {
936
- fragments[index].remove();
937
- }
938
- }
1081
+ const next = items.templates.map((template) => items.fragments?.find((fragment) => fragment.identifier === template.identifier) ?? template);
1082
+ const comparison = compareArrays(items.fragments ?? [], items.templates);
1083
+ if (comparison !== "removed") addToArray(identifiers, {
1084
+ ...items,
1085
+ next
1086
+ }, nodes, comparison === "added");
1087
+ const toRemove = items.fragments?.filter((fragment) => !identifiers.next.has(fragment.identifier)) ?? [];
1088
+ const { length } = toRemove;
1089
+ for (let index = 0; index < length; index += 1) toRemove[index].remove();
1090
+ return {
1091
+ fragments: next,
1092
+ nodes: next.flatMap((fragment) => fragment.get())
1093
+ };
1094
+ }
1095
+ function removeFragments(fragments$1) {
1096
+ if (fragments$1 != null) {
1097
+ const { length } = fragments$1;
1098
+ for (let index = 0; index < length; index += 1) fragments$1[index].remove();
1099
+ }
939
1100
  }
940
1101
  function replaceText(item, comment, isNullable) {
941
- let to;
942
- if (isNullable) {
943
- to = [comment];
944
- }
945
- else {
946
- to = item.text == null ? [] : [item.text];
947
- }
948
- replaceNodes(item.nodes ?? [], to);
1102
+ let to;
1103
+ if (isNullable) to = [comment];
1104
+ else to = item.text == null ? [] : [item.text];
1105
+ replaceNodes(item.nodes ?? [], to);
949
1106
  }
950
1107
  function setArray(item, comment, value) {
951
- if (value.length === 0) {
952
- return {
953
- nodes: setText(item, comment, value),
954
- };
955
- }
956
- let templates = value.filter(item => isFragment(item) && item.identifier != null);
957
- const next = templates.map(fragment => fragment.identifier);
958
- const previous = item.fragments?.map(fragment => fragment.identifier) ?? [];
959
- if (new Set(next).size !== templates.length) {
960
- templates = [];
961
- }
962
- const noTemplates = templates.length === 0;
963
- if (noTemplates ||
964
- item.nodes == null ||
965
- previous.some(identifier => identifier == null)) {
966
- return {
967
- fragments: noTemplates ? undefined : templates,
968
- nodes: setNodes(item, comment, noTemplates
969
- ? value.flatMap(item => createNodes(item))
970
- : templates.flatMap(template => template.get())),
971
- };
972
- }
973
- return handleArray({
974
- next,
975
- previous,
976
- }, {
977
- templates,
978
- fragments: item.fragments ?? [],
979
- }, item.nodes);
1108
+ if (value.length === 0) return { nodes: setText(item, comment, value) };
1109
+ let templates$1 = value.filter((item$1) => isFragment(item$1) && item$1.identifier != null);
1110
+ const next = templates$1.map((fragment) => fragment.identifier);
1111
+ const previous = item.fragments?.map((fragment) => fragment.identifier) ?? [];
1112
+ if (new Set(next).size !== templates$1.length) templates$1 = [];
1113
+ const noTemplates = templates$1.length === 0;
1114
+ if (noTemplates || item.nodes == null || previous.some((identifier) => identifier == null)) return {
1115
+ fragments: noTemplates ? void 0 : templates$1,
1116
+ nodes: setNodes(item, comment, noTemplates ? value.flatMap((item$1) => createNodes(item$1)) : templates$1.flatMap((template) => template.get()))
1117
+ };
1118
+ return handleArray({
1119
+ next: new Set(next),
1120
+ previous: new Set(previous)
1121
+ }, {
1122
+ templates: templates$1,
1123
+ fragments: item.fragments ?? []
1124
+ }, item.nodes);
980
1125
  }
981
1126
  function setNodes(item, comment, next) {
982
- if (item.nodes == null) {
983
- if (comment.parentNode != null) {
984
- replaceNodes([comment], next);
985
- }
986
- else if (item.text?.parentNode != null) {
987
- replaceNodes([item.text], next);
988
- }
989
- }
990
- else {
991
- replaceNodes(item.nodes, next);
992
- }
993
- removeFragments(item.fragments);
994
- return next;
1127
+ if (item.nodes == null) {
1128
+ if (comment.parentNode != null) replaceNodes([comment], next);
1129
+ else if (item.text?.parentNode != null) replaceNodes([item.text], next);
1130
+ } else replaceNodes(item.nodes, next);
1131
+ removeFragments(item.fragments);
1132
+ return next;
995
1133
  }
996
1134
  function setReactiveValue(data, comment, reactive) {
997
- let item = data.items.find(item => item.nodes?.includes(comment));
998
- item ??= {};
999
- item.text = new Text();
1000
- data.mora.subscribers.add(reactive.subscribe(value => {
1001
- if (Array.isArray(value)) {
1002
- setReactiveValueForArray(item, comment, value);
1003
- }
1004
- else {
1005
- setReactiveValueForSingle(item, comment, value);
1006
- }
1007
- item.nodes = [...(item.nodes ?? [comment])];
1008
- }));
1135
+ let item = data.items.find((item$1) => item$1.nodes?.includes(comment));
1136
+ item ??= {};
1137
+ item.text = new Text();
1138
+ data.mora.subscribers.add(reactive.subscribe((value) => {
1139
+ if (Array.isArray(value)) setReactiveValueForArray(item, comment, value);
1140
+ else setReactiveValueForSingle(item, comment, value);
1141
+ item.nodes = [...item.nodes ?? [comment]];
1142
+ }));
1009
1143
  }
1010
1144
  function setReactiveValueForArray(item, comment, value) {
1011
- const result = setArray(item, comment, value);
1012
- item.fragments = typeof result === 'boolean' ? undefined : result?.fragments;
1013
- if (typeof result === 'boolean') {
1014
- if (result) {
1015
- item.nodes = item.text == null ? [] : [item.text];
1016
- }
1017
- else {
1018
- item.nodes = undefined;
1019
- }
1020
- }
1021
- else {
1022
- item.nodes = result?.nodes;
1023
- }
1145
+ const result = setArray(item, comment, value);
1146
+ item.fragments = typeof result === "boolean" ? void 0 : result?.fragments;
1147
+ if (typeof result === "boolean") if (result) item.nodes = item.text == null ? [] : [item.text];
1148
+ else item.nodes = void 0;
1149
+ else item.nodes = result?.nodes;
1024
1150
  }
1025
1151
  function setReactiveValueForSingle(item, comment, value) {
1026
- const valueIsFragment = isFragment(value);
1027
- item.fragments = valueIsFragment ? [value] : undefined;
1028
- if (valueIsFragment || isChildNode(value)) {
1029
- item.nodes = setNodes(item, comment, createNodes(value));
1030
- }
1031
- else {
1032
- item.nodes = setText(item, comment, value);
1033
- }
1152
+ const valueIsFragment = isFragment(value);
1153
+ item.fragments = valueIsFragment ? [value] : void 0;
1154
+ if (valueIsFragment || isChildNode(value)) item.nodes = setNodes(item, comment, createNodes(value));
1155
+ else item.nodes = setText(item, comment, value);
1034
1156
  }
1035
1157
  function setText(item, comment, value) {
1036
- const isNullable = isNullableOrWhitespace(value);
1037
- if (item.text != null) {
1038
- item.text.textContent = isNullable ? '' : getString(value);
1039
- }
1040
- let result = false;
1041
- if (item.nodes != null) {
1042
- replaceText(item, comment, isNullable);
1043
- result = !isNullable;
1044
- }
1045
- else if (isNullable && comment.parentNode == null) {
1046
- item.text?.replaceWith(comment);
1047
- }
1048
- else if (!isNullable && item?.text?.parentNode == null) {
1049
- if (item.text != null) {
1050
- comment.replaceWith(item.text);
1051
- }
1052
- result = true;
1053
- }
1054
- removeFragments(item.fragments);
1055
- if (result) {
1056
- return item.text == null ? [] : [item.text];
1057
- }
1058
- }
1059
-
1158
+ const isNullable = isNullableOrWhitespace(value);
1159
+ if (item.text != null) item.text.textContent = isNullable ? "" : getString$1(value);
1160
+ let result = false;
1161
+ if (item.nodes != null) {
1162
+ replaceText(item, comment, isNullable);
1163
+ result = !isNullable;
1164
+ } else if (isNullable && comment.parentNode == null) item.text?.replaceWith(comment);
1165
+ else if (!isNullable && item?.text?.parentNode == null) {
1166
+ if (item.text != null) comment.replaceWith(item.text);
1167
+ result = true;
1168
+ }
1169
+ removeFragments(item.fragments);
1170
+ if (result) return item.text == null ? [] : [item.text];
1171
+ }
1060
1172
  function mapNode(data, comment) {
1061
- const matches = EXPRESSION_COMMENT_CONTENT.exec(comment.textContent ?? '');
1062
- const value = matches == null ? null : data.values[+matches[1]];
1063
- if (value != null) {
1064
- mapValue(data, comment, value);
1065
- }
1173
+ const matches = EXPRESSION_ABYDON_CONTENT.exec(comment.textContent ?? "");
1174
+ const value = matches == null ? null : data.values[+matches[1]];
1175
+ if (value != null) mapValue(data, comment, value);
1066
1176
  }
1067
1177
  function mapNodes(data, nodes) {
1068
- const { length } = nodes;
1069
- for (let index = 0; index < length; index += 1) {
1070
- const node = nodes[index];
1071
- if (node instanceof Comment) {
1072
- mapNode(data, node);
1073
- continue;
1074
- }
1075
- if (isHTMLOrSVGElement(node)) {
1076
- mapAttributes(data, node);
1077
- }
1078
- if (node.hasChildNodes()) {
1079
- mapNodes(data, [...node.childNodes]);
1080
- }
1081
- }
1178
+ const { length } = nodes;
1179
+ for (let index = 0; index < length; index += 1) {
1180
+ const node = nodes[index];
1181
+ if (node instanceof Comment) {
1182
+ mapNode(data, node);
1183
+ continue;
1184
+ }
1185
+ if (isHTMLOrSVGElement(node)) mapAttributes(data, node);
1186
+ if (node.hasChildNodes()) mapNodes(data, [...node.childNodes]);
1187
+ }
1082
1188
  }
1083
1189
  function mapValue(data, comment, value) {
1084
- switch (true) {
1085
- case typeof value === 'function':
1086
- setComputedValue(data, comment, value);
1087
- break;
1088
- case isFragments(value):
1089
- handleFragments(value, false);
1090
- setReactiveValue(data, comment, value.items);
1091
- break;
1092
- case isReactive(value):
1093
- setReactiveValue(data, comment, value);
1094
- break;
1095
- default:
1096
- replaceComment(data, comment, value);
1097
- break;
1098
- }
1190
+ switch (true) {
1191
+ case typeof value === "function":
1192
+ setComputedValue(data, comment, value);
1193
+ break;
1194
+ case isFragments(value):
1195
+ handleFragments(value, false);
1196
+ setReactiveValue(data, comment, value.items);
1197
+ break;
1198
+ case isReactive(value):
1199
+ setReactiveValue(data, comment, value);
1200
+ break;
1201
+ default:
1202
+ replaceComment(data, comment, value);
1203
+ break;
1204
+ }
1099
1205
  }
1100
1206
  function replaceComment(data, comment, value) {
1101
- const item = data.items.find(item => item.nodes?.includes(comment));
1102
- const nodes = createNodes(value);
1103
- if (item != null) {
1104
- item.fragments = isFragment(value) ? [value] : undefined;
1105
- item.nodes = nodes;
1106
- }
1107
- comment.replaceWith(...nodes);
1207
+ const item = data.items.find((item$1) => item$1.nodes?.includes(comment));
1208
+ const nodes = createNodes(value);
1209
+ if (item != null) {
1210
+ item.fragments = isFragment(value) ? [value] : void 0;
1211
+ item.nodes = nodes;
1212
+ }
1213
+ comment.replaceWith(...nodes);
1108
1214
  }
1109
1215
  function setComputedValue(data, comment, callback) {
1110
- const value = computed(callback);
1111
- data.mora.values.add(value);
1112
- setReactiveValue(data, comment, value);
1216
+ const value = computed(callback);
1217
+ data.mora.values.add(value);
1218
+ setReactiveValue(data, comment, value);
1113
1219
  }
1114
-
1115
1220
  function handleExpression(data, prefix, expression) {
1116
- if (Array.isArray(expression)) {
1117
- const { length } = expression;
1118
- let expressions = '';
1119
- for (let index = 0; index < length; index += 1) {
1120
- expressions += handleExpression(data, '', expression[index]);
1121
- }
1122
- return `${prefix}${expressions}`;
1123
- }
1124
- if (typeof expression === 'function' ||
1125
- (typeof expression === 'object' && expression != null)) {
1126
- const index = data.values.push(expression) - 1;
1127
- return `${prefix}<!--abydon.${index}-->`;
1128
- }
1129
- return isNullableOrWhitespace(expression) ? prefix : `${prefix}${expression}`;
1221
+ if (Array.isArray(expression)) {
1222
+ const { length } = expression;
1223
+ let expressions = "";
1224
+ for (let index = 0; index < length; index += 1) expressions += handleExpression(data, "", expression[index]);
1225
+ return `${prefix}${expressions}`;
1226
+ }
1227
+ if (typeof expression === "function" || typeof expression === "object" && expression != null) return transformExpression(prefix, data.values.push(expression) - 1);
1228
+ return isNullableOrWhitespace(expression) ? prefix : `${prefix}${expression}`;
1130
1229
  }
1131
1230
  function parse(data) {
1132
- if (data.template != null) {
1133
- return data.template;
1134
- }
1135
- const { length } = data.strings;
1136
- data.template = '';
1137
- for (let index = 0; index < length; index += 1) {
1138
- data.template += handleExpression(data, data.strings[index], data.expressions[index]);
1139
- }
1140
- data.expressions = [];
1141
- data.strings = [];
1142
- return data.template;
1143
- }
1144
-
1145
- class Fragment {
1146
- #data;
1147
- #configuration = {
1148
- identifier: undefined,
1149
- ignoreCache: false,
1150
- };
1151
- /**
1152
- * Fragment identifier
1153
- */
1154
- get identifier() {
1155
- return this.#configuration.identifier;
1156
- }
1157
- constructor(strings, expressions) {
1158
- Object.defineProperty(this, '$fragment', {
1159
- value: true,
1160
- });
1161
- this.#data = {
1162
- expressions,
1163
- strings,
1164
- items: [],
1165
- mora: {
1166
- subscribers: new Set(),
1167
- values: new Set(),
1168
- },
1169
- values: [],
1170
- };
1171
- }
1172
- /**
1173
- * Append the fragment to the given element
1174
- * @param element Element to append to
1175
- */
1176
- appendTo(element) {
1177
- element.append(...this.get());
1178
- }
1179
- /**
1180
- * Configure the fragment
1181
- * @param configuration Configuration options
1182
- * @returns Fragment
1183
- */
1184
- configure(configuration) {
1185
- const actual = isPlainObject(configuration) ? configuration : {};
1186
- if (actual.identifier !== undefined) {
1187
- this.#configuration.identifier = actual.identifier;
1188
- }
1189
- if (typeof actual.ignoreCache === 'boolean') {
1190
- this.#configuration.ignoreCache = actual.ignoreCache;
1191
- }
1192
- return this;
1193
- }
1194
- /**
1195
- * Get a list of the fragment's nodes
1196
- * @returns List of nodes
1197
- */
1198
- get() {
1199
- const data = this.#data;
1200
- if (data.items.length === 0) {
1201
- const parsed = parse(data);
1202
- const templated = html$1(parsed, {
1203
- ignoreCache: this.#configuration.ignoreCache,
1204
- sanitizeBooleanAttributes: false,
1205
- });
1206
- data.items.splice(0, data.items.length, ...templated.map(node => ({
1207
- nodes: [node],
1208
- })));
1209
- mapNodes(data, data.items.flatMap(item => item.fragments?.flatMap(fragment => fragment.get()) ??
1210
- item.nodes ??
1211
- []));
1212
- }
1213
- return [
1214
- ...data.items.flatMap(item => item.fragments?.flatMap(fragment => fragment.get()) ??
1215
- item.nodes ??
1216
- []),
1217
- ];
1218
- }
1219
- /**
1220
- * Set an identifier for the fragment
1221
- *
1222
- * _An identifier can be used to uniquely identify a fragment,
1223
- * which helps prevent re-rendering in certain scenarios._
1224
- * @param identifier Identifier
1225
- * @returns Fragment
1226
- */
1227
- identify(identifier) {
1228
- this.#configuration.identifier = identifier;
1229
- return this;
1230
- }
1231
- /**
1232
- * Remove the fragment from the DOM
1233
- */
1234
- remove() {
1235
- removeFragment(this.#data);
1236
- }
1237
- }
1231
+ if (data.template != null) return data.template;
1232
+ const { length } = data.strings;
1233
+ data.template = "";
1234
+ for (let index = 0; index < length; index += 1) data.template += handleExpression(data, data.strings[index], data.expressions[index]);
1235
+ data.template = data.template.replaceAll(EXPRESSION_ABYDON_ATTRIBUTE_FULL, transformAttribute);
1236
+ data.expressions = [];
1237
+ data.strings = [];
1238
+ return data.template;
1239
+ }
1240
+ function transformAttribute(_, name, index) {
1241
+ return `_${name}="@abydon.${index}@"`;
1242
+ }
1243
+ function transformExpression(prefix, index) {
1244
+ return `${prefix}<!--abydon.${index}-->`;
1245
+ }
1246
+ var Fragment = class {
1247
+ #data;
1248
+ #configuration = {
1249
+ identifier: void 0,
1250
+ cache: true
1251
+ };
1252
+ get identifier() {
1253
+ return this.#configuration.identifier;
1254
+ }
1255
+ constructor(strings, expressions) {
1256
+ Object.defineProperty(this, NAME_FRAGMENT, { value: true });
1257
+ this.#data = {
1258
+ expressions,
1259
+ strings,
1260
+ items: [],
1261
+ mora: {
1262
+ subscribers: /* @__PURE__ */ new Set(),
1263
+ values: /* @__PURE__ */ new Set()
1264
+ },
1265
+ values: []
1266
+ };
1267
+ }
1268
+ appendTo(element) {
1269
+ element.append(...this.get());
1270
+ }
1271
+ configure(configuration) {
1272
+ const actual = isPlainObject$1(configuration) ? configuration : {};
1273
+ if ("identifier" in actual) this.#configuration.identifier = actual.identifier;
1274
+ if (typeof actual.cache === "boolean") this.#configuration.cache = actual.cache;
1275
+ return this;
1276
+ }
1277
+ get() {
1278
+ const data = this.#data;
1279
+ if (data.items.length === 0) {
1280
+ const templated = html$1(parse(data), { cache: this.#configuration.cache });
1281
+ data.items.splice(0, data.items.length, ...templated.map((node) => ({ nodes: [node] })));
1282
+ mapNodes(data, data.items.flatMap((item) => item.fragments?.flatMap((fragment) => fragment.get()) ?? item.nodes ?? []));
1283
+ }
1284
+ return data.items.flatMap((item) => item.fragments?.flatMap((fragment) => fragment.get()) ?? item.nodes ?? []);
1285
+ }
1286
+ identify(identifier) {
1287
+ this.#configuration.identifier = identifier;
1288
+ return this;
1289
+ }
1290
+ remove() {
1291
+ removeFragment(this.#data);
1292
+ }
1293
+ };
1238
1294
  function removeFragment(data) {
1239
- removeMora(data);
1240
- let { length } = data.items;
1241
- for (let index = 0; index < length; index += 1) {
1242
- const { fragments, nodes } = data.items[index];
1243
- const fragmentsLength = fragments?.length ?? 0;
1244
- for (let fragmentIndex = 0; fragmentIndex < fragmentsLength; fragmentIndex += 1) {
1245
- fragments?.[fragmentIndex]?.remove();
1246
- }
1247
- removeNodes(nodes ?? []);
1248
- }
1249
- data.items.length = 0;
1250
- length = data.values.length;
1251
- for (let index = 0; index < length; index += 1) {
1252
- const value = data.values[index];
1253
- if (isFragments(value)) {
1254
- handleFragments(value, true);
1255
- }
1256
- }
1295
+ removeMora(data);
1296
+ let { length } = data.items;
1297
+ for (let index = 0; index < length; index += 1) {
1298
+ const { fragments: fragments$1, nodes } = data.items[index];
1299
+ const fragmentsLength = fragments$1?.length ?? 0;
1300
+ for (let fragmentIndex = 0; fragmentIndex < fragmentsLength; fragmentIndex += 1) fragments$1?.[fragmentIndex]?.remove();
1301
+ removeNodes(nodes ?? []);
1302
+ }
1303
+ data.items.length = 0;
1304
+ length = data.values.length;
1305
+ for (let index = 0; index < length; index += 1) {
1306
+ const value = data.values[index];
1307
+ if (isFragments(value)) handleFragments(value, true);
1308
+ }
1257
1309
  }
1258
1310
  function removeMora(data) {
1259
- const unsubscribers = [...data.mora.subscribers];
1260
- data.mora.subscribers.clear();
1261
- data.mora.values.clear();
1262
- for (const unsubscribe of unsubscribers) {
1263
- unsubscribe();
1264
- }
1311
+ const unsubscribers = [...data.mora.subscribers];
1312
+ data.mora.subscribers.clear();
1313
+ data.mora.values.clear();
1314
+ for (const unsubscribe$1 of unsubscribers) unsubscribe$1();
1265
1315
  }
1266
-
1267
- function fragments(array, identify, fragment) {
1268
- return new Fragments(array, identify, fragment);
1316
+ function fragments(array$1, identify, fragment) {
1317
+ return new Fragments(array$1, identify, fragment);
1269
1318
  }
1270
- function html(strings, ...values) {
1271
- return new Fragment(strings, values);
1319
+ function html(template, ...values) {
1320
+ return new Fragment(template, values);
1272
1321
  }
1273
-
1274
1322
  export { array, computed, effect, fragments, html, isArray, isComputed, isEffect, isReactive, isSignal, signal, startBatch, stopBatch, store };