@oscarpalmer/abydon 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,593 +1,429 @@
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
- ]);
338
+ return new ReactiveArray(Array.isArray(value) ? value : [], options);
339
+ }
340
+ function updateArray(type, array$1, state, length) {
341
+ const affectsLength = METHODS_AFFECTING_LENGTH.has(type);
342
+ const previousArray = affectsLength ? [] : [...array$1];
343
+ const previousLength = array$1.length;
344
+ return (...args) => {
345
+ const result = array$1[type](...args);
346
+ if (affectsLength ? array$1.length !== previousLength : !equalArrays(state, previousArray, array$1)) {
347
+ emitValue(state);
348
+ length.set(array$1.length);
349
+ }
350
+ return result;
351
+ };
352
+ }
353
+ function setAtIndex(array$1, index, value) {
354
+ const actual = index < 0 ? array$1.length + index : index;
355
+ if (actual > -1) array$1[actual] = value;
356
+ }
510
357
 
511
358
  function isKey(value) {
512
- return typeof value === "number" || typeof value === "string";
359
+ return typeof value === "number" || typeof value === "string";
513
360
  }
514
361
  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;
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;
523
366
  }
524
367
 
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
- }
368
+ function getString$1(value) {
369
+ if (typeof value === "string") return value;
370
+ if (value == null) return "";
371
+ if (typeof value !== "object") return String(value);
372
+ const asString = String(value.valueOf?.() ?? value);
373
+ return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
573
374
  }
