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