574
- _keyed = new WeakMap();
375
+
376
+ function isNullableOrWhitespace(value) {
377
+ return value == null || EXPRESSION_WHITESPACE.test(getString$1(value));
378
+ }
379
+ var EXPRESSION_WHITESPACE = /^\s*$/;
380
+
381
+ var Store = class extends Reactive {
382
+ #keyed = /* @__PURE__ */ new Map();
383
+ constructor(value, options) {
384
+ super(NAME_STORE, new Proxy(value, { set: (target, property, value$1) => setValueInProxy({
385
+ target,
386
+ property,
387
+ value: value$1,
388
+ isArray: false,
389
+ state: this.state
390
+ }) }), options);
391
+ }
392
+ get(key) {
393
+ return isKey(key) ? getReactiveValueInProxy(this, this.#keyed, key, false).get() : getValue$1(this.state);
394
+ }
395
+ peek(key) {
396
+ return isKey(key) ? this.state.value[key] : { ...this.state.value };
397
+ }
398
+ set(first, second) {
399
+ if (isKey(first)) this.state.value[first] = second;
400
+ else if (first == null || isPlainObject$1(first)) setProxyValue(this.state.value, first ?? {});
401
+ }
402
+ subscribe(first, second) {
403
+ if (isKey(first) && typeof second === "function") return getReactiveValueInProxy(this, this.#keyed, first, false).subscribe(second);
404
+ return typeof first === "function" ? subscribe(this.state, first) : noop;
405
+ }
406
+ update(callback) {
407
+ const updated = callback({ ...this.state.value });
408
+ if (updated == null || isPlainObject$1(updated)) setProxyValue(this.state.value, updated ?? {});
409
+ }
410
+ };
575
411
  function store(value, options) {
576
- return new Store(isPlainObject$1(value) ? value : {}, options);
412
+ return new Store(isPlainObject$1(value) ? value : {}, options);
577
413
  }
578
414
 
579
415
  function isChildNode(value) {
580
- return value instanceof Node && childNodeTypes.has(value.nodeType);
416
+ return value instanceof Node && CHILD_NODE_TYPES.has(value.nodeType);
581
417
  }
582
418
  function isHTMLOrSVGElement(value) {
583
419
  return value instanceof HTMLElement || value instanceof SVGElement;
584
420
  }
585
- var childNodeTypes = new Set([
586
- 1,
587
- 3,
588
- 7,
589
- 8,
590
- 10
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
591
427
  ]);
592
428
 
593
429
  function getString(value) {
@@ -605,16 +441,11 @@ function isPlainObject(value) {
605
441
  return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
606
442
  }
607
443
 
608
- function isNullableOrWhitespace(value) {
609
- return value == null || whiteSpaceExpression.test(getString(value));
610
- }
611
- var whiteSpaceExpression = /^\s*$/;
612
-
613
444
  function isAttribute(value) {
614
445
  return value instanceof Attr || isPlainObject(value) && typeof value.name === "string" && typeof value.value === "string";
615
446
  }
616
447
  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);
448
+ return validateAttribute((attribute) => attribute == null || EXPRESSION_ON_PREFIX.test(attribute.name) || EXPRESSION_SOURCE_PREFIX.test(attribute.name) && EXPRESSION_VALUE_PREFIX.test(String(attribute.value)), first, second);
618
449
  }
619
450
  function isBooleanAttribute(value) {
620
451
  return validateAttribute((attribute) => attribute != null && booleanAttributes.includes(attribute.name.toLowerCase()), value, "");
@@ -636,13 +467,16 @@ function isProperty(value) {
636
467
  function setAttribute$1(element, first, second) {
637
468
  updateValue(element, first, second, updateAttribute);
638
469
  }
470
+ function setProperty(element, first, second) {
471
+ updateValue(element, first, second, updateProperty$1);
472
+ }
639
473
  function updateAttribute(element, name, value) {
640
- if (booleanAttributes.includes(name.toLowerCase())) updateProperty$1(element, name, value);
474
+ if (booleanAttributes.includes(name.toLowerCase())) updateProperty$1(element, name, value, false);
641
475
  else if (value == null) element.removeAttribute(name);
642
476
  else element.setAttribute(name, typeof value === "string" ? value : getString(value));
643
477
  }
644
478
  function updateProperty$1(element, name, value, validate) {
645
- const actual = name;
479
+ const actual = validate ?? true ? name.toLowerCase() : name;
646
480
  if (actual === "hidden") element.hidden = value === "" || value === true;
647
481
  else element[actual] = value === "" || typeof value === "string" && value.toLowerCase() === actual || value === true;
648
482
  }
@@ -660,6 +494,9 @@ function validateAttribute(callback, first, second) {
660
494
  };
661
495
  return callback(attribute);
662
496
  }
497
+ var EXPRESSION_ON_PREFIX = /^on/i;
498
+ var EXPRESSION_SOURCE_PREFIX = /^(href|src|xlink:href)$/i;
499
+ var EXPRESSION_VALUE_PREFIX = /(data:text\/html|javascript:)/i;
663
500
  const booleanAttributes = Object.freeze([
664
501
  "async",
665
502
  "autofocus",
@@ -686,9 +523,6 @@ const booleanAttributes = Object.freeze([
686
523
  "reversed",
687
524
  "selected"
688
525
  ]);
689
- var onPrefix = /^on/i;
690
- var sourcePrefix = /^(href|src|xlink:href)$/i;
691
- var valuePrefix = /(data:text\/html|javascript:)/i;
692
526
 
693
527
  function getOptions$1(input) {
694
528
  const options = isPlainObject(input) ? input : {};
@@ -696,7 +530,7 @@ function getOptions$1(input) {
696
530
  return options;
697
531
  }
698
532
  function sanitize(value, options) {
699
- return sanitizeNodes(Array.isArray(value) ? value : [value], getOptions$1(options));
533
+ return sanitizeNodes$1(Array.isArray(value) ? value : [value], getOptions$1(options));
700
534
  }
701
535
  function sanitizeAttributes(element, attributes, options) {
702
536
  const { length } = attributes;
@@ -706,13 +540,13 @@ function sanitizeAttributes(element, attributes, options) {
706
540
  else if (options.sanitizeBooleanAttributes && isInvalidBooleanAttribute(attribute)) element.setAttribute(attribute.name, "");
707
541
  }
708
542
  }
709
- function sanitizeNodes(nodes, options) {
543
+ function sanitizeNodes$1(nodes, options) {
710
544
  const actual = nodes.filter((node) => node instanceof Node);
711
545
  const { length } = nodes;
712
546
  for (let index = 0; index < length; index += 1) {
713
547
  const node = actual[index];
714
548
  if (node instanceof Element) sanitizeAttributes(node, [...node.attributes], options);
715
- if (node.hasChildNodes()) sanitizeNodes([...node.childNodes], options);
549
+ if (node.hasChildNodes()) sanitizeNodes$1([...node.childNodes], options);
716
550
  }
717
551
  return nodes;
718
552
  }
@@ -725,15 +559,18 @@ function createTemplate(html$1) {
725
559
  }
726
560
  function getTemplate(value) {
727
561
  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];
562
+ let template = templates[value];
563
+ if (template != null) return template;
564
+ const element = EXPRESSION_ID.test(value) ? document.querySelector(`#${value}`) : null;
565
+ template = element instanceof HTMLTemplateElement ? element : createTemplate(value);
566
+ templates[value] = template;
567
+ return template;
733
568
  }
734
- function html$1(value, sanitization) {
569
+ var html$1 = ((value, sanitization) => {
735
570
  if (typeof value !== "string" && !(value instanceof HTMLTemplateElement)) return [];
736
- const options = sanitization == null || sanitization === true ? {} : isPlainObject(sanitization) ? { ...sanitization } : null;
571
+ let options;
572
+ if (sanitization == null || sanitization === true) options = {};
573
+ else options = sanitization === false ? void 0 : sanitization;
737
574
  const template = value instanceof HTMLTemplateElement ? value : getTemplate(value);
738
575
  if (template == null) return [];
739
576
  const cloned = template.content.cloneNode(true);
@@ -742,18 +579,31 @@ function html$1(value, sanitization) {
742
579
  for (let index = 0; index < length; index += 1) scripts[index].remove();
743
580
  cloned.normalize();
744
581
  return options != null ? sanitize([...cloned.childNodes], options) : [...cloned.childNodes];
745
- }
746
- var idPattern = /^[a-z][\w-]*$/i;
582
+ });
583
+ html$1.clear = () => {
584
+ templates = {};
585
+ };
586
+ html$1.remove = (template) => {
587
+ if (typeof template === "string") templates[template] = void 0;
588
+ };
589
+ var EXPRESSION_ID = /^[a-z][\w-]*$/i;
747
590
  var templates = {};
748
591
 
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';
592
+ const ABORT_CONTROLLERS = new WeakMap();
593
+ const ATTRIBUTE_CLASS_PREFIX_LENGTH = 6;
594
+ const EXPRESSION_ATTRIBUTE_CLASS = /^class\./;
595
+ const EXPRESSION_ATTRIBUTE_STYLE_FULL = /^style\.([\w-]+)(?:\.([\w-]+))?$/;
596
+ const EXPRESSION_ATTRIBUTE_STYLE_PREFIX = /^style\./;
597
+ const EXPRESSION_COMMENT_FULL = /^<!--abydon\.(\d+)-->$/;
598
+ const EXPRESSION_COMMENT_CONTENT = /^abydon\.(\d+)$/;
599
+ const EXPRESSION_EVENT_NAME = /^@([\w-]+)(?::([a-z:]+))?$/i;
600
+ const REASON_EVENT_REMOVED = 'Event removed as element was removed from document by Abydon';
601
+
752
602
  function getController(element) {
753
- let controller = controllers.get(element);
603
+ let controller = ABORT_CONTROLLERS.get(element);
754
604
  if (controller == null) {
755
605
  controller = new AbortController();
756
- controllers.set(element, controller);
606
+ ABORT_CONTROLLERS.set(element, controller);
757
607
  }
758
608
  return controller;
759
609
  }
@@ -762,12 +612,12 @@ function getOptions(options) {
762
612
  return {
763
613
  capture: parts.includes('c') || parts.includes('capture'),
764
614
  once: parts.includes('o') || parts.includes('once'),
765
- passive: !parts.includes('a') && !parts.includes('active'),
615
+ passive: !(parts.includes('a') || parts.includes('active')),
766
616
  };
767
617
  }
768
618
  function mapEvent(element, name, value) {
769
619
  element.removeAttribute(name);
770
- const [, type, options] = eventNamePattern.exec(name) ?? [];
620
+ const [, type, options] = EXPRESSION_EVENT_NAME.exec(name) ?? [];
771
621
  if (typeof value === 'function' && type != null) {
772
622
  element.addEventListener(type, value, {
773
623
  ...getOptions(options ?? ''),
@@ -776,8 +626,8 @@ function mapEvent(element, name, value) {
776
626
  }
777
627
  }
778
628
  function removeEvents(element) {
779
- controllers.get(element)?.abort(reason);
780
- controllers.delete(element);
629
+ ABORT_CONTROLLERS.get(element)?.abort(REASON_EVENT_REMOVED);
630
+ ABORT_CONTROLLERS.delete(element);
781
631
  }
782
632
 
783
633
  function compareArrays(first, second) {
@@ -805,10 +655,10 @@ function createNodes(value) {
805
655
  if (isChildNode(value)) {
806
656
  return [value];
807
657
  }
808
- return [new Text(getString(value))];
658
+ return [new Text(getString$1(value))];
809
659
  }
810
660
  function removeNodes(nodes) {
811
- sanitiseNodes(nodes);
661
+ sanitizeNodes(nodes);
812
662
  const { length } = nodes;
813
663
  for (let index = 0; index < length; index += 1) {
814
664
  nodes[index].remove();
@@ -821,7 +671,7 @@ function replaceNodes(from, to) {
821
671
  from[index].remove();
822
672
  }
823
673
  }
824
- function sanitiseNodes(nodes) {
674
+ function sanitizeNodes(nodes) {
825
675
  const { length } = nodes;
826
676
  for (let index = 0; index < length; index += 1) {
827
677
  const node = nodes[index];
@@ -829,21 +679,18 @@ function sanitiseNodes(nodes) {
829
679
  removeEvents(node);
830
680
  }
831
681
  if (node.hasChildNodes()) {
832
- sanitiseNodes([...node.childNodes]);
682
+ sanitizeNodes([...node.childNodes]);
833
683
  }
834
684
  }
835
685
  }
836
686
 
837
- const classExpression = /^class\./;
838
- const styleFullExpression = /^style\.([\w-]+)(?:\.([\w-]+))?$/;
839
- const stylePrefixExpression = /^style\./;
840
687
  function setAttribute(data, element, name, value) {
841
688
  element.removeAttribute(name);
842
689
  switch (true) {
843
- case classExpression.test(name):
690
+ case EXPRESSION_ATTRIBUTE_CLASS.test(name):
844
691
  setClasses(data, element, name, value);
845
692
  return;
846
- case stylePrefixExpression.test(name):
693
+ case EXPRESSION_ATTRIBUTE_STYLE_PREFIX.test(name):
847
694
  setStyle(data, element, name, value);
848
695
  return;
849
696
  default:
@@ -860,7 +707,7 @@ function setClasses(data, element, name, value) {
860
707
  element.classList.remove(...classes);
861
708
  }
862
709
  }
863
- const classes = name.slice(6).split('.');
710
+ const classes = name.slice(ATTRIBUTE_CLASS_PREFIX_LENGTH).split('.');
864
711
  if (isReactive(value)) {
865
712
  data.mora.subscribers.add(value.subscribe(update));
866
713
  }
@@ -869,30 +716,33 @@ function setClasses(data, element, name, value) {
869
716
  }
870
717
  }
871
718
  function setStyle(data, element, name, value) {
719
+ const [, property, unit] = EXPRESSION_ATTRIBUTE_STYLE_FULL.exec(name) ?? [];
720
+ if (property == null) {
721
+ return;
722
+ }
872
723
  function update(value) {
873
724
  if (value == null || value === false || (value === true && unit == null)) {
874
725
  element.style.removeProperty(property);
875
726
  }
876
727
  else {
877
- element.style.setProperty(property, value === true ? unit : getString(value));
728
+ element.style.setProperty(property, value === true ? unit : getString$1(value));
878
729
  }
879
730
  }
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
- }
731
+ if (isReactive(value)) {
732
+ data.mora.subscribers.add(value.subscribe(update));
733
+ }
734
+ else {
735
+ update(value);
888
736
  }
889
737
  }
890
738
  function setValue(data, element, name, value) {
891
- const callback = isBooleanAttribute(name) && name in element
892
- ? name === 'selected'
893
- ? updateSelected
894
- : updateProperty
895
- : setAttribute$1;
739
+ let callback;
740
+ if (isBooleanAttribute(name) && name in element) {
741
+ callback = name === 'selected' ? updateSelected : updateProperty;
742
+ }
743
+ else {
744
+ callback = setAttribute$1;
745
+ }
896
746
  if (isReactive(value)) {
897
747
  data.mora.subscribers.add(value.subscribe(next => {
898
748
  callback(element, name, next);
@@ -902,11 +752,6 @@ function setValue(data, element, name, value) {
902
752
  callback(element, name, value);
903
753
  }
904
754
  }
905
- function triggerSelectChange(select) {
906
- if (select != null) {
907
- select.dispatchEvent(new Event('change', { bubbles: true }));
908
- }
909
- }
910
755
  function updateProperty(element, name, value) {
911
756
  element[name] = value === true;
912
757
  }
@@ -914,14 +759,13 @@ function updateSelected(element, name, value) {
914
759
  const select = element.closest('select');
915
760
  const options = [...(select?.options ?? [])];
916
761
  if (select != null && options.includes(element)) {
917
- triggerSelectChange(select);
762
+ select.dispatchEvent(new Event('change', { bubbles: true }));
918
763
  }
919
764
  updateProperty(element, name, value);
920
765
  }
921
766
 
922
- const commentExpression$1 = /^<!--abydon\.(\d+)-->$/;
923
767
  function getValue(data, original) {
924
- const matches = commentExpression$1.exec(original ?? '');
768
+ const matches = EXPRESSION_COMMENT_FULL.exec(original ?? '');
925
769
  return matches == null ? original : data.values[+matches[1]];
926
770
  }
927
771
  function mapAttributes(data, element) {
@@ -930,24 +774,27 @@ function mapAttributes(data, element) {
930
774
  for (let index = 0; index < length; index += 1) {
931
775
  const { name, value } = attributes[index];
932
776
  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);
777
+ switch (true) {
778
+ case name.startsWith('@'):
779
+ mapEvent(element, name, actual);
780
+ break;
781
+ case name.includes('.') ||
782
+ typeof actual === 'function' ||
783
+ isReactive(actual):
784
+ mapValue$1(data, element, name, actual);
785
+ break;
786
+ case isBooleanAttribute(name):
787
+ setProperty(element, name, value);
788
+ break;
940
789
  }
941
790
  }
942
791
  }
943
792
  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;
793
+ if (typeof value === 'function') {
794
+ setComputedAttribute(data, element, name, value);
795
+ }
796
+ else {
797
+ setAttribute(data, element, name, value);
951
798
  }
952
799
  }
953
800
  function setComputedAttribute(data, element, name, callback) {
@@ -956,6 +803,44 @@ function setComputedAttribute(data, element, name, callback) {
956
803
  setAttribute(data, element, name, value);
957
804
  }
958
805
 
806
+ //
807
+ function addToArray(identifiers, items, nodes, added) {
808
+ let position = nodes[0];
809
+ const before = added && !identifiers.previous.includes(items.templates[0].identifier);
810
+ const next = items.next.flatMap(fragment => fragment.get().flatMap(node => ({
811
+ identifier: fragment.identifier,
812
+ value: node,
813
+ })));
814
+ const { length } = next;
815
+ for (let index = 0; index < length; index += 1) {
816
+ const node = next[index];
817
+ if (!(added && identifiers.previous.includes(node.identifier))) {
818
+ if (index === 0 && before) {
819
+ position.before(node.value);
820
+ }
821
+ else {
822
+ position.after(node.value);
823
+ }
824
+ }
825
+ position = node.value;
826
+ }
827
+ }
828
+ function handleArray(identifiers, items, nodes) {
829
+ const next = items.templates.map(template => items.fragments?.find(fragment => fragment.identifier === template.identifier) ?? template);
830
+ const comparison = compareArrays(items.fragments ?? [], items.templates);
831
+ if (comparison !== 'removed') {
832
+ addToArray(identifiers, { ...items, next }, nodes, comparison === 'added');
833
+ }
834
+ const toRemove = items.fragments?.filter(fragment => !identifiers.next.includes(fragment.identifier)) ?? [];
835
+ const { length } = toRemove;
836
+ for (let index = 0; index < length; index += 1) {
837
+ toRemove[index].remove();
838
+ }
839
+ return {
840
+ fragments: next,
841
+ nodes: next.flatMap(fragment => fragment.get()),
842
+ };
843
+ }
959
844
  function removeFragments(fragments) {
960
845
  if (fragments != null) {
961
846
  const { length } = fragments;
@@ -964,133 +849,111 @@ function removeFragments(fragments) {
964
849
  }
965
850
  }
966
851
  }
967
- function setArray(fragments, nodes, comment, text, value) {
852
+ function setArray(item, comment, value) {
968
853
  if (value.length === 0) {
969
854
  return {
970
- nodes: setText(fragments, nodes, comment, text, value),
855
+ nodes: setText(item, comment, value),
971
856
  };
972
857
  }
973
858
  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) {
859
+ const next = templates.map(fragment => fragment.identifier);
860
+ const previous = item.fragments?.map(fragment => fragment.identifier) ?? [];
861
+ if (new Set(next).size !== templates.length) {
977
862
  templates = [];
978
863
  }
979
864
  const noTemplates = templates.length === 0;
980
865
  if (noTemplates ||
981
- nodes == null ||
982
- oldIdentifiers.some(identifier => identifier == null)) {
866
+ item.nodes == null ||
867
+ previous.some(identifier => identifier == null)) {
983
868
  return {
984
869
  fragments: noTemplates ? undefined : templates,
985
- nodes: setNodes(fragments, nodes, comment, text, noTemplates
870
+ nodes: setNodes(item, comment, noTemplates
986
871
  ? value.flatMap(item => createNodes(item))
987
872
  : templates.flatMap(template => template.get())),
988
873
  };
989
874
  }
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
- };
875
+ return handleArray({
876
+ next,
877
+ previous,
878
+ }, {
879
+ templates,
880
+ fragments: item.fragments ?? [],
881
+ }, item.nodes);
1024
882
  }
1025
- function setNodes(fragments, nodes, comment, text, next) {
1026
- if (nodes == null) {
883
+ function setNodes(item, comment, next) {
884
+ if (item.nodes == null) {
1027
885
  if (comment.parentNode != null) {
1028
886
  replaceNodes([comment], next);
1029
887
  }
1030
- else if (text.parentNode != null) {
1031
- replaceNodes([text], next);
888
+ else if (item.text?.parentNode != null) {
889
+ replaceNodes([item.text], next);
1032
890
  }
1033
891
  }
1034
892
  else {
1035
- replaceNodes(nodes, next);
893
+ replaceNodes(item.nodes, next);
1036
894
  }
1037
- removeFragments(fragments);
895
+ removeFragments(item.fragments);
1038
896
  return next;
1039
897
  }
1040
898
  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;
899
+ let item = data.items.find(item => item.nodes?.includes(comment));
900
+ item ??= {};
901
+ item.text = new Text();
1045
902
  data.mora.subscribers.add(reactive.subscribe(value => {
1046
903
  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;
904
+ setReactiveValueForArray(item, comment, value);
1055
905
  }
1056
906
  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])];
907
+ setReactiveValueForSingle(item, comment, value);
1069
908
  }
909
+ item.nodes = [...(item.nodes ?? [comment])];
1070
910
  }));
1071
911
  }
1072
- function setText(fragments, nodes, comment, text, value) {
912
+ function setReactiveValueForArray(item, comment, value) {
913
+ const result = setArray(item, comment, value);
914
+ item.fragments = typeof result === 'boolean' ? undefined : result?.fragments;
915
+ if (typeof result === 'boolean') {
916
+ item.nodes = result ? item.text == null ? [] : [item.text] : undefined;
917
+ }
918
+ else {
919
+ item.nodes = result?.nodes;
920
+ }
921
+ }
922
+ function setReactiveValueForSingle(item, comment, value) {
923
+ const valueIsFragment = isFragment(value);
924
+ item.fragments = valueIsFragment ? [value] : undefined;
925
+ if (valueIsFragment || isChildNode(value)) {
926
+ item.nodes = setNodes(item, comment, createNodes(value));
927
+ }
928
+ else {
929
+ item.nodes = setText(item, comment, value);
930
+ }
931
+ }
932
+ function setText(item, comment, value) {
1073
933
  const isNullable = isNullableOrWhitespace(value);
1074
- text.textContent = isNullable ? '' : getString(value);
934
+ if (item.text != null) {
935
+ item.text.textContent = isNullable ? '' : getString$1(value);
936
+ }
1075
937
  let result = false;
1076
- if (nodes != null) {
1077
- replaceNodes(nodes, [isNullable ? comment : text]);
938
+ if (item.nodes != null) {
939
+ replaceNodes(item.nodes, isNullable ? [comment] : item.text == null ? [] : [item.text]);
1078
940
  result = !isNullable;
1079
941
  }
1080
942
  else if (isNullable && comment.parentNode == null) {
1081
- text.replaceWith(comment);
943
+ item.text?.replaceWith(comment);
1082
944
  }
1083
- else if (!isNullable && text.parentNode == null) {
1084
- comment.replaceWith(text);
945
+ else if (!isNullable && item?.text?.parentNode == null) {
946
+ if (item.text != null) {
947
+ comment.replaceWith(item.text);
948
+ }
1085
949
  result = true;
1086
950
  }
1087
- removeFragments(fragments);
1088
- return result ? [text] : undefined;
951
+ removeFragments(item.fragments);
952
+ return result ? item.text == null ? [] : [item.text] : undefined;
1089
953
  }
1090
954
 
1091
- const commentExpression = /^abydon\.(\d+)$/;
1092
955
  function mapNode(data, comment) {
1093
- const matches = commentExpression.exec(comment.textContent ?? '');
956
+ const matches = EXPRESSION_COMMENT_CONTENT.exec(comment.textContent ?? '');
1094
957
  const value = matches == null ? null : data.values[+matches[1]];
1095
958
  if (value != null) {
1096
959
  mapValue(data, comment, value);
@@ -1126,7 +989,7 @@ function mapValue(data, comment, value) {
1126
989
  }
1127
990
  }
1128
991
  function replaceComment(data, comment, value) {
1129
- const item = data.items.find(item => item.nodes.includes(comment));
992
+ const item = data.items.find(item => item.nodes?.includes(comment));
1130
993
  const nodes = createNodes(value);
1131
994
  if (item != null) {
1132
995
  item.fragments = isFragment(value) ? [value] : undefined;
@@ -1157,22 +1020,48 @@ function handleExpression(data, prefix, expression) {
1157
1020
  return isNullableOrWhitespace(expression) ? prefix : `${prefix}${expression}`;
1158
1021
  }
1159
1022
  function parse(data) {
1023
+ if (data.template != null) {
1024
+ return data.template;
1025
+ }
1160
1026
  const { length } = data.strings;
1161
- let template = '';
1027
+ data.template = '';
1162
1028
  for (let index = 0; index < length; index += 1) {
1163
- template += handleExpression(data, data.strings[index], data.expressions[index]);
1029
+ data.template += handleExpression(data, data.strings[index], data.expressions[index]);
1164
1030
  }
1165
- return template;
1031
+ data.expressions = [];
1032
+ data.strings = [];
1033
+ return data.template;
1166
1034
  }
1167
1035
 
1036
+ function calculate() {
1037
+ return new Promise((resolve) => {
1038
+ const values = [];
1039
+ let last;
1040
+ function step(now) {
1041
+ if (last != null) values.push(now - last);
1042
+ last = now;
1043
+ if (values.length >= CALCULATION_TOTAL) resolve(values.sort().slice(2, -2).reduce((first, second) => first + second, 0) / (values.length - CALCULATION_TRIM));
1044
+ else requestAnimationFrame(step);
1045
+ }
1046
+ requestAnimationFrame(step);
1047
+ });
1048
+ }
1049
+ var CALCULATION_TOTAL = 10;
1050
+ var CALCULATION_TRIM = 4;
1051
+ calculate().then((value) => {
1052
+ });
1053
+
1168
1054
  class Fragment {
1169
- $fragment = true;
1170
- data;
1055
+ #data;
1056
+ #configuration = {
1057
+ identifier: undefined,
1058
+ ignoreCache: false,
1059
+ };
1171
1060
  get identifier() {
1172
- return this.data.identifier;
1061
+ return this.#configuration.identifier;
1173
1062
  }
1174
1063
  constructor(strings, expressions) {
1175
- this.data = {
1064
+ this.#data = {
1176
1065
  expressions,
1177
1066
  strings,
1178
1067
  items: [],
@@ -1182,6 +1071,9 @@ class Fragment {
1182
1071
  },
1183
1072
  values: [],
1184
1073
  };
1074
+ Object.defineProperty(this, '$fragment', {
1075
+ value: true,
1076
+ });
1185
1077
  }
1186
1078
  /**
1187
1079
  * Appends the fragment to the given element
@@ -1189,33 +1081,47 @@ class Fragment {
1189
1081
  appendTo(element) {
1190
1082
  element.append(...this.get());
1191
1083
  }
1084
+ configure(configuration) {
1085
+ const actual = isPlainObject$1(configuration) ? configuration : {};
1086
+ if (actual.identifier !== undefined) {
1087
+ this.#configuration.identifier = actual.identifier;
1088
+ }
1089
+ if (typeof actual.ignoreCache === 'boolean') {
1090
+ this.#configuration.ignoreCache = actual.ignoreCache;
1091
+ }
1092
+ return this;
1093
+ }
1192
1094
  /**
1193
1095
  * Gets a list of the fragment's nodes
1194
1096
  */
1195
1097
  get() {
1196
- if (this.data.items.length === 0) {
1197
- const parsed = parse(this.data);
1098
+ const data = this.#data;
1099
+ if (data.items.length === 0) {
1100
+ const parsed = parse(data);
1198
1101
  const templated = html$1(parsed, {
1199
1102
  sanitizeBooleanAttributes: false,
1200
1103
  });
1201
- this.data.items.splice(0, this.data.items.length, ...templated.map(node => ({
1104
+ if (this.#configuration.ignoreCache) {
1105
+ html$1.remove(parsed);
1106
+ }
1107
+ data.items.splice(0, data.items.length, ...templated.map(node => ({
1202
1108
  nodes: [node],
1203
1109
  })));
1204
- mapNodes(this.data, this.data.items.flatMap(item => item.fragments?.flatMap(fragment => fragment.get()) ?? item.nodes));
1110
+ mapNodes(data, data.items.flatMap(item => item.fragments?.flatMap(fragment => fragment.get()) ?? item.nodes ?? []));
1205
1111
  }
1206
1112
  return [
1207
- ...this.data.items.flatMap(item => item.fragments?.flatMap(fragment => fragment.get()) ?? item.nodes),
1113
+ ...data.items.flatMap(item => item.fragments?.flatMap(fragment => fragment.get()) ?? item.nodes ?? []),
1208
1114
  ];
1209
1115
  }
1210
1116
  identify(identifier) {
1211
- this.data.identifier = identifier;
1117
+ this.#configuration.identifier = identifier;
1212
1118
  return this;
1213
1119
  }
1214
1120
  /**
1215
1121
  * Removes the fragment from the DOM
1216
1122
  */
1217
1123
  remove() {
1218
- removeFragment(this.data);
1124
+ removeFragment(this.#data);
1219
1125
  }
1220
1126
  }
1221
1127
  function removeFragment(data) {
@@ -1223,13 +1129,13 @@ function removeFragment(data) {
1223
1129
  const { length } = data.items;
1224
1130
  for (let index = 0; index < length; index += 1) {
1225
1131
  const { fragments, nodes } = data.items[index];
1226
- const { length } = fragments ?? [];
1132
+ const length = fragments?.length ?? 0;
1227
1133
  for (let index = 0; index < length; index += 1) {
1228
1134
  fragments?.[index]?.remove();
1229
1135
  }
1230
- removeNodes(nodes);
1136
+ removeNodes(nodes ?? []);
1231
1137
  }
1232
- data.items.splice(0, length);
1138
+ data.items.length = 0;
1233
1139
  }
1234
1140
  function removeMora(data) {
1235
1141
  const unsubscribers = [...data.mora.subscribers];