@oscarpalmer/abydon 0.23.0 → 0.24.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.
@@ -2,15 +2,16 @@
2
2
  const ACTIVE = {};
3
3
  const BATCH = {
4
4
  depth: 0,
5
- handlers: /* @__PURE__ */ new Set()
5
+ flushing: false,
6
+ handlers: /* @__PURE__ */ new Map()
6
7
  };
7
- const METHODS_AFFECTING_LENGTH = new Set([
8
+ const METHODS_AFFECTING_LENGTH = /* @__PURE__ */ new Set([
8
9
  "pop",
9
10
  "push",
10
11
  "shift",
11
12
  "unshift"
12
13
  ]);
13
- const METHODS_UPDATE = new Set([
14
+ const METHODS_UPDATE = /* @__PURE__ */ new Set([
14
15
  ...METHODS_AFFECTING_LENGTH,
15
16
  "copyWithin",
16
17
  "fill",
@@ -22,753 +23,1166 @@ const NAME_ARRAY = "array";
22
23
  const NAME_COMPUTED = "computed";
23
24
  const NAME_EFFECT = "effect";
24
25
  const NAME_MORA = "$mora";
26
+ const NAME_READONLY = "readonly";
25
27
  const NAME_SIGNAL = "signal";
26
28
  const NAME_STORE = "store";
27
- const NAME_ALL = new Set([
29
+ const NAME_SUBSCRIPTION = "subscription";
30
+ const NAME_ALL = /* @__PURE__ */ new Set([
28
31
  NAME_ARRAY,
29
32
  NAME_COMPUTED,
33
+ NAME_READONLY,
30
34
  NAME_SIGNAL,
31
35
  NAME_STORE
32
36
  ]);
37
+ const PROPERTY_LENGTH = "length";
38
+ const SYMBOL_EFFECT = Symbol("effect");
39
+ const SYMBOL_STATE = Symbol("state");
40
+ const SUBSCRIPTION_PROPERTY$1 = {
41
+ key: NAME_MORA,
42
+ value: NAME_SUBSCRIPTION
43
+ };
44
+ const SUBSCRIPTION_TYPE_COPY = "copy";
45
+ const SUBSCRIPTION_TYPE_FROZEN = "frozen";
46
+ const SUBSCRIPTION_TYPE_ORIGINAL = "original";
47
+ const SUBSCRIPTION_TYPE_READONLY = "readonly";
48
+ const SUBSCRIPTION_TYPES_COPY = /* @__PURE__ */ new Set([SUBSCRIPTION_TYPE_COPY, SUBSCRIPTION_TYPE_READONLY]);
49
+ const SUBSCRIPTION_TYPES = /* @__PURE__ */ new Set([
50
+ ...SUBSCRIPTION_TYPES_COPY,
51
+ SUBSCRIPTION_TYPE_FROZEN,
52
+ SUBSCRIPTION_TYPE_ORIGINAL
53
+ ]);
33
54
  //#endregion
34
55
  //#region node_modules/@oscarpalmer/mora/dist/effect.mjs
35
- var Effect = class {
36
- constructor(callback) {
37
- Object.defineProperty(this, NAME_MORA, { value: NAME_EFFECT });
38
- this.state = { callback };
39
- runEffect(this);
40
- }
41
- };
42
- function runEffect(effect) {
43
- const previousEffect = ACTIVE.effect;
44
- ACTIVE.effect = effect;
45
- try {
46
- effect.state.callback();
47
- } finally {
48
- ACTIVE.effect = previousEffect;
49
- }
56
+ function Effect(callback) {
57
+ this[SYMBOL_STATE] = { callback };
58
+ runEffect(this[SYMBOL_STATE]);
50
59
  }
60
+ Effect.prototype[NAME_MORA] = NAME_EFFECT;
51
61
  /**
52
62
  * Create an effect
63
+ *
53
64
  * @param callback Callback for handling signal effects
54
65
  * @returns Effect
55
66
  */
56
67
  function effect(callback) {
57
- return typeof callback === "function" ? new Effect(callback) : void 0;
68
+ if (typeof callback !== "function") throw new TypeError("Effect callback must be a function");
69
+ return getEffect(callback)[0];
70
+ }
71
+ function getEffect(callback) {
72
+ const instance = new Effect(callback);
73
+ return [instance, instance[SYMBOL_STATE]];
74
+ }
75
+ function internalEffect(callback) {
76
+ return getEffect(callback)[1];
77
+ }
78
+ function runEffect(state) {
79
+ const previousEffect = ACTIVE.effect;
80
+ ACTIVE.effect = state;
81
+ try {
82
+ state.callback();
83
+ } finally {
84
+ ACTIVE.effect = previousEffect;
85
+ }
58
86
  }
59
87
  //#endregion
60
- //#region node_modules/@oscarpalmer/mora/dist/helpers/is.mjs
88
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
61
89
  /**
62
- * Is the value a reactive array?
90
+ * Is the value a _Key_?
91
+ *
63
92
  * @param value Value to check
64
- * @returns True if value is a {@link ReactiveArray}
93
+ * @returns `true` if the value is a _Key_ _(`number` or `string`)_, otherwise `false`
65
94
  */
66
- function isArray(value) {
67
- return isMora(value, NAME_ARRAY);
95
+ function isKey(value) {
96
+ return typeof value === "number" || typeof value === "string";
68
97
  }
69
98
  /**
70
- * Is the value a computed signal?
99
+ * Is the value not a template strings array?
100
+ *
71
101
  * @param value Value to check
72
- * @returns True if value is a {@link Computed}
102
+ * @returns `true` if the value is not a `TemplateStringsArray`, otherwise `false`
73
103
  */
74
- function isComputed(value) {
75
- return isMora(value, NAME_COMPUTED);
104
+ function isNonTemplateStringsArray(value) {
105
+ return !isTemplateStringsArray(value);
76
106
  }
77
107
  /**
78
- * Is the value an effect?
108
+ * Is the value a number?
109
+ *
79
110
  * @param value Value to check
80
- * @returns True if value is an {@link Effect}
111
+ * @returns `true` if the value is a `number`, otherwise `false`
81
112
  */
82
- function isEffect(value) {
83
- return isMora(value, NAME_EFFECT);
84
- }
85
- function isMora(value, name) {
86
- return typeof value === "object" && value != null && "$mora" in value && (typeof name === "string" ? value["$mora"] === name : name.has(value["$mora"]));
113
+ function isNumber(value) {
114
+ return typeof value === "number" && !Number.isNaN(value);
87
115
  }
88
116
  /**
89
- * Is the value reactive?
117
+ * Is the value a plain object?
118
+ *
90
119
  * @param value Value to check
91
- * @returns True if value is a {@link Reactive}
120
+ * @returns `true` if the value is a plain object, otherwise `false`
92
121
  */
93
- function isReactive(value) {
94
- return isMora(value, NAME_ALL);
122
+ function isPlainObject(value) {
123
+ if (value === null || typeof value !== "object") return false;
124
+ if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
125
+ const prototype = Object.getPrototypeOf(value);
126
+ return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
95
127
  }
96
128
  /**
97
- * Is the value a signal?
129
+ * Is the value a template strings array?
130
+ *
98
131
  * @param value Value to check
99
- * @returns True if value is a {@link Signal}
132
+ * @returns `true` if the value is a `TemplateStringsArray`, otherwise `false`
100
133
  */
101
- function isSignal(value) {
102
- return isMora(value, NAME_SIGNAL);
134
+ function isTemplateStringsArray(value) {
135
+ return Array.isArray(value) && Array.isArray(value.raw);
103
136
  }
104
137
  //#endregion
105
- //#region node_modules/@oscarpalmer/mora/dist/batch.mjs
106
- function flushHandlers() {
107
- while (BATCH.depth === 0 && BATCH.handlers.size > 0) {
108
- const handlers = [...BATCH.handlers];
109
- BATCH.handlers.clear();
110
- for (const handler of handlers) if (isEffect(handler)) runEffect(handler);
111
- else handler.callback(handler.state.value);
112
- }
138
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/string/misc.mjs
139
+ /**
140
+ * Get the string value from any value
141
+ *
142
+ * @param value Original value
143
+ * @returns String representation of the value
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * getString(null) // => ''
148
+ * getString('foo') // => 'foo'
149
+ * getString(123) // => '123'
150
+ * getString(true) // => 'true'
151
+ * getString([1, 2, 3]) // => '1,2,3'
152
+ * getString({a: 1}) // => '{"a":1}'
153
+ * getString(() => 123) // => '123'
154
+ * ```
155
+ */
156
+ function getString(value) {
157
+ if (typeof value === "string") return value;
158
+ if (value == null) return "";
159
+ if (typeof value === "function") return getString(value());
160
+ if (typeof value !== "object") return String(value);
161
+ const asString = String(value.valueOf?.() ?? value);
162
+ return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
113
163
  }
114
164
  /**
115
- * Start batching effects
165
+ * Join an array of values into a string _(while ignoring empty values)_
116
166
  *
117
- * _(Use {@link stopBatch} to flush and run batched effects)_
167
+ * _(`null`, `undefined`, and any values that become whitespace-only strings are considered empty)_
168
+ *
169
+ * @param array Array of values
170
+ * @param delimiter Delimiter to use between values
171
+ * @returns Joined string
118
172
  */
119
- function startBatch() {
120
- BATCH.depth += 1;
173
+ function join(array, delimiter) {
174
+ if (!Array.isArray(array)) return "";
175
+ const { length } = array;
176
+ if (length === 0) return "";
177
+ const values = [];
178
+ for (let index = 0; index < length; index += 1) {
179
+ const item = getString(array[index]);
180
+ if (item.length > 0) values.push(item);
181
+ }
182
+ return values.join(typeof delimiter === "string" ? delimiter : "");
121
183
  }
122
184
  /**
123
- * Stop batching effects and flush _(run)_ them
185
+ * Split a string into words _(and other readable parts)_
186
+ *
187
+ * @param value Original string
188
+ * @returns Array of words found in the string
124
189
  */
125
- function stopBatch() {
126
- if (BATCH.depth > 0) BATCH.depth -= 1;
127
- flushHandlers();
190
+ function words(value) {
191
+ return typeof value === "string" ? value.match(STRING_EXPRESSION_WORDS) ?? [] : [];
128
192
  }
193
+ const STRING_EXPRESSION_WORDS = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
129
194
  //#endregion
130
- //#region node_modules/@oscarpalmer/mora/dist/subscription.mjs
131
- var Subscription = class {
132
- callback;
133
- state;
134
- constructor(state, callback) {
135
- this.state = state;
136
- this.callback = callback;
137
- callback(state.value);
138
- }
139
- destroy() {
140
- this.callback = noop$1;
141
- this.state = void 0;
142
- }
143
- };
144
- function noop$1() {}
145
- function subscribe(state, callback) {
146
- if (typeof callback !== "function" || state.subscriptions.has(callback)) return noop$1;
147
- state.subscriptions.set(callback, new Subscription(state, callback));
148
- return () => {
149
- unsubscribe(state, callback);
150
- };
151
- }
152
- function unsubscribe(state, callback) {
153
- state.subscriptions.get(callback)?.destroy();
154
- state.subscriptions.delete(callback);
195
+ //#region node_modules/@oscarpalmer/atoms/dist/is.mjs
196
+ /**
197
+ * Is the value `undefined`, `null`, or stringified as a whitespace-only string?
198
+ *
199
+ * @param value Value to check
200
+ * @returns `true` if the value is nullable or matches a whitespace-only string, otherwise `false`
201
+ */
202
+ function isNullableOrWhitespace(value) {
203
+ return value == null || EXPRESSION_WHITESPACE$1.test(getString(value));
155
204
  }
205
+ const EXPRESSION_WHITESPACE$1 = /^\s*$/;
156
206
  //#endregion
157
- //#region node_modules/@oscarpalmer/mora/dist/value/reactive.mjs
158
- var Reactive = class {
159
- /**
160
- * Internal state of the reactive value
161
- *
162
- * @internal
163
- */
164
- state = {
165
- computeds: /* @__PURE__ */ new Set(),
166
- effects: /* @__PURE__ */ new Set(),
167
- equal: Object.is,
168
- subscriptions: /* @__PURE__ */ new Map(),
169
- value: void 0
170
- };
171
- constructor(name, value, options) {
172
- this.state.value = value;
173
- if (typeof options === "object" && typeof options.equal === "function") this.state.equal = options.equal;
174
- Object.defineProperty(this, NAME_MORA, { value: name });
175
- }
176
- /**
177
- * Get the value _(without reactivity)_
178
- * @return Current value
179
- */
180
- peek() {
181
- return this.state.value;
182
- }
183
- /**
184
- * Subscribe to changes
185
- * @param callback Callback for changes
186
- * @return Unsubscribe callback
187
- */
188
- subscribe(callback) {
189
- return subscribe(this.state, callback);
190
- }
191
- /**
192
- * JSON representation of the value
193
- * @return JSON value
194
- */
195
- toJSON() {
196
- return this.get();
207
+ //#region node_modules/@oscarpalmer/mora/dist/helpers/value.mjs
208
+ function emitValue(instance, notify) {
209
+ const state = instance[SYMBOL_STATE];
210
+ if (state.computeds != null && state.computeds.size > 0) for (const computed of state.computeds) computed.dirty = true;
211
+ if (state.effects != null && state.effects.size > 0) for (const effect of state.effects) BATCH.handlers.set(effect, effect);
212
+ if (notify ?? false) {
213
+ const mapped = instance[SYMBOL_STATE].mapped;
214
+ for (const [, item] of mapped) {
215
+ const fx = item[SYMBOL_EFFECT];
216
+ BATCH.handlers.set(fx.instance, fx.instance);
217
+ }
197
218
  }
198
- /**
199
- * String representation of the value
200
- * @return Value as string
201
- */
202
- toString() {
203
- return String(this.get());
219
+ for (const type of SUBSCRIPTION_TYPES) {
220
+ const subscriptions = state.subscriptions?.values.to.keyed?.get(type);
221
+ if (subscriptions != null && subscriptions.size > 0) for (const [subscription, callback] of subscriptions) BATCH.handlers.set(subscription, {
222
+ callback,
223
+ instance,
224
+ state,
225
+ frozen: type === SUBSCRIPTION_TYPE_FROZEN,
226
+ copy: SUBSCRIPTION_TYPES_COPY.has(type)
227
+ });
204
228
  }
205
- /**
206
- * Unsubscribe from changes
207
- * @param callback Callback to unsubscribe
208
- */
209
- unsubscribe(callback) {
210
- unsubscribe(this.state, callback);
229
+ if (BATCH.depth === 0) flushHandlers();
230
+ }
231
+ function equalArrays(first, second, equal) {
232
+ const { length } = first;
233
+ if (length !== second.length) return false;
234
+ const eq = equal ?? Object.is;
235
+ let offset = 0;
236
+ if (length >= 100) {
237
+ offset = Math.round(length / 10);
238
+ offset = offset > 25 ? 25 : offset;
239
+ for (let index = 0; index < offset; index += 1) if (!(eq(first[index], second[index]) && eq(first[length - index - 1], second[length - index - 1]))) return false;
211
240
  }
212
- };
213
- //#endregion
214
- //#region node_modules/@oscarpalmer/mora/dist/value/computed.mjs
215
- var Computed = class extends Reactive {
216
- effect = {
217
- dirty: true,
218
- instance: void 0
219
- };
220
- constructor(callback, options) {
221
- super(NAME_COMPUTED, void 0, options);
222
- this.effect.instance = effect(() => {
223
- if (this.effect.dirty) {
224
- setValue$2(this, this.state, callback);
225
- this.effect.dirty = false;
226
- }
227
- });
241
+ const end = length - offset;
242
+ for (let index = offset; index < end; index += 1) if (!eq(first[index], second[index])) return false;
243
+ return true;
244
+ }
245
+ function getFrozenValue(value) {
246
+ let frozen = value;
247
+ if (Array.isArray(frozen)) frozen = Object.freeze(frozen.slice());
248
+ else if (isPlainObject(frozen)) frozen = Object.freeze({ ...frozen });
249
+ return frozen;
250
+ }
251
+ function getJsonValue() {
252
+ return this[SYMBOL_STATE].value;
253
+ }
254
+ function getSignalValue() {
255
+ const state = this[SYMBOL_STATE];
256
+ if (ACTIVE.computed != null) {
257
+ state.computeds ??= /* @__PURE__ */ new Set();
258
+ state.computeds.add(ACTIVE.computed);
228
259
  }
229
- /**
230
- * @inheritdoc
231
- */
232
- get() {
233
- if (ACTIVE.computed != null && this !== ACTIVE.computed) this.state.computeds.add(ACTIVE.computed);
234
- if (ACTIVE.effect != null && ACTIVE.effect !== this.effect.instance) this.state.effects.add(ACTIVE.effect);
235
- if (this.effect.dirty && BATCH.depth === 0) runEffect(this.effect.instance);
236
- return this.state.value;
260
+ if (ACTIVE.effect != null) {
261
+ state.effects ??= /* @__PURE__ */ new Set();
262
+ state.effects.add(ACTIVE.effect);
237
263
  }
238
- };
239
- /**
240
- * Create a computed value
241
- * @param callback Callback to compute the value
242
- * @param options Reactivity options
243
- * @returns Computed value
244
- */
245
- function computed(callback, options) {
246
- return new Computed(callback, options);
264
+ return state.value;
247
265
  }
248
- function setAndEmit$1(state, value) {
249
- if (state.equal(state.value, value)) return;
250
- state.value = value;
251
- for (const computed of state.computeds) computed.effect.dirty = true;
252
- for (const effect of state.effects) BATCH.handlers.add(effect);
253
- for (const [, subscription] of state.subscriptions) subscription.callback(value);
254
- flushHandlers();
266
+ function getStringValue(json) {
267
+ return json === true ? JSON.stringify(this[SYMBOL_STATE].value) : String(this[SYMBOL_STATE].value);
255
268
  }
256
- function setValue$2(instance, state, callback) {
257
- const previousComputed = ACTIVE.computed;
258
- ACTIVE.computed = instance;
269
+ function handleSignal(instance, origin, setValue, onAfter, notify) {
270
+ const state = instance[SYMBOL_STATE];
259
271
  try {
260
- const value = callback();
261
- if (value instanceof Promise) {
262
- state.promise = value;
263
- value.then((resolvedValue) => {
264
- if (state.promise === value) {
272
+ let actual = typeof origin === "function" ? origin() : origin;
273
+ if (actual instanceof Promise) {
274
+ state.promise = actual;
275
+ actual.then((value) => {
276
+ if (actual === state.promise) {
265
277
  state.promise = void 0;
266
- setAndEmit$1(state, resolvedValue);
278
+ setValue(instance, value, notify ?? false);
267
279
  }
268
280
  }).catch(() => {
269
- if (state.promise === value) state.promise = void 0;
281
+ if (actual === state.promise) state.promise = void 0;
270
282
  });
271
- } else setAndEmit$1(state, value);
283
+ } else setValue(instance, actual, notify ?? false);
284
+ } catch {} finally {
285
+ onAfter?.();
286
+ }
287
+ }
288
+ function peekSignalValue(copy) {
289
+ let peeked = Array.isArray(this) ? this[1] : this[SYMBOL_STATE].value;
290
+ if (copy !== true) return peeked;
291
+ if (Array.isArray(peeked)) peeked = peeked.slice();
292
+ else if (isPlainObject(peeked)) peeked = { ...peeked };
293
+ return peeked;
294
+ }
295
+ function updateSignal(instance, callback, setValue) {
296
+ if (typeof callback !== "function") throw new TypeError("Callback must be a function");
297
+ handleSignal(instance, callback(instance[SYMBOL_STATE].value), setValue);
298
+ }
299
+ //#endregion
300
+ //#region node_modules/@oscarpalmer/mora/dist/batch.mjs
301
+ function flushHandlers() {
302
+ if (BATCH.flushing) return;
303
+ BATCH.flushing = true;
304
+ try {
305
+ while (BATCH.depth === 0 && BATCH.handlers.size > 0) {
306
+ const handlers = [...BATCH.handlers];
307
+ const { length } = handlers;
308
+ BATCH.handlers.clear();
309
+ for (let index = 0; index < length; index += 1) {
310
+ const [, handler] = handlers[index];
311
+ const subscription = handler;
312
+ if (typeof subscription.frozen === "boolean") subscription.callback(subscription.frozen ? getFrozenValue(subscription.state.value) : peekSignalValue.call(subscription.instance, subscription.copy));
313
+ else runEffect(handler);
314
+ }
315
+ }
272
316
  } finally {
273
- ACTIVE.computed = previousComputed;
317
+ BATCH.flushing = false;
274
318
  }
275
319
  }
320
+ /**
321
+ * Start batching effects
322
+ *
323
+ * _(Use {@link stopBatch} to flush and run batched effects)_
324
+ */
325
+ function startBatch() {
326
+ BATCH.depth += 1;
327
+ }
328
+ /**
329
+ * Stop batching effects and flush _(run)_ them
330
+ */
331
+ function stopBatch() {
332
+ if (BATCH.depth > 0) BATCH.depth -= 1;
333
+ flushHandlers();
334
+ }
276
335
  //#endregion
277
- //#region node_modules/@oscarpalmer/mora/node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
336
+ //#region node_modules/@oscarpalmer/mora/dist/helpers/is.mjs
278
337
  /**
279
- * Is the value a key?
338
+ * Is the value a computed signal?
339
+ *
280
340
  * @param value Value to check
281
- * @returns `true` if the value is a `Key` _(`number` or `string`)_, otherwise `false`
341
+ * @returns True if value is a {@link Computed}
282
342
  */
283
- function isKey(value) {
284
- return typeof value === "number" || typeof value === "string";
343
+ function isComputed(value) {
344
+ return isMora(value, NAME_COMPUTED);
285
345
  }
286
346
  /**
287
- * Is the value a plain object?
347
+ * Is the value an effect?
348
+ *
288
349
  * @param value Value to check
289
- * @returns `true` if the value is a plain object, otherwise `false`
350
+ * @returns True if value is an {@link Effect}
290
351
  */
291
- function isPlainObject$1(value) {
292
- if (value === null || typeof value !== "object") return false;
293
- if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
294
- const prototype = Object.getPrototypeOf(value);
295
- return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
352
+ function isEffect(value) {
353
+ return isMora(value, NAME_EFFECT);
354
+ }
355
+ function isMora(value, name) {
356
+ return typeof value === "object" && value != null && "$mora" in value && (typeof name === "string" ? value["$mora"] === name : name.has(value["$mora"]));
296
357
  }
297
- //#endregion
298
- //#region node_modules/@oscarpalmer/mora/node_modules/@oscarpalmer/atoms/dist/math.mjs
299
358
  /**
300
- * Round a number
301
- * @param value Number to round
302
- * @param decimals Number of decimal places to round to _(defaults to `0`)_
303
- * @returns Rounded number, or `NaN` if the value if unable to be rounded
359
+ * Is the value reactive?
360
+ *
361
+ * @param value Value to check
362
+ * @returns True if value is a {@link Reactive}
304
363
  */
305
- function round(value, decimals) {
306
- return roundNumber(Math.round, value, decimals);
364
+ function isReactive(value) {
365
+ return isMora(value, NAME_ALL);
307
366
  }
308
- function roundNumber(callback, value, decimals) {
309
- if (typeof value !== "number") return NaN;
310
- if (typeof decimals !== "number" || decimals < 1) return callback(value);
311
- const mod = 10 ** decimals;
312
- return callback((value + Number.EPSILON) * mod) / mod;
367
+ /**
368
+ * Is the value a signal?
369
+ *
370
+ * @param value Value to check
371
+ * @returns True if value is a {@link Signal}
372
+ */
373
+ function isSignal(value) {
374
+ return isMora(value, NAME_SIGNAL);
313
375
  }
314
- //#endregion
315
- //#region node_modules/@oscarpalmer/mora/dist/helpers/value.mjs
316
- function emitValue(state) {
317
- for (const computed of state.computeds) computed.effect.dirty = true;
318
- for (const effect of state.effects) BATCH.handlers.add(effect);
319
- for (const [, subscription] of state.subscriptions) BATCH.handlers.add(subscription);
320
- if (BATCH.depth === 0) flushHandlers();
376
+ /**
377
+ * Is the value a reactive array?
378
+ *
379
+ * @param value Value to check
380
+ * @returns True if value is a {@link ReactiveArray}
381
+ */
382
+ function isReactiveArray(value) {
383
+ return isMora(value, NAME_ARRAY);
321
384
  }
322
- function equalArrays(state, first, second) {
323
- let { length } = first;
324
- if (length !== second.length) return false;
325
- let offset = 0;
326
- if (length >= 100) {
327
- offset = round(length / 10);
328
- offset = offset > 25 ? 25 : offset;
329
- for (let index = 0; index < offset; index += 1) if (!state.equal(first[index], second[index])) return false;
330
- }
331
- length -= offset;
332
- for (let index = offset; index < length; index += 1) if (!state.equal(first[index], second[index])) return false;
333
- return true;
385
+ /**
386
+ * Is the value a reactive store?
387
+ *
388
+ * @param value Value to check
389
+ * @returns True if value is a {@link Store}
390
+ */
391
+ function isReactiveStore(value) {
392
+ return isMora(value, NAME_STORE);
334
393
  }
335
- function getValue$1(state) {
336
- if (ACTIVE.computed != null) state.computeds.add(ACTIVE.computed);
337
- if (ACTIVE.effect != null) state.effects.add(ACTIVE.effect);
338
- return state.value;
394
+ /**
395
+ * Is the value a readonly signal?
396
+ *
397
+ * @param value Value to check
398
+ * @returns True if value is a {@link ReadonlySignal}
399
+ */
400
+ function isReadonlySignal(value) {
401
+ return isMora(value, NAME_READONLY);
339
402
  }
340
403
  //#endregion
341
- //#region node_modules/@oscarpalmer/mora/dist/value/signal.mjs
342
- var Signal = class extends Reactive {
343
- constructor(value, options) {
344
- super(NAME_SIGNAL, value, options);
345
- }
346
- /**
347
- * @inheritdoc
348
- */
349
- get() {
350
- return getValue$1(this.state);
351
- }
352
- /**
353
- * Set the value
354
- * @param value New value
355
- */
356
- set(value) {
357
- setValue$1(this.state, value);
358
- }
359
- /**
360
- * Update the value _(based on the current value)_
361
- * @param callback Callback to update the value
362
- */
363
- update(callback) {
364
- this.set(callback(this.state.value));
365
- }
366
- };
367
- function setAndEmit(state, value) {
368
- if (!state.equal(state.value, value)) {
369
- state.value = value;
370
- emitValue(state);
404
+ //#region node_modules/@oscarpalmer/mora/dist/helpers/misc.mjs
405
+ function getState(value, options) {
406
+ return {
407
+ value,
408
+ equal: typeof options === "object" && typeof options?.equal === "function" ? options.equal : void 0
409
+ };
410
+ }
411
+ //#endregion
412
+ //#region node_modules/@oscarpalmer/mora/dist/helpers/proxy.mjs
413
+ function getReactiveValueInProxy(instance, key) {
414
+ const state = instance[SYMBOL_STATE];
415
+ state.mapped ??= /* @__PURE__ */ new Map();
416
+ const mapKey = String(key);
417
+ let item = state.mapped.get(mapKey);
418
+ if (item == null) {
419
+ item = internalComputed(() => state.isArray ? instance.get().at(key) : instance.get()[key]);
420
+ state.mapped.set(mapKey, item);
371
421
  }
422
+ return item;
372
423
  }
373
- function setValue$1(state, value) {
374
- try {
375
- let actual = value;
376
- if (typeof value === "function") actual = value();
377
- if (actual instanceof Promise) {
378
- state.promise = actual;
379
- actual.then((value) => {
380
- if (actual === state.promise) {
381
- state.promise = void 0;
382
- setAndEmit(state, value);
383
- }
384
- }).catch(() => {
385
- if (actual === state.promise) state.promise = void 0;
386
- });
387
- } else setAndEmit(state, actual);
388
- } catch {}
424
+ function getValueInProxy(first) {
425
+ let signal;
426
+ if (this[SYMBOL_STATE].isArray ? typeof first === "number" : isKey(first)) signal = getReactiveValueInProxy(this, first);
427
+ return getSignalValue.call(signal ?? this);
389
428
  }
390
- function signal(value, options) {
391
- const instance = new Signal(void 0, options);
392
- instance.set(value);
393
- return instance;
429
+ function isProxyKey(isArray, value) {
430
+ return isArray ? typeof value === "number" : isKey(value);
394
431
  }
395
- //#endregion
396
- //#region node_modules/@oscarpalmer/mora/dist/helpers/proxy.mjs
397
- function emityProxyValues(state, mapped) {
398
- const values = [...mapped.values()];
432
+ function isProxyObject(isArray, value) {
433
+ return value == null || (isArray ? Array.isArray(value) : isPlainObject(value));
434
+ }
435
+ function notifyProxyValue() {
436
+ const state = this[SYMBOL_STATE];
437
+ state.mapped ??= /* @__PURE__ */ new Map();
438
+ const values = [...state.mapped.values()];
399
439
  const { length } = values;
400
- for (let index = 0; index < length; index += 1) values[index].effect.dirty = true;
401
- emitValue(state);
440
+ for (let index = 0; index < length; index += 1) {
441
+ values[index][SYMBOL_EFFECT].dirty = true;
442
+ values[index][SYMBOL_EFFECT].notify = true;
443
+ }
444
+ emitValue(this, true);
402
445
  }
403
- function getReactiveValueInProxy(reactive, mapped, key, isArray) {
404
- let item = mapped.get(key);
405
- if (item == null) {
406
- item = computed(() => isArray ? reactive.get().at(key) : reactive.get()[key]);
407
- mapped.set(key, item);
446
+ function peekValueInProxy(first, second) {
447
+ const state = this[SYMBOL_STATE];
448
+ let value;
449
+ if (state.isArray ? typeof first === "number" : isKey(first)) value = state.isArray ? state.value.at(first) : state.value[first];
450
+ else value = state.value;
451
+ return peekSignalValue.call([this, value], first === true || second === true);
452
+ }
453
+ function setProxyObject(state, value) {
454
+ if (state.isArray) {
455
+ const values = state.value;
456
+ values.splice(0, values.length, ...value ?? []);
457
+ return;
408
458
  }
409
- return item;
459
+ startBatch();
460
+ const current = state.value;
461
+ const next = value ?? {};
462
+ const currentKeys = Object.keys(current);
463
+ const nextKeys = Object.keys(next);
464
+ let { length } = currentKeys;
465
+ for (let index = 0; index < length; index += 1) {
466
+ const key = currentKeys[index];
467
+ current[key] = nextKeys.includes(key) ? next[key] : void 0;
468
+ }
469
+ length = nextKeys.length;
470
+ for (let index = 0; index < length; index += 1) {
471
+ const key = nextKeys[index];
472
+ if (!currentKeys.includes(key)) current[key] = next[key];
473
+ }
474
+ stopBatch();
410
475
  }
411
- function setProxyValue(array, state, isObject, isProperty, setObject, setProperty, first, second) {
412
- if (array && first === "length") {
476
+ function setProxyProperty(state, property, value) {
477
+ if (!state.isArray) {
478
+ state.value[property] = value;
479
+ return;
480
+ }
481
+ const array = state.value;
482
+ const index = property;
483
+ const actual = index < 0 ? array.length + index : index;
484
+ if (actual > -1) array[actual] = value;
485
+ }
486
+ function setProxyValue(first, second) {
487
+ const state = this[SYMBOL_STATE];
488
+ if (state.isArray && first === "length") {
413
489
  state.value.length = second;
414
490
  return;
415
491
  }
416
- if (isObject(first)) {
417
- setObject(state, first);
492
+ if (isProxyObject(state.isArray, first)) {
493
+ setProxyObject(state, first);
418
494
  return;
419
495
  }
420
- const property = isProperty(first);
421
- if (array && property && Number.isNaN(first)) return;
422
- let actual = property ? second : first;
496
+ const keyed = isProxyKey(state.isArray, first);
497
+ if (state.isArray && keyed && Number.isNaN(first)) return;
498
+ let actual = keyed ? second : first;
423
499
  if (typeof actual === "function") try {
424
500
  actual = actual();
425
501
  } catch {
426
502
  return;
427
503
  }
428
504
  if (actual instanceof Promise) {
429
- if (property) {
505
+ if (keyed) {
430
506
  state.promises ??= /* @__PURE__ */ new Map();
431
507
  state.promises.set(first, actual);
432
508
  } else state.promise = actual;
433
509
  actual.then((value) => {
434
- if (property && state.promises.get(first) === actual) {
435
- state.promises.delete(first);
436
- setProperty(state, first, value);
510
+ if (keyed && state.promises?.get(first) === actual) {
511
+ state.promises?.delete(first);
512
+ setProxyProperty(state, first, value);
437
513
  return;
438
514
  }
439
- if (!property && isObject(value) && state.promise === actual) {
515
+ if (!keyed && isProxyObject(state.isArray, value) && state.promise === actual) {
440
516
  state.promise = void 0;
441
- setObject(state, value);
517
+ setProxyObject(state, value);
442
518
  }
443
519
  }).catch(() => {
444
- if (property && state.promises.get(first) === actual) state.promises.delete(first);
445
- else if (!property && state.promise === actual) state.promise = void 0;
520
+ if (keyed && state.promises?.get(first) === actual) state.promises?.delete(first);
521
+ else if (!keyed && state.promise === actual) state.promise = void 0;
446
522
  });
447
- } else if (property) setProperty(state, first, actual);
448
- else if (isObject(actual)) setObject(state, actual);
523
+ } else if (keyed) setProxyProperty(state, first, actual);
524
+ else if (isProxyObject(state.isArray, actual)) setProxyObject(state, actual);
449
525
  }
450
- function setValueInProxy(parameters) {
451
- const { isArray, length, property, state, target, value } = parameters;
452
- if (isArray) {
526
+ function setValueInProxy(instance, target, property, value) {
527
+ const state = instance[SYMBOL_STATE];
528
+ if (state.isArray) {
453
529
  if (!(!Number.isNaN(Number(property)) || property === "length")) return Reflect.set(target, property, value);
454
530
  }
455
531
  const previous = Reflect.get(target, property);
456
- if (!state.equal(previous, value)) {
532
+ if (!(state.equal ?? Object.is)(previous, value)) {
457
533
  Reflect.set(target, property, value);
458
- emitValue(state);
459
- if (isArray) length?.set(target.length);
534
+ emitValue(instance);
535
+ if (state.isArray) state.length?.set(target.length);
460
536
  }
461
537
  return true;
462
538
  }
539
+ function updateProxyValue(callback) {
540
+ if (typeof callback !== "function") throw new TypeError("Callback must be a function");
541
+ setProxyValue.call(this, callback(this[SYMBOL_STATE].value));
542
+ }
463
543
  //#endregion
464
- //#region node_modules/@oscarpalmer/mora/dist/value/array.mjs
465
- var ReactiveArray = class extends Reactive {
466
- #indiced = /* @__PURE__ */ new Map();
467
- #size = signal(0);
468
- /**
469
- * The length of the array
470
- */
471
- get length() {
472
- return this.#size.get();
473
- }
474
- /**
475
- * Set the length of the array
476
- */
477
- set length(value) {
478
- if (typeof value === "number" && value >= 0 && value !== this.state.value.length) this.get().length = value;
479
- }
480
- constructor(value, options) {
481
- super(NAME_ARRAY, new Proxy(value, {
482
- get: (target, property) => METHODS_UPDATE.has(property) ? updateArray(property, target, this.state, this.#size) : Reflect.get(target, property),
483
- set: (target, property, value) => setValueInProxy({
484
- property,
485
- target,
486
- value,
487
- isArray: true,
488
- state: this.state,
489
- length: this.#size
490
- })
491
- }), options);
492
- this.#size.set(value.length);
493
- }
494
- /**
495
- * Clear the array
496
- */
497
- clear() {
498
- this.length = 0;
499
- }
500
- /**
501
- * Create a computed, filtered array
502
- * @param callback Callback to evaluate each item
503
- * @return Computed array of filtered items
504
- */
505
- filter(callback) {
506
- return computed(() => this.get().filter(callback));
507
- }
508
- get(first) {
509
- if (typeof first === "number") return getReactiveValueInProxy(this, this.#indiced, first, true).get();
510
- return first === "length" ? this.length : getValue$1(this.state);
511
- }
512
- /**
513
- * Create a computed, mapped array
514
- * @param callback Callback to transform each item
515
- * @return Computed array of mapped items
516
- */
517
- map(callback) {
518
- return computed(() => this.get().map(callback));
519
- }
520
- /**
521
- * Notify dependents of changes
522
- *
523
- * _This bypasses equality checks and will immediately notify dependents.
524
- * Use this only if you're modifying nested data that would be ignored by equality checks._
525
- */
526
- notify() {
527
- emityProxyValues(this.state, this.#indiced);
528
- }
529
- peek(value) {
530
- if (value === "length") return this.#size.peek();
531
- return typeof value === "number" ? this.state.value.at(value) : this.state.value.slice();
532
- }
533
- /**
534
- * Remove and return the last item of the array
535
- * @returns Removed item, or `undefined` if the array is empty
536
- */
537
- pop() {
538
- return this.state.value.pop();
539
- }
540
- /**
541
- * Add items to the end of the array
542
- * @param items Items to add
543
- * @returns New array length
544
- */
545
- push(...items) {
546
- return this.state.value.push(...items);
547
- }
548
- set(first, second) {
549
- setProxyValue(true, this.state, isArrayValue, isArrayIndex, setArray$1, setAtIndex, first, second);
550
- }
551
- /**
552
- * Remove and return the first item of the array
553
- * @returns Removed item, or `undefined` if the array is empty
554
- */
555
- shift() {
556
- return this.state.value.shift();
557
- }
558
- /**
559
- * Remove and return items from the array _(and optionally add new items)_
560
- * @param from Index to start removing items from
561
- * @param to Index to stop removing items at _(defaults to the end of the array)_
562
- * @param items Optional items to add
563
- * @returns Removed items
564
- */
565
- splice(from, to, ...items) {
566
- return this.state.value.splice(from, to ?? this.state.value.length, ...items);
567
- }
568
- subscribe(first, second) {
569
- if (typeof first === "number" && typeof second === "function") return getReactiveValueInProxy(this, this.#indiced, first, true).subscribe(second);
570
- return typeof first === "function" ? subscribe(this.state, first) : noop$1;
571
- }
572
- /**
573
- * Add items to the beginning of the array
574
- * @param items Items to add
575
- * @returns New array length
576
- */
577
- unshift(...items) {
578
- return this.state.value.unshift(...items);
544
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/aborter.mjs
545
+ function createAborter(value, onAbort) {
546
+ if (!(value instanceof AbortSignal)) return;
547
+ value.addEventListener(ABORT_EVENT, onAbort, ABORT_OPTIONS);
548
+ return {
549
+ callback: onAbort,
550
+ signal: value,
551
+ cancel: () => value.removeEventListener(ABORT_EVENT, onAbort)
552
+ };
553
+ }
554
+ const ABORT_EVENT = "abort";
555
+ const ABORT_OPTIONS = { once: true };
556
+ //#endregion
557
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/subscription.mjs
558
+ const SUBSCRIPTION_NAME = "subscription";
559
+ const SUBSCRIPTION_PROPERTY = "$subscription";
560
+ const SUBSCRIPTION_STORE = "subscriptions";
561
+ function Subscription(state, property, parameters) {
562
+ this[SUBSCRIPTION_SYMBOL] = state;
563
+ this[property.key] = property.value;
564
+ state.aborter = createAborter(parameters.signal, () => this.unsubscribe(subscriptions, this, state));
565
+ addSubscription(this);
566
+ }
567
+ Subscription.prototype[SUBSCRIPTION_PROPERTY] = SUBSCRIPTION_NAME;
568
+ Subscription.prototype.unsubscribe = removeSubscription;
569
+ Object.defineProperty(Subscription.prototype, "active", {
570
+ enumerable: true,
571
+ get: getSubscriptionActive
572
+ });
573
+ function Subscriptions(parameters) {
574
+ const { keys, property } = createSubscriptionsParameters(parameters);
575
+ this[SUBSCRIPTION_SYMBOL] = createSubscriptionsState(property, keys);
576
+ }
577
+ Subscriptions.prototype[SUBSCRIPTION_PROPERTY] = SUBSCRIPTION_STORE;
578
+ Subscriptions.prototype.clear = clearSubscriptions;
579
+ Subscriptions.prototype.create = createSubscription;
580
+ Object.defineProperties(Subscriptions.prototype, {
581
+ items: {
582
+ enumerable: true,
583
+ get: getSubscriptionsItems
584
+ },
585
+ values: {
586
+ enumerable: true,
587
+ get: getSubscriptionsValues
588
+ }
589
+ });
590
+ function addSubscription(instance) {
591
+ const state = instance[SUBSCRIPTION_SYMBOL];
592
+ const { key, value } = state.parameters;
593
+ const { items, values } = state.subscriptions;
594
+ if (!isKey(key)) {
595
+ items.any.add(instance);
596
+ values.from.any.set(value, instance);
597
+ values.to.any.set(instance, value);
598
+ return;
579
599
  }
580
- /**
581
- * Update the value _(based on the current value)_
582
- * @param callback Callback to update the value
583
- */
584
- update(callback) {
585
- const updated = callback(this.state.value);
586
- if (updated == null || Array.isArray(updated)) this.set(updated);
600
+ /* istanbul ignore if */
601
+ if (items.keyed == null || values.from.keyed == null || values.to.keyed == null)
602
+ // istanbul ignore next
603
+ return;
604
+ let keyedItems = items.keyed.get(key);
605
+ if (keyedItems == null) {
606
+ keyedItems = /* @__PURE__ */ new Set();
607
+ items.keyed.set(key, keyedItems);
608
+ }
609
+ keyedItems.add(instance);
610
+ let keyedFrom = values.from.keyed.get(key);
611
+ if (keyedFrom == null) {
612
+ keyedFrom = /* @__PURE__ */ new Map();
613
+ values.from.keyed.set(key, keyedFrom);
614
+ }
615
+ keyedFrom.set(value, instance);
616
+ let keyedTo = values.to.keyed.get(key);
617
+ if (keyedTo == null) {
618
+ keyedTo = /* @__PURE__ */ new Map();
619
+ values.to.keyed.set(key, keyedTo);
620
+ }
621
+ keyedTo.set(instance, value);
622
+ }
623
+ function clearSubscriptions() {
624
+ const state = this[SUBSCRIPTION_SYMBOL];
625
+ for (const susbcription of state.values.to.any.keys()) susbcription.unsubscribe();
626
+ if (state.values.to.keyed != null && state.values.to.keyed.size > 0) for (const values of state.values.to.keyed.values()) for (const susbcription of values.keys()) susbcription.unsubscribe();
627
+ }
628
+ function createSubscription(params) {
629
+ const parameters = createSubscriptionParameters(params);
630
+ if (parameters.signal?.aborted ?? false) throw new Error(parameters.signal?.reason);
631
+ const subscriptions = this[SUBSCRIPTION_SYMBOL];
632
+ const state = {
633
+ parameters,
634
+ subscriptions,
635
+ active: true
636
+ };
637
+ const existing = getExistingSubscription(subscriptions, state);
638
+ if (existing != null) return [existing, true];
639
+ if (subscriptions.keys != null && isKey(parameters.key)) {
640
+ if (subscriptions.keys === false) throw new Error(SUBSCRIPTION_DISALLOWED_KEY);
641
+ else if (subscriptions.keys !== true && !subscriptions.keys.has(parameters.key)) throw new Error(SUBSCRIPTION_INVALID_KEY);
587
642
  }
588
- };
589
- function array(value, options) {
590
- const instance = new ReactiveArray([], options);
591
- instance.set(value);
592
- return instance;
643
+ return [new Subscription(state, subscriptions.property, parameters), false];
593
644
  }
594
- function isArrayIndex(value) {
595
- return typeof value === "number";
645
+ function getExistingSubscription(subscriptions, state) {
646
+ const { values } = subscriptions;
647
+ const { parameters } = state;
648
+ return isKey(parameters.key) ? values.from.keyed?.get(parameters.key)?.get(parameters.value) : values.from.any.get(parameters.value);
596
649
  }
597
- function isArrayValue(value) {
598
- return value == null || Array.isArray(value);
650
+ function getSubscriptionActive() {
651
+ const state = this[SUBSCRIPTION_SYMBOL];
652
+ return (state.parameters?.isActive?.() ?? true) && state.active;
599
653
  }
600
- function updateArray(type, array, state, length) {
601
- const affectsLength = METHODS_AFFECTING_LENGTH.has(type);
602
- const previousArray = affectsLength ? [] : array.slice();
603
- const previousLength = array.length;
604
- return (...args) => {
605
- const result = array[type](...args);
606
- if (affectsLength ? array.length !== previousLength : !equalArrays(state, previousArray, array)) {
607
- emitValue(state);
608
- length.set(array.length);
654
+ function getSubscriptionsItems() {
655
+ return this[SUBSCRIPTION_SYMBOL].items;
656
+ }
657
+ function getSubscriptionsValues() {
658
+ return this[SUBSCRIPTION_SYMBOL].values;
659
+ }
660
+ function createSubscriptionParameters(input) {
661
+ const values = isPlainObject(input) ? input : {};
662
+ if (values.value == null) throw new Error(SUBSCRIPTION_INVALID_VALUE);
663
+ return {
664
+ isActive: typeof values.isActive === "function" ? values.isActive : void 0,
665
+ key: isKey(values.key) ? values.key : void 0,
666
+ signal: values.signal instanceof AbortSignal ? values.signal : void 0,
667
+ value: values.value
668
+ };
669
+ }
670
+ function createSubscriptionsParameters(input) {
671
+ const values = isPlainObject(input) ? input : {};
672
+ let keys;
673
+ if (values.keys instanceof Set) keys = values.keys;
674
+ else keys = typeof values.keys === "boolean" ? values.keys : false;
675
+ return {
676
+ keys,
677
+ property: createSubscriptionsProperty(values.property)
678
+ };
679
+ }
680
+ function createSubscriptionsProperty(input) {
681
+ const values = isPlainObject(input) ? input : {};
682
+ return {
683
+ key: typeof values.key === "string" ? values.key : SUBSCRIPTION_PROPERTY,
684
+ value: values.value == null ? SUBSCRIPTION_NAME : values.value
685
+ };
686
+ }
687
+ function createSubscriptionsState(property, keys) {
688
+ return {
689
+ keys,
690
+ property,
691
+ items: {
692
+ any: /* @__PURE__ */ new Set(),
693
+ keyed: keys === false ? void 0 : /* @__PURE__ */ new Map()
694
+ },
695
+ values: {
696
+ from: {
697
+ any: /* @__PURE__ */ new Map(),
698
+ keyed: keys === false ? void 0 : /* @__PURE__ */ new Map()
699
+ },
700
+ to: {
701
+ any: /* @__PURE__ */ new Map(),
702
+ keyed: keys === false ? void 0 : /* @__PURE__ */ new Map()
703
+ }
609
704
  }
610
- return result;
611
705
  };
612
706
  }
613
- function setArray$1(state, value) {
614
- state.value.splice(0, state.value.length, ...value ?? []);
707
+ function removeFromStore(items, values, subscription, value, key) {
708
+ items.delete(subscription);
709
+ if (key == null) {
710
+ values.from.any.delete(value);
711
+ values.to.any.delete(subscription);
712
+ } else {
713
+ values.from.keyed?.get(key)?.delete(value);
714
+ values.to.keyed?.get(key)?.delete(subscription);
715
+ }
716
+ }
717
+ function removeSubscription() {
718
+ const state = this[SUBSCRIPTION_SYMBOL];
719
+ if (!state.active) return;
720
+ state.aborter = void 0;
721
+ state.active = false;
722
+ const { items, values } = state.subscriptions;
723
+ const { key, value } = state.parameters;
724
+ state.parameters = void 0;
725
+ state.subscriptions = void 0;
726
+ if (!isKey(key)) {
727
+ removeFromStore(items.any, values, this, value);
728
+ return;
729
+ }
730
+ const keyed = items.keyed?.get(key);
731
+ /* istanbul ignore if */
732
+ if (items.keyed == null || keyed == null)
733
+ // istanbul ignore next
734
+ return;
735
+ removeFromStore(keyed, values, this, value, key);
736
+ if (keyed.size === 0) items.keyed.delete(key);
737
+ }
738
+ /**
739
+ * Create a subscription store
740
+ *
741
+ * @param parameters Store parameters
742
+ * @returns Subscription store
743
+ */
744
+ function subscriptions(parameters) {
745
+ return new Subscriptions(parameters);
746
+ }
747
+ const SUBSCRIPTION_DISALLOWED_KEY = "Disallowed key for subscription";
748
+ const SUBSCRIPTION_INVALID_KEY = "Invalid key for subscription";
749
+ const SUBSCRIPTION_INVALID_VALUE = "A subscription requires a non-null value to identify it";
750
+ const SUBSCRIPTION_SYMBOL = Symbol(SUBSCRIPTION_PROPERTY);
751
+ //#endregion
752
+ //#region node_modules/@oscarpalmer/mora/dist/helpers/subscription.mjs
753
+ function subscribeToProxy(first, second, third) {
754
+ if (isKey(first)) return getReactiveValueInProxy(this, first).subscribe(second, third);
755
+ return subscribeToSignal.call(this, first, second);
756
+ }
757
+ function subscribeToReactive(type, subscriber) {
758
+ this[SYMBOL_STATE].subscriptions ??= subscriptions({
759
+ keys: SUBSCRIPTION_TYPES,
760
+ property: SUBSCRIPTION_PROPERTY$1
761
+ });
762
+ const [subscription, existing] = this[SYMBOL_STATE].subscriptions.create({
763
+ key: type,
764
+ value: subscriber
765
+ });
766
+ if (!existing) subscriber(type === "frozen" ? getFrozenValue(this[SYMBOL_STATE].value) : peekSignalValue.call(this, SUBSCRIPTION_TYPES_COPY.has(type)), subscription);
767
+ return subscription;
768
+ }
769
+ function subscribeToReadonly(subscriber) {
770
+ return subscribeToReactive.call(this, this.frozen ? SUBSCRIPTION_TYPE_FROZEN : SUBSCRIPTION_TYPE_READONLY, subscriber);
615
771
  }
616
- function setAtIndex(state, index, value) {
617
- const actual = index < 0 ? state.value.length + index : index;
618
- if (actual > -1) state.value[actual] = value;
772
+ function subscribeToSignal(subscriber, copy) {
773
+ return subscribeToReactive.call(this, copy === true ? SUBSCRIPTION_TYPE_COPY : SUBSCRIPTION_TYPE_ORIGINAL, subscriber);
619
774
  }
620
775
  //#endregion
621
- //#region node_modules/@oscarpalmer/mora/dist/value/store.mjs
622
- var Store = class extends Reactive {
623
- #keyed = /* @__PURE__ */ new Map();
624
- constructor(value, options) {
625
- super(NAME_STORE, new Proxy(value, { set: (target, property, value) => setValueInProxy({
626
- target,
627
- property,
628
- value,
629
- isArray: false,
630
- state: this.state
631
- }) }), options);
776
+ //#region node_modules/@oscarpalmer/mora/dist/value/computed.mjs
777
+ function Computed(callback, options) {
778
+ this[SYMBOL_STATE] = getState(void 0, options);
779
+ this[SYMBOL_EFFECT] = getComputedEffect(this, callback);
780
+ }
781
+ Computed.prototype[NAME_MORA] = NAME_COMPUTED;
782
+ Computed.prototype.get = getComputedValue;
783
+ Computed.prototype.peek = peekSignalValue;
784
+ Computed.prototype.subscribe = subscribeToSignal;
785
+ Computed.prototype.toJSON = getJsonValue;
786
+ Computed.prototype.toString = getStringValue;
787
+ /**
788
+ * Create a computed value
789
+ *
790
+ * @param callback Callback to compute the value
791
+ * @param options Reactivity options
792
+ * @returns Computed value
793
+ */
794
+ function computed(callback, options) {
795
+ return getComputed(callback, options);
796
+ }
797
+ function getComputed(callback, options) {
798
+ if (typeof callback !== "function") throw new TypeError("Computed callback must be a function");
799
+ return new Computed(callback, options);
800
+ }
801
+ function getComputedEffect(instance, callback) {
802
+ const fx = {
803
+ dirty: true,
804
+ instance: void 0,
805
+ notify: false
806
+ };
807
+ fx.instance = internalEffect(() => {
808
+ if (fx.dirty) {
809
+ const previousComputed = ACTIVE.computed;
810
+ ACTIVE.computed = fx;
811
+ handleSignal(instance, callback, setAndEmit$1, () => {
812
+ ACTIVE.computed = previousComputed;
813
+ fx.notify = false;
814
+ }, fx.notify);
815
+ fx.dirty = false;
816
+ }
817
+ });
818
+ return fx;
819
+ }
820
+ function getComputedValue() {
821
+ const fx = this[SYMBOL_EFFECT];
822
+ const state = this[SYMBOL_STATE];
823
+ if (ACTIVE.computed != null && fx !== ACTIVE.computed) {
824
+ state.computeds ??= /* @__PURE__ */ new Set();
825
+ state.computeds.add(ACTIVE.computed);
632
826
  }
633
- get(key) {
634
- return isKey(key) ? getReactiveValueInProxy(this, this.#keyed, key, false).get() : getValue$1(this.state);
827
+ if (ACTIVE.effect != null && ACTIVE.effect !== fx.instance) {
828
+ state.effects ??= /* @__PURE__ */ new Set();
829
+ state.effects.add(ACTIVE.effect);
635
830
  }
636
- /**
637
- * Notify dependents of changes
638
- *
639
- * _This bypasses equality checks and will immediately notify dependents.
640
- * Use this only if you're modifying nested data that would be ignored by equality checks._
641
- */
642
- notify() {
643
- emityProxyValues(this.state, this.#keyed);
831
+ if (fx.dirty && BATCH.depth === 0) runEffect(fx.instance);
832
+ return state.value;
833
+ }
834
+ function internalComputed(callback, options) {
835
+ return getComputed(callback, options);
836
+ }
837
+ function setAndEmit$1(instance, value, notify) {
838
+ const state = instance[SYMBOL_STATE];
839
+ if (!notify && (state.equal ?? Object.is)(state.value, value)) return;
840
+ state.value = value;
841
+ if (state.computeds != null && state.computeds.size > 0) for (const computed of state.computeds) computed.dirty = true;
842
+ if (state.effects != null && state.effects.size > 0) for (const effect of state.effects) BATCH.handlers.set(effect, effect);
843
+ for (const type of SUBSCRIPTION_TYPES) {
844
+ if (type === "frozen") continue;
845
+ const subscriptions = state.subscriptions?.values.to.keyed?.get(type);
846
+ if (subscriptions != null && subscriptions.size > 0) {
847
+ const copy = SUBSCRIPTION_TYPES_COPY.has(type);
848
+ for (const [, callback] of subscriptions) callback(peekSignalValue.call(instance, copy));
849
+ }
644
850
  }
645
- peek(key) {
646
- return isKey(key) ? this.state.value[key] : { ...this.state.value };
851
+ flushHandlers();
852
+ }
853
+ //#endregion
854
+ //#region node_modules/@oscarpalmer/mora/dist/value/readonly.mjs
855
+ function Readonly(state, frozen) {
856
+ this[SUBSCRIPTION_TYPE_FROZEN] = frozen;
857
+ this[SYMBOL_STATE] = state;
858
+ }
859
+ Readonly.prototype[NAME_MORA] = NAME_READONLY;
860
+ Readonly.prototype.get = getReadonlyValue;
861
+ Readonly.prototype.peek = peekReadonlyValue;
862
+ Readonly.prototype.subscribe = subscribeToReadonly;
863
+ Readonly.prototype.toJSON = getJsonValue;
864
+ Readonly.prototype.toString = getStringValue;
865
+ function getReadonlyInstance(state, frozen) {
866
+ return new Readonly(state, frozen);
867
+ }
868
+ function getReadonlySignal(frozen) {
869
+ const key = frozen === true ? SUBSCRIPTION_TYPE_FROZEN : SUBSCRIPTION_TYPE_ORIGINAL;
870
+ this[SYMBOL_STATE].readonlies ??= {};
871
+ this[SYMBOL_STATE].readonlies[key] ??= getReadonlyInstance(this[SYMBOL_STATE], frozen === true);
872
+ return this[SYMBOL_STATE].readonlies[key];
873
+ }
874
+ function getReadonlyValue() {
875
+ return handleReadonlyValue(this, false, this[SUBSCRIPTION_TYPE_FROZEN]);
876
+ }
877
+ function handleReadonlyValue(instance, peek, frozen, copy) {
878
+ let value;
879
+ if (peek) value = peekSignalValue.call(instance, copy === true);
880
+ else value = getSignalValue.call(instance);
881
+ return frozen ? getFrozenValue(value) : value;
882
+ }
883
+ function peekReadonlyValue(copy) {
884
+ return handleReadonlyValue(this, true, this[SUBSCRIPTION_TYPE_FROZEN], copy);
885
+ }
886
+ //#endregion
887
+ //#region node_modules/@oscarpalmer/mora/dist/value/signal.mjs
888
+ function Signal(value, options) {
889
+ this[SYMBOL_STATE] = getState(void 0, options);
890
+ handleSignal(this, value, setAndEmit);
891
+ }
892
+ Signal.prototype[NAME_MORA] = NAME_SIGNAL;
893
+ Signal.prototype.asReadonly = getReadonlySignal;
894
+ Signal.prototype.get = getSignalValue;
895
+ Signal.prototype.peek = peekSignalValue;
896
+ Signal.prototype.set = setSignalValue;
897
+ Signal.prototype.subscribe = subscribeToSignal;
898
+ Signal.prototype.toString = getStringValue;
899
+ Signal.prototype.toJSON = getJsonValue;
900
+ Signal.prototype.update = updateSignalValue;
901
+ function setAndEmit(instance, value) {
902
+ const state = instance[SYMBOL_STATE];
903
+ if (!(state.equal ?? Object.is)(state.value, value)) {
904
+ state.value = value;
905
+ emitValue(instance);
647
906
  }
648
- set(first, second) {
649
- setProxyValue(false, this.state, isStoreObject, isKey, setObject, setProperty, first, second);
907
+ }
908
+ function setSignalValue(value) {
909
+ handleSignal(this, value, setAndEmit);
910
+ }
911
+ function signal(value, options) {
912
+ return new Signal(value, options);
913
+ }
914
+ function updateSignalValue(callback) {
915
+ updateSignal(this, callback, setAndEmit);
916
+ }
917
+ //#endregion
918
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/array/callbacks.mjs
919
+ function getArrayCallback(value) {
920
+ switch (typeof value) {
921
+ case "function": return value;
922
+ case "number":
923
+ case "string": return typeof value === "string" && value.includes(".") ? void 0 : (obj) => obj[value];
924
+ default: return;
650
925
  }
651
- subscribe(first, second) {
652
- if (isKey(first) && typeof second === "function") return getReactiveValueInProxy(this, this.#keyed, first, false).subscribe(second);
653
- return typeof first === "function" ? subscribe(this.state, first) : noop$1;
926
+ }
927
+ function getArrayCallbacks(bool, key, value) {
928
+ if (typeof bool === "function") return { bool };
929
+ return {
930
+ keyed: getArrayCallback(key),
931
+ value: getArrayCallback(value)
932
+ };
933
+ }
934
+ //#endregion
935
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/array/find.mjs
936
+ function createFindParameters(original) {
937
+ const { length } = original;
938
+ return {
939
+ bool: length === 1 && typeof original[0] === "function" ? original[0] : void 0,
940
+ key: length === 2 ? original[0] : void 0,
941
+ value: length === 1 && typeof original[0] !== "function" ? original[0] : original[1]
942
+ };
943
+ }
944
+ function findValue(type, array, parameters, reversed) {
945
+ const findIndex = type === FIND_VALUE_INDEX;
946
+ if (!Array.isArray(array) || array.length === 0) return findIndex ? -1 : void 0;
947
+ const { bool, key, value } = createFindParameters(parameters);
948
+ const callbacks = getArrayCallbacks(bool, key);
949
+ if (callbacks?.bool == null && callbacks?.keyed == null) {
950
+ if (findIndex) return reversed ? array.lastIndexOf(value) : array.indexOf(value);
951
+ return reversed ? array.findLast((item) => Object.is(item, value)) : array.find((item) => Object.is(item, value));
654
952
  }
655
- /**
656
- * Update the value _(based on the current value)_
657
- * @param callback Callback to update the value
658
- */
659
- update(callback) {
660
- const updated = callback(this.state.value);
661
- if (updated == null || isPlainObject$1(updated)) setObject(this.state, updated);
953
+ if (callbacks.bool != null) {
954
+ const index = reversed ? array.findLastIndex(callbacks.bool) : array.findIndex(callbacks.bool);
955
+ return findIndex ? index : array[index];
662
956
  }
663
- };
664
- function isStoreObject(value) {
665
- return value == null || isPlainObject$1(value);
957
+ return findValueInArray(array, callbacks.keyed, value, findIndex, reversed);
666
958
  }
667
- function setObject(state, value) {
668
- startBatch();
669
- const actual = value ?? {};
670
- const proxy = state.value;
671
- const proxyKeys = Object.keys(proxy);
672
- const actualKeys = Object.keys(actual);
673
- let { length } = proxyKeys;
959
+ function findValueInArray(array, callback, value, findIndex, reversed) {
960
+ const { length } = array;
674
961
  for (let index = 0; index < length; index += 1) {
675
- const key = proxyKeys[index];
676
- proxy[key] = actualKeys.includes(key) ? actual[key] : void 0;
962
+ const item = reversed ? array.at(-(index + 1)) : array[index];
963
+ if (Object.is(callback?.(item, index, array), value)) return findIndex ? index : item;
964
+ }
965
+ return findIndex ? -1 : void 0;
966
+ }
967
+ function findValues(type, array, parameters, mapper) {
968
+ const result = {
969
+ matched: [],
970
+ notMatched: []
971
+ };
972
+ if (!Array.isArray(array) || array.length === 0) return result;
973
+ const { length } = array;
974
+ const { bool, key, value } = createFindParameters(parameters);
975
+ const callbacks = getArrayCallbacks(bool, key);
976
+ if (type === "unique" && callbacks?.keyed == null && length >= FIND_UNIQUE_THRESHOLD) {
977
+ result.matched = [...new Set(array)];
978
+ return result;
979
+ }
980
+ const mapCallback = getArrayCallback(mapper?.callback);
981
+ const mapReverse = mapper?.reverse ?? false;
982
+ const mapAfter = mapCallback == null ? void 0 : mapReverse ? void 0 : mapCallback;
983
+ const mapBefore = mapCallback == null ? void 0 : mapReverse ? mapCallback : void 0;
984
+ if (callbacks?.bool != null || type === "all" && key == null) {
985
+ const callback = callbacks?.bool ?? ((item) => Object.is(item, value));
986
+ for (let index = 0; index < length; index += 1) {
987
+ const item = array[index];
988
+ const transformed = mapBefore?.(item, index, array) ?? item;
989
+ if (callback(transformed, index, array)) result.matched.push(mapAfter?.(item, index, array) ?? transformed);
990
+ else result.notMatched.push(item);
991
+ }
992
+ return result;
677
993
  }
678
- length = actualKeys.length;
994
+ const keys = /* @__PURE__ */ new Set();
679
995
  for (let index = 0; index < length; index += 1) {
680
- const key = actualKeys[index];
681
- if (!proxyKeys.includes(key)) proxy[key] = actual[key];
996
+ const item = array[index];
997
+ let keyed;
998
+ let transformed;
999
+ if (mapBefore == null) {
1000
+ keyed = callbacks?.keyed?.(item, index, array) ?? item;
1001
+ transformed = item;
1002
+ } else {
1003
+ transformed = mapBefore(item, index, array);
1004
+ keyed = callbacks?.keyed?.(transformed, index, array) ?? transformed;
1005
+ }
1006
+ if (type === "all" && Object.is(keyed, value) || type === "unique" && !keys.has(keyed)) {
1007
+ keys.add(keyed);
1008
+ result.matched.push(mapAfter?.(item, index, array) ?? transformed);
1009
+ } else result.notMatched.push(item);
682
1010
  }
683
- stopBatch();
1011
+ return result;
684
1012
  }
685
- function setProperty(state, key, value) {
686
- state.value[key] = value;
1013
+ const FIND_VALUE_INDEX = "index";
1014
+ const FIND_VALUE_ITEM = "item";
1015
+ const FIND_UNIQUE_THRESHOLD = 100;
1016
+ //#endregion
1017
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/array/index-of.mjs
1018
+ function indexOf(array, ...parameters) {
1019
+ return findValue(FIND_VALUE_INDEX, array, parameters, false);
687
1020
  }
688
- function store(value, options) {
689
- const instance = new Store({}, options);
690
- instance.set(value);
691
- return instance;
1021
+ function lastIndexOf(array, ...parameters) {
1022
+ return findValue(FIND_VALUE_INDEX, array, parameters, true);
692
1023
  }
1024
+ indexOf.last = lastIndexOf;
693
1025
  //#endregion
694
- //#region node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
695
- /**
696
- * Is the value a number?
697
- * @param value Value to check
698
- * @returns `true` if the value is a `number`, otherwise `false`
699
- */
700
- function isNumber(value) {
701
- return typeof value === "number" && !Number.isNaN(value);
1026
+ //#region node_modules/@oscarpalmer/atoms/dist/array/find.mjs
1027
+ function find(array, ...parameters) {
1028
+ return findValue(FIND_VALUE_ITEM, array, parameters, false);
702
1029
  }
703
- /**
704
- * Is the value a plain object?
705
- * @param value Value to check
706
- * @returns `true` if the value is a plain object, otherwise `false`
707
- */
708
- function isPlainObject(value) {
709
- if (value === null || typeof value !== "object") return false;
710
- if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
711
- const prototype = Object.getPrototypeOf(value);
712
- return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
1030
+ function findLast(array, ...parameters) {
1031
+ return findValue(FIND_VALUE_ITEM, array, parameters, true);
713
1032
  }
1033
+ find.last = findLast;
714
1034
  //#endregion
715
- //#region node_modules/@oscarpalmer/atoms/dist/internal/string.mjs
716
- /**
717
- * Get the string value from any value
718
- * @param value Original value
719
- * @returns String representation of the value
720
- */
721
- function getString(value) {
722
- if (typeof value === "string") return value;
723
- if (value == null) return "";
724
- if (typeof value === "function") return getString(value());
725
- if (typeof value !== "object") return String(value);
726
- const asString = String(value.valueOf?.() ?? value);
727
- return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
1035
+ //#region node_modules/@oscarpalmer/atoms/dist/array/select.mjs
1036
+ function reverseSelect(array, ...parameters) {
1037
+ return findValues("all", array, parameters, {
1038
+ callback: parameters.shift(),
1039
+ reverse: true
1040
+ }).matched;
1041
+ }
1042
+ function select(array, ...parameters) {
1043
+ return selectValues(array, parameters);
1044
+ }
1045
+ function selectValues(array, parameters) {
1046
+ return findValues("all", array, parameters, {
1047
+ callback: parameters.pop(),
1048
+ reverse: false
1049
+ }).matched;
1050
+ }
1051
+ select.reverse = reverseSelect;
1052
+ //#endregion
1053
+ //#region node_modules/@oscarpalmer/atoms/dist/array/filter.mjs
1054
+ function exclude(array, ...parameters) {
1055
+ return findValues("all", array, parameters).notMatched;
728
1056
  }
729
- /**
730
- * Join an array of values into a string _(while ignoring empty values)_
731
- *
732
- * _(`null`, `undefined`, and any values that become whitespace-only strings are considered empty)_
733
- * @param array Array of values
734
- * @param delimiter Delimiter to use between values
735
- * @returns Joined string
736
- */
737
- function join(array, delimiter) {
738
- if (!Array.isArray(array)) return "";
739
- const { length } = array;
740
- if (length === 0) return "";
741
- const values = [];
742
- for (let index = 0; index < length; index += 1) {
743
- const item = getString(array[index]);
744
- if (item.trim().length > 0) values.push(item);
745
- }
746
- return values.join(typeof delimiter === "string" ? delimiter : "");
1057
+ function filter(array, ...parameters) {
1058
+ return findValues("all", array, parameters).matched;
747
1059
  }
748
- /**
749
- * Split a string into words _(and other readable parts)_
750
- * @param value Original string
751
- * @returns Array of words found in the string
752
- */
753
- function words(value) {
754
- return typeof value === "string" ? value.match(EXPRESSION_WORDS) ?? [] : [];
1060
+ filter.remove = exclude;
1061
+ //#endregion
1062
+ //#region node_modules/@oscarpalmer/mora/dist/value/array.mjs
1063
+ function ReactiveArray(value, options) {
1064
+ this[SYMBOL_STATE] = {
1065
+ ...getState(void 0, options),
1066
+ isArray: true,
1067
+ length: signal(0)
1068
+ };
1069
+ this[SYMBOL_STATE].value = new Proxy([], {
1070
+ get: (target, property) => METHODS_UPDATE.has(property) ? updateArray(this, property, target) : Reflect.get(target, property),
1071
+ set: (target, property, value) => setValueInProxy(this, target, property, value)
1072
+ });
1073
+ setProxyValue.call(this, value);
1074
+ }
1075
+ ReactiveArray.prototype[NAME_MORA] = NAME_ARRAY;
1076
+ Object.defineProperty(ReactiveArray.prototype, PROPERTY_LENGTH, {
1077
+ enumerable: true,
1078
+ get: getArrayLength,
1079
+ set: setArrayLength
1080
+ });
1081
+ ReactiveArray.prototype.asReadonly = getReadonlySignal;
1082
+ ReactiveArray.prototype.at = getArrayValues;
1083
+ ReactiveArray.prototype.clear = clearArrayValues;
1084
+ ReactiveArray.prototype.filter = filterArrayValues;
1085
+ ReactiveArray.prototype.get = getArrayValues;
1086
+ ReactiveArray.prototype.map = mapArrayValues;
1087
+ ReactiveArray.prototype.notify = notifyProxyValue;
1088
+ ReactiveArray.prototype.peek = peekArrayValue;
1089
+ ReactiveArray.prototype.pop = popArrayValue;
1090
+ ReactiveArray.prototype.push = pushArrayValues;
1091
+ ReactiveArray.prototype.select = selectArrayValues;
1092
+ ReactiveArray.prototype.shift = shiftArrayValue;
1093
+ ReactiveArray.prototype.set = setProxyValue;
1094
+ ReactiveArray.prototype.splice = spliceArrayValues;
1095
+ ReactiveArray.prototype.subscribe = subscribeToProxy;
1096
+ ReactiveArray.prototype.toString = getStringValue;
1097
+ ReactiveArray.prototype.toJSON = getJsonValue;
1098
+ ReactiveArray.prototype.unshift = unshiftArrayValues;
1099
+ ReactiveArray.prototype.update = updateProxyValue;
1100
+ function array(value, options) {
1101
+ return new ReactiveArray(value, options);
1102
+ }
1103
+ function clearArrayValues() {
1104
+ this[SYMBOL_STATE].value.length = 0;
1105
+ }
1106
+ function filterArrayValues(callback) {
1107
+ return computed(() => filter(getArrayValues.call(this), callback));
1108
+ }
1109
+ function getArrayLength() {
1110
+ return this[SYMBOL_STATE].length.get();
1111
+ }
1112
+ function getArrayValues(value) {
1113
+ return value === "length" ? this[SYMBOL_STATE].length.get() : getValueInProxy.call(this, value);
1114
+ }
1115
+ function mapArrayValues(callback) {
1116
+ return computed(() => getArrayValues.call(this).map(callback));
1117
+ }
1118
+ function peekArrayValue(first, second) {
1119
+ return first === "length" ? this[SYMBOL_STATE].length.peek() : peekValueInProxy.call(this, first, second);
1120
+ }
1121
+ function popArrayValue() {
1122
+ return this[SYMBOL_STATE].value.pop();
1123
+ }
1124
+ function pushArrayValues(...items) {
1125
+ return this[SYMBOL_STATE].value.push(...items);
1126
+ }
1127
+ function selectArrayValues(filter, map) {
1128
+ return computed(() => select(getArrayValues.call(this), filter, map));
1129
+ }
1130
+ function setArrayLength(value) {
1131
+ const values = this[SYMBOL_STATE].value;
1132
+ if (typeof value === "number" && !Number.isNaN(value) && value >= 0 && value !== values.length) values.length = value;
1133
+ }
1134
+ function shiftArrayValue() {
1135
+ return this[SYMBOL_STATE].value.shift();
1136
+ }
1137
+ function spliceArrayValues(from, to, ...items) {
1138
+ const values = this[SYMBOL_STATE].value;
1139
+ return values.splice(from, to ?? values.length, ...items);
1140
+ }
1141
+ function unshiftArrayValues(...items) {
1142
+ return this[SYMBOL_STATE].value.unshift(...items);
1143
+ }
1144
+ function updateArray(instance, type, array) {
1145
+ const state = instance[SYMBOL_STATE];
1146
+ const affectsLength = METHODS_AFFECTING_LENGTH.has(type);
1147
+ const previousArray = affectsLength ? [] : array.slice();
1148
+ const previousLength = array.length;
1149
+ return (...args) => {
1150
+ const result = array[type](...args);
1151
+ if (affectsLength ? array.length !== previousLength : !equalArrays(previousArray, array, state.equal)) {
1152
+ emitValue(instance);
1153
+ state.length.set(array.length);
1154
+ }
1155
+ return result;
1156
+ };
755
1157
  }
756
- const EXPRESSION_WORDS = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
757
1158
  //#endregion
758
- //#region node_modules/@oscarpalmer/atoms/dist/is.mjs
759
- /**
760
- * Is the value `undefined`, `null`, or stringified as a whitespace-only string?
761
- * @param value Value to check
762
- * @returns `true` if the value is nullable or matches a whitespace-only string, otherwise `false`
763
- */
764
- function isNullableOrWhitespace(value) {
765
- return value == null || EXPRESSION_WHITESPACE$1.test(getString(value));
1159
+ //#region node_modules/@oscarpalmer/mora/dist/value/store.mjs
1160
+ function ReactiveStore(value, options) {
1161
+ this[SYMBOL_STATE] = {
1162
+ ...getState(void 0, options),
1163
+ isArray: false
1164
+ };
1165
+ this[SYMBOL_STATE].value = new Proxy({}, { set: (target, property, value) => setValueInProxy(this, target, property, value) });
1166
+ setProxyValue.call(this, value);
1167
+ }
1168
+ ReactiveStore.prototype[NAME_MORA] = NAME_STORE;
1169
+ ReactiveStore.prototype.asReadonly = getReadonlySignal;
1170
+ ReactiveStore.prototype.get = getValueInProxy;
1171
+ ReactiveStore.prototype.notify = notifyProxyValue;
1172
+ ReactiveStore.prototype.peek = peekValueInProxy;
1173
+ ReactiveStore.prototype.set = setProxyValue;
1174
+ ReactiveStore.prototype.subscribe = subscribeToProxy;
1175
+ ReactiveStore.prototype.toJSON = getJsonValue;
1176
+ ReactiveStore.prototype.toString = getStringValue;
1177
+ ReactiveStore.prototype.update = updateProxyValue;
1178
+ function store(value, options) {
1179
+ return new ReactiveStore(value, options);
766
1180
  }
767
- const EXPRESSION_WHITESPACE$1 = /^\s*$/;
768
1181
  //#endregion
769
1182
  //#region node_modules/@oscarpalmer/toretto/dist/internal/is.mjs
770
1183
  /**
771
1184
  * Is the value an event target?
1185
+ *
772
1186
  * @param value Value to check
773
1187
  * @returns `true` if it's an event target, otherwise `false`
774
1188
  */
@@ -776,15 +1190,17 @@ function isEventTarget(value) {
776
1190
  return typeof value === "object" && value != null && typeof value.addEventListener === "function" && typeof value.removeEventListener === "function" && typeof value.dispatchEvent === "function";
777
1191
  }
778
1192
  /**
779
- * Is the value an HTML or SVG element?
1193
+ * Is the value an _HTML_ or _SVG_ element?
1194
+ *
780
1195
  * @param value Value to check
781
- * @returns `true` if it's an HTML or SVG element, otherwise `false`
1196
+ * @returns `true` if it's an _HTML_ or _SVG_ element, otherwise `false`
782
1197
  */
783
1198
  function isHTMLOrSVGElement(value) {
784
1199
  return value instanceof HTMLElement || value instanceof SVGElement;
785
1200
  }
786
1201
  /**
787
1202
  * Is the value an input element? _(`<input>`, `<select>`, or `<textarea>`)_
1203
+ *
788
1204
  * @param value Value to check
789
1205
  * @returns `true` if it's an input element, otherwise `false`
790
1206
  */
@@ -792,31 +1208,26 @@ function isInputElement(value) {
792
1208
  return value instanceof HTMLInputElement || value instanceof HTMLSelectElement || value instanceof HTMLTextAreaElement;
793
1209
  }
794
1210
  //#endregion
795
- //#region node_modules/@oscarpalmer/toretto/dist/is.mjs
796
- /**
797
- * Is the value a child node?
798
- * @param value Value to check
799
- * @returns `true` if it's a child node, otherwise `false`
800
- */
801
- function isChildNode(value) {
802
- return value instanceof Node && CHILD_NODE_TYPES.has(value.nodeType);
1211
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/defaults.mjs
1212
+ function getNumberOrDefault(value, defaultValue, minimum) {
1213
+ return typeof value === "number" && !Number.isNaN(value) && value >= (minimum ?? 0) ? value : defaultValue;
803
1214
  }
804
- const CHILD_NODE_TYPES = new Set([
805
- Node.ELEMENT_NODE,
806
- Node.TEXT_NODE,
807
- Node.PROCESSING_INSTRUCTION_NODE,
808
- Node.COMMENT_NODE,
809
- Node.DOCUMENT_TYPE_NODE
810
- ]);
811
1215
  //#endregion
812
1216
  //#region node_modules/@oscarpalmer/atoms/dist/internal/number.mjs
813
1217
  /**
814
1218
  * Clamp a number between a minimum and maximum value
1219
+ *
815
1220
  * @param value Value to clamp
816
1221
  * @param minimum Minimum value
817
1222
  * @param maximum Maximum value
818
1223
  * @param loop If `true`, the value will loop around when smaller than the minimum or larger than the maximum _(defaults to `false`)_
819
1224
  * @returns Clamped value
1225
+ *
1226
+ * @example
1227
+ * ```typescript
1228
+ * clamp(10, 0, 5); // => 5
1229
+ * clamp(10, 0, 5, true); // => 0
1230
+ * ```
820
1231
  */
821
1232
  function clamp(value, minimum, maximum, loop) {
822
1233
  if (![
@@ -828,29 +1239,29 @@ function clamp(value, minimum, maximum, loop) {
828
1239
  return value > maximum ? loop === true ? minimum : maximum : value;
829
1240
  }
830
1241
  //#endregion
831
- //#region node_modules/@oscarpalmer/atoms/dist/internal/sized.mjs
1242
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/sized/misc.mjs
832
1243
  function getSizedMaximum(first, second) {
833
1244
  let actual;
834
1245
  if (typeof first === "number") actual = first;
835
- else actual = typeof second === "number" ? second : MAXIMUM_DEFAULT;
836
- return clamp(actual, 1, MAXIMUM_ABSOLUTE);
1246
+ else actual = typeof second === "number" ? second : SIZED_MAXIMUM_DEFAULT;
1247
+ return clamp(actual, 1, SIZED_MAXIMUM_ABSOLUTE);
837
1248
  }
838
- const MAXIMUM_ABSOLUTE = 16777216;
839
- const MAXIMUM_DEFAULT = 1048576;
1249
+ const SIZED_MAXIMUM_ABSOLUTE = 16777216;
1250
+ const SIZED_MAXIMUM_DEFAULT = 1048576;
840
1251
  //#endregion
841
- //#region node_modules/@oscarpalmer/atoms/dist/sized/map.mjs
1252
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/sized/map.mjs
842
1253
  /**
843
- * A Map with a maximum size
1254
+ * A _Map_ with a maximum size
844
1255
  *
845
- * Behavior is similar to a _LRU_-cache, where the least recently used entries are removed
1256
+ * Behavior is similar to a _LRU_ cache, where the least recently used entries are removed
846
1257
  */
847
1258
  var SizedMap = class extends Map {
848
1259
  /**
849
- * The maximum size of the Map
1260
+ * The maximum size of the _Map_
850
1261
  */
851
1262
  #maximumSize;
852
1263
  /**
853
- * Is the Map full?
1264
+ * Is the _Map_ full?
854
1265
  */
855
1266
  get full() {
856
1267
  return super.size >= this.#maximumSize;
@@ -872,11 +1283,12 @@ var SizedMap = class extends Map {
872
1283
  * @inheritdoc
873
1284
  */
874
1285
  get(key) {
1286
+ let value;
875
1287
  if (super.has(key)) {
876
- const value = super.get(key);
1288
+ value = super.get(key);
877
1289
  this.#setValue(key, value, true);
878
- return value;
879
1290
  }
1291
+ return value;
880
1292
  }
881
1293
  /**
882
1294
  * @inheritdoc
@@ -884,124 +1296,104 @@ var SizedMap = class extends Map {
884
1296
  set(key, value) {
885
1297
  return this.#setValue(key, value, super.has(key));
886
1298
  }
887
- #setValue(key, value, has) {
888
- if (has) super.delete(key);
889
- else if (super.size >= this.#maximumSize) super.delete(super.keys().next().value);
890
- super.set(key, value);
891
- return this;
892
- }
893
- };
894
- //#endregion
895
- //#region node_modules/@oscarpalmer/atoms/dist/function/memoize.mjs
896
- /**
897
- * A memoized function, caching and retrieving results based on the its parameters _(or a custom cache key)_
898
- */
899
- var Memoized = class {
900
- #state;
901
- /**
902
- * Maximum cache size
903
- */
904
- get maximum() {
905
- return this.#state.cache?.maximum ?? NaN;
906
- }
907
- /**
908
- * Current cache size
909
- */
910
- get size() {
911
- return this.#state.cache?.size ?? NaN;
912
- }
913
- constructor(callback, options) {
914
- const cache = new SizedMap(options.cacheSize);
915
- const getter = (...parameters) => {
916
- const key = options.cacheKey?.(...parameters) ?? (parameters.length === 1 ? parameters[0] : join(parameters.map(getString), SEPARATOR));
917
- if (cache.has(key)) return cache.get(key);
918
- const value = callback(...parameters);
919
- cache.set(key, value);
920
- return value;
921
- };
922
- this.#state = {
923
- cache,
924
- getter
925
- };
926
- }
927
- /**
928
- * Clear the cache
929
- */
930
- clear() {
931
- this.#state.cache?.clear();
932
- }
933
- /**
934
- * Delete a result from the cache
935
- * @param key Key to delete
936
- * @returns `true` if the key existed and was removed, otherwise `false`
937
- */
938
- delete(key) {
939
- return this.#state.cache?.delete(key) ?? false;
940
- }
941
- /**
942
- * Destroy the instance _(clearing its cache and removing its callback)_
943
- */
944
- destroy() {
945
- this.#state.cache?.clear();
946
- this.#state.cache = void 0;
947
- this.#state.getter = void 0;
948
- }
949
- /**
950
- * Get a result from the cache
951
- * @param key Key to get
952
- * @returns Cached result or `undefined` if it does not exist
953
- */
954
- get(key) {
955
- return this.#state.cache?.get(key);
956
- }
957
- /**
958
- * Does the result exist?
959
- * @param key Key to check
960
- * @returns `true` if the result exists, otherwise `false`
961
- */
962
- has(key) {
963
- return this.#state.cache?.has(key) ?? false;
964
- }
965
- /**
966
- * Run the callback with the provided parameters
967
- * @param parameters Parameters to pass to the callback
968
- * @returns Cached or computed _(then cached)_ result
969
- */
970
- run(...parameters) {
971
- if (this.#state.cache == null || this.#state.getter == null) throw new Error("The Memoized instance has been destroyed");
972
- return this.#state.getter(...parameters);
1299
+ #setValue(key, value, has) {
1300
+ if (has) super.delete(key);
1301
+ else if (super.size >= this.#maximumSize) super.delete(super.keys().next().value);
1302
+ super.set(key, value);
1303
+ return this;
973
1304
  }
974
1305
  };
975
- function getMemoizationOptions(input) {
1306
+ //#endregion
1307
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/function/memoize.mjs
1308
+ function Memoized(callback, options) {
1309
+ this[MEMOIZED_SYMBOL] = {
1310
+ options,
1311
+ cache: new SizedMap(options.cacheSize),
1312
+ getter: void 0
1313
+ };
1314
+ this[MEMOIZED_SYMBOL].getter = createGetter(this[MEMOIZED_SYMBOL], callback);
1315
+ }
1316
+ Memoized.prototype.clear = clearMemoized;
1317
+ Memoized.prototype.delete = deleteMemoizedValue;
1318
+ Memoized.prototype.get = getMemoizedValue;
1319
+ Memoized.prototype.has = hasMemoizedValue;
1320
+ Memoized.prototype.run = runMemoized;
1321
+ Object.defineProperties(Memoized.prototype, {
1322
+ maximum: {
1323
+ enumerable: true,
1324
+ get: getMemoizedMaximum
1325
+ },
1326
+ size: {
1327
+ enumerable: true,
1328
+ get: getMemoizedSize
1329
+ }
1330
+ });
1331
+ function clearMemoized() {
1332
+ this[MEMOIZED_SYMBOL].cache.clear();
1333
+ }
1334
+ function deleteMemoizedValue(key) {
1335
+ return this[MEMOIZED_SYMBOL].cache.delete(key);
1336
+ }
1337
+ function createGetter(state, callback) {
1338
+ return (...parameters) => {
1339
+ const key = state.options.cacheKey?.(...parameters) ?? (parameters.length === 1 ? parameters[0] : join(parameters.map(getString), MEMOIZED_KEY_SEPARATOR));
1340
+ if (state.cache.has(key)) return state.cache.get(key);
1341
+ const value = callback(...parameters);
1342
+ state.cache.set(key, value);
1343
+ return value;
1344
+ };
1345
+ }
1346
+ function createMemoizationOptions(input) {
976
1347
  const { cacheKey, cacheSize } = isPlainObject(input) ? input : {};
977
1348
  return {
978
1349
  cacheKey: typeof cacheKey === "function" ? cacheKey : void 0,
979
- cacheSize: typeof cacheSize === "number" && cacheSize > 0 ? cacheSize : DEFAULT_CACHE_SIZE
1350
+ cacheSize: getNumberOrDefault(cacheSize, MEMOIZED_CACHE_SIZE_DEFAULT)
980
1351
  };
981
1352
  }
1353
+ function getMemoizedMaximum() {
1354
+ return this[MEMOIZED_SYMBOL].cache.maximum;
1355
+ }
1356
+ function getMemoizedSize() {
1357
+ return this[MEMOIZED_SYMBOL].cache.size;
1358
+ }
1359
+ function getMemoizedValue(key) {
1360
+ return this[MEMOIZED_SYMBOL].cache.get(key);
1361
+ }
1362
+ function hasMemoizedValue(key) {
1363
+ return this[MEMOIZED_SYMBOL].cache.has(key);
1364
+ }
982
1365
  /**
983
1366
  * Memoize a function, caching and retrieving results based on the first parameter
1367
+ *
984
1368
  * @param callback Callback to memoize
985
1369
  * @param options Memoization options
986
- * @returns Memoized instance
1370
+ * @returns _Memoized_ instance
987
1371
  */
988
1372
  function memoize(callback, options) {
989
- return new Memoized(callback, getMemoizationOptions(options));
1373
+ if (typeof callback !== "function") throw new TypeError(MEMOIZED_CALLBACK);
1374
+ return new Memoized(callback, createMemoizationOptions(options));
1375
+ }
1376
+ function runMemoized(...parameters) {
1377
+ return this[MEMOIZED_SYMBOL].getter(...parameters);
990
1378
  }
991
- const DEFAULT_CACHE_SIZE = 1024;
992
- const SEPARATOR = "_";
1379
+ const MEMOIZED_CACHE_SIZE_DEFAULT = 1024;
1380
+ const MEMOIZED_CALLBACK = "Memoized requires a callback function";
1381
+ const MEMOIZED_KEY_SEPARATOR = "_";
1382
+ const MEMOIZED_SYMBOL = Symbol("memoized");
993
1383
  //#endregion
994
- //#region node_modules/@oscarpalmer/atoms/dist/string/case.mjs
1384
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/string/case.mjs
995
1385
  /**
996
1386
  * Convert a string to camel case _(thisIsCamelCase)_
1387
+ *
997
1388
  * @param value String to convert
998
1389
  * @returns Camel-cased string
999
1390
  */
1000
1391
  function camelCase(value) {
1001
- return toCase(CASE_CAMEL, value, true, false);
1392
+ return toCase(STRING_CASE_CAMEL, value, true, false);
1002
1393
  }
1003
1394
  /**
1004
1395
  * Capitalize the first letter of a string _(and lowercase the rest)_
1396
+ *
1005
1397
  * @param value String to capitalize
1006
1398
  * @returns Capitalized string
1007
1399
  */
@@ -1012,11 +1404,12 @@ function capitalize(value) {
1012
1404
  }
1013
1405
  /**
1014
1406
  * Convert a string to kebab case _(this-is-kebab-case)_
1407
+ *
1015
1408
  * @param value String to convert
1016
1409
  * @returns Kebab-cased string
1017
1410
  */
1018
1411
  function kebabCase(value) {
1019
- return toCase(CASE_KEBAB, value, false, false);
1412
+ return toCase(STRING_CASE_KEBAB, value, false, false);
1020
1413
  }
1021
1414
  function toCase(type, value, capitalizeAny, capitalizeFirst) {
1022
1415
  caseMemoizers[type] ??= memoize(toCaseCallback.bind({
@@ -1034,7 +1427,7 @@ function toCaseCallback(value) {
1034
1427
  const partsLength = parts.length;
1035
1428
  const cased = [];
1036
1429
  for (let partIndex = 0; partIndex < partsLength; partIndex += 1) {
1037
- const items = parts[partIndex].replace(EXPRESSION_ACRONYM, (full, one, two, three) => three === S ? full : `${one}-${two}${three}`).replace(EXPRESSION_CAMEL_CASE, REPLACEMENT_CAMEL_CASE).split("-");
1430
+ const items = parts[partIndex].replace(STRING_EXPRESSION_ACRONYM, (full, one, two, three) => three === STRING_S ? full : `${one}-${two}${three}`).replace(STRING_EXPRESSION_CAMEL_CASE, STRING_REPLACEMENT_CAMEL_CASE).split("-");
1038
1431
  const itemsLength = items.length;
1039
1432
  const partResult = [];
1040
1433
  let itemCount = 0;
@@ -1049,41 +1442,72 @@ function toCaseCallback(value) {
1049
1442
  }
1050
1443
  return join(cased, delimiters[type]);
1051
1444
  }
1052
- const CASE_CAMEL = "camel";
1053
- const CASE_KEBAB = "kebab";
1054
- const CASE_PASCAL = "pascal";
1055
- const CASE_SNAKE = "snake";
1056
- const DELIMTER_EMPTY = "";
1057
- const DELIMITER_HYPHEN = "-";
1058
- const DELIMITER_UNDERSCORE = "_";
1059
- const EXPRESSION_CAMEL_CASE = /(\p{Ll})(\p{Lu})/gu;
1060
- const EXPRESSION_ACRONYM = /(\p{Lu}*)(\p{Lu})(\p{Ll}+)/gu;
1061
- const REPLACEMENT_CAMEL_CASE = "$1-$2";
1062
- const S = "s";
1445
+ const STRING_CASE_CAMEL = "camel";
1446
+ const STRING_CASE_KEBAB = "kebab";
1447
+ const STRING_CASE_PASCAL = "pascal";
1448
+ const STRING_CASE_SNAKE = "snake";
1449
+ const STRING_DELIMTER_EMPTY = "";
1450
+ const STRING_DELIMITER_HYPHEN = "-";
1451
+ const STRING_DELIMITER_UNDERSCORE = "_";
1452
+ const STRING_EXPRESSION_CAMEL_CASE = /(\p{Ll})(\p{Lu})/gu;
1453
+ const STRING_EXPRESSION_ACRONYM = /(\p{Lu}*)(\p{Lu})(\p{Ll}+)/gu;
1454
+ const STRING_REPLACEMENT_CAMEL_CASE = "$1-$2";
1455
+ const STRING_S = "s";
1063
1456
  const caseMemoizers = {};
1064
1457
  const delimiters = {
1065
- [CASE_CAMEL]: DELIMTER_EMPTY,
1066
- [CASE_KEBAB]: DELIMITER_HYPHEN,
1067
- [CASE_PASCAL]: DELIMTER_EMPTY,
1068
- [CASE_SNAKE]: DELIMITER_UNDERSCORE
1458
+ [STRING_CASE_CAMEL]: STRING_DELIMTER_EMPTY,
1459
+ [STRING_CASE_KEBAB]: STRING_DELIMITER_HYPHEN,
1460
+ [STRING_CASE_PASCAL]: STRING_DELIMTER_EMPTY,
1461
+ [STRING_CASE_SNAKE]: STRING_DELIMITER_UNDERSCORE
1069
1462
  };
1070
1463
  let memoizedCapitalize;
1071
1464
  //#endregion
1465
+ //#region node_modules/@oscarpalmer/toretto/dist/internal/property.mjs
1466
+ function getPropertyValue(element, name, value) {
1467
+ if (isInputElement(element) && name === "value") return getString(value);
1468
+ return value;
1469
+ }
1470
+ function updateProperty(element, name, value, dispatch) {
1471
+ let property = name;
1472
+ if (!(property in element)) property = camelCase(name);
1473
+ const next = getPropertyValue(element, name, value);
1474
+ if (!(property in element) || Object.is(element[property], next)) return;
1475
+ element[property] = next;
1476
+ const event = dispatch && elementEvents[element.tagName]?.[property];
1477
+ if (typeof event === "string") element.dispatchEvent(new Event(event, {
1478
+ bubbles: true,
1479
+ cancelable: true
1480
+ }));
1481
+ }
1482
+ const elementEvents = {
1483
+ DETAILS: { open: "toggle" },
1484
+ INPUT: {
1485
+ checked: "change",
1486
+ value: "input"
1487
+ },
1488
+ SELECT: { value: "change" },
1489
+ TEXTAREA: { value: "input" }
1490
+ };
1491
+ //#endregion
1072
1492
  //#region node_modules/@oscarpalmer/toretto/dist/internal/element-value.mjs
1493
+ function getValueForAttribute(value, json) {
1494
+ if (typeof value === "string") return value;
1495
+ return json ? JSON.stringify(value) : getString(value);
1496
+ }
1073
1497
  function ignoreSetAttribute(element, name) {
1074
1498
  if (element instanceof HTMLTextAreaElement && name === "value") return true;
1075
1499
  return false;
1076
1500
  }
1077
1501
  function normalizeKey(key, style) {
1078
- return style && key.startsWith(CSS_VARIABLE_PREFIX) ? key : kebabCase(key);
1502
+ return style && key.startsWith(CSS_VARIABLE_PREFIX$1) ? key : kebabCase(key);
1079
1503
  }
1080
1504
  function setElementValue(element, first, second, third, callback, style) {
1081
- if (!isHTMLOrSVGElement(element)) return;
1505
+ if (!(element instanceof Element)) return;
1082
1506
  if (typeof first === "string") setElementValues(element, first, second, third, callback, style);
1083
1507
  else if (isAttribute(first)) setElementValues(element, first.name, first.value, third, callback, style);
1084
1508
  }
1085
1509
  function setElementValues(element, first, second, third, callback, style) {
1086
- if (!isHTMLOrSVGElement(element)) return;
1510
+ if (!(element instanceof Element)) return;
1087
1511
  const dispatch = third !== false;
1088
1512
  if (typeof first === "string") {
1089
1513
  callback(element, normalizeKey(first, style), second, dispatch);
@@ -1101,38 +1525,11 @@ function setElementValues(element, first, second, third, callback, style) {
1101
1525
  if (typeof entry === "object" && typeof entry?.name === "string") callback(element, normalizeKey(entry.name, style), entry.value, dispatch);
1102
1526
  }
1103
1527
  }
1104
- function updateElementValue(element, key, value, set, remove, isBoolean, json) {
1105
- if (isBoolean ? value == null : isNullableOrWhitespace(value)) remove.call(element, key);
1106
- else if (!ignoreSetAttribute(element, key)) set.call(element, key, json ? JSON.stringify(value) : getString(value));
1107
- }
1108
- const CSS_VARIABLE_PREFIX = "--";
1109
- //#endregion
1110
- //#region node_modules/@oscarpalmer/toretto/dist/internal/property.mjs
1111
- function getPropertyValue(element, name, value) {
1112
- if (isInputElement(element) && name === "value") return getString(value);
1113
- return value;
1114
- }
1115
- function updateProperty(element, name, value, dispatch) {
1116
- let property = name;
1117
- if (!(property in element)) property = camelCase(name);
1118
- const next = getPropertyValue(element, name, value);
1119
- if (!(property in element) || Object.is(element[property], next)) return;
1120
- element[property] = next;
1121
- const event = dispatch && elementEvents[element.tagName]?.[property];
1122
- if (typeof event === "string") element.dispatchEvent(new Event(event, {
1123
- bubbles: true,
1124
- cancelable: true
1125
- }));
1528
+ function updateElementValue(element, key, value, set, remove, json) {
1529
+ if (value == null) remove.call(element, key);
1530
+ else if (!ignoreSetAttribute(element, key)) set.call(element, key, getValueForAttribute(value, json));
1126
1531
  }
1127
- const elementEvents = {
1128
- DETAILS: { open: "toggle" },
1129
- INPUT: {
1130
- checked: "change",
1131
- value: "input"
1132
- },
1133
- SELECT: { value: "change" },
1134
- TEXTAREA: { value: "input" }
1135
- };
1532
+ const CSS_VARIABLE_PREFIX$1 = "--";
1136
1533
  //#endregion
1137
1534
  //#region node_modules/@oscarpalmer/toretto/dist/internal/attribute.mjs
1138
1535
  function badAttributeHandler(name, value) {
@@ -1184,7 +1581,7 @@ function updateAttribute(element, name, value, dispatch) {
1184
1581
  const isBoolean = booleanAttributesSet.has(lowerCaseName);
1185
1582
  const next = isBoolean ? value === true || typeof value === "string" && (value === "" || value.toLowerCase() === lowerCaseName) : value == null ? "" : value;
1186
1583
  if (isBoolean || dispatchedAttributes.has(name)) updateProperty(element, name, next, dispatch);
1187
- updateElementValue(element, name, isBoolean ? next ? "" : null : value, element.setAttribute, element.removeAttribute, isBoolean, false);
1584
+ updateElementValue(element, name, isBoolean ? next ? "" : null : value, element.setAttribute, element.removeAttribute, false);
1188
1585
  }
1189
1586
  const EXPRESSION_CLOBBERED_NAME = /^(id|name)$/i;
1190
1587
  const EXPRESSION_DATA_OR_SCRIPT = /^(?:data|\w+script):/i;
@@ -1224,7 +1621,7 @@ const booleanAttributes = Object.freeze([
1224
1621
  "selected"
1225
1622
  ]);
1226
1623
  const booleanAttributesSet = new Set(booleanAttributes);
1227
- const dispatchedAttributes = new Set([
1624
+ const dispatchedAttributes = /* @__PURE__ */ new Set([
1228
1625
  "checked",
1229
1626
  "open",
1230
1627
  "value"
@@ -1238,12 +1635,10 @@ function setAttribute$1(element, first, second, third) {
1238
1635
  }
1239
1636
  //#endregion
1240
1637
  //#region node_modules/@oscarpalmer/toretto/dist/html/sanitize.mjs
1241
- function handleElement(element, depth) {
1242
- if (depth === 0) {
1243
- const removable = [...element.querySelectorAll(REMOVE_SELECTOR)];
1244
- const { length } = removable;
1245
- for (let index = 0; index < length; index += 1) removable[index].remove();
1246
- }
1638
+ function handleElement(element) {
1639
+ const removable = [...element.querySelectorAll(REMOVE_SELECTOR)];
1640
+ const { length } = removable;
1641
+ for (let index = 0; index < length; index += 1) removable[index].remove();
1247
1642
  sanitizeAttributes(element, [...element.attributes]);
1248
1643
  }
1249
1644
  /**
@@ -1265,43 +1660,45 @@ function sanitizeAttributes(element, attributes) {
1265
1660
  else if (_isInvalidBooleanAttribute(name, value, false)) setAttribute$1(element, name, true);
1266
1661
  }
1267
1662
  }
1268
- function sanitizeNodes(nodes, depth) {
1269
- const actual = nodes.filter((node) => node instanceof Node);
1663
+ function sanitizeNodes(nodes) {
1664
+ const actual = [];
1270
1665
  let { length } = nodes;
1271
1666
  for (let index = 0; index < length; index += 1) {
1272
- const node = actual[index];
1667
+ const node = nodes[index];
1273
1668
  let remove = isClobbered(node);
1274
1669
  if (!remove) switch (node.nodeType) {
1275
1670
  case Node.ELEMENT_NODE:
1276
- handleElement(node, depth);
1671
+ handleElement(node);
1277
1672
  break;
1278
1673
  case Node.COMMENT_NODE:
1279
1674
  remove = COMMENT_HARMFUL.test(node.data);
1280
1675
  break;
1281
1676
  case Node.DOCUMENT_TYPE_NODE:
1282
- case Node.PROCESSING_INSTRUCTION_NODE:
1283
- remove = true;
1284
- break;
1677
+ case Node.PROCESSING_INSTRUCTION_NODE: remove = true;
1285
1678
  }
1286
1679
  if (remove) {
1287
1680
  removeNode(node);
1288
- actual.splice(index, 1);
1289
- index -= 1;
1290
- length -= 1;
1291
1681
  continue;
1292
1682
  }
1293
- if (node.hasChildNodes()) sanitizeNodes([...node.childNodes], depth + 1);
1683
+ if (node.hasChildNodes()) sanitizeNodes(node.childNodes);
1684
+ actual.push(node);
1294
1685
  }
1295
- return nodes;
1686
+ return actual;
1296
1687
  }
1297
1688
  const COMMENT_HARMFUL = /<[/\w]/g;
1298
1689
  const REMOVE_SELECTOR = "script, toretto-temporary";
1299
1690
  //#endregion
1300
1691
  //#region node_modules/@oscarpalmer/toretto/dist/html/index.mjs
1692
+ /**
1693
+ * Clear cache of template elements
1694
+ */
1695
+ function clearHtmlTemplates() {
1696
+ templates.clear();
1697
+ }
1301
1698
  function createHtml(value) {
1302
1699
  const parsed = getParser().parseFromString(getHtml(value), PARSE_TYPE_HTML);
1303
1700
  parsed.body.normalize();
1304
- sanitizeNodes([parsed.body], 0);
1701
+ sanitizeNodes([parsed.body]);
1305
1702
  return parsed.body.innerHTML;
1306
1703
  }
1307
1704
  function createTemplate(value, options) {
@@ -1377,28 +1774,23 @@ function hasNodes(value) {
1377
1774
  if (value instanceof HTMLCollection || value instanceof NodeList) return true;
1378
1775
  return Array.isArray(value) && value.some((item) => item instanceof Node);
1379
1776
  }
1380
- function html$1(first, ...second) {
1777
+ function html(first, ...second) {
1381
1778
  if (isTagged(first)) {
1382
1779
  const tagged = getTagged(first, second);
1383
1780
  return getNodes(tagged.template, getOptions$1(), tagged.nodes);
1384
1781
  }
1385
1782
  return getNodes(first, getOptions$1(second[0]));
1386
1783
  }
1784
+ function isTagged(value) {
1785
+ return Array.isArray(value) && Array.isArray(value.raw);
1786
+ }
1387
1787
  /**
1388
- * Clear cache of template elements
1389
- */
1390
- html$1.clear = () => {
1391
- templates.clear();
1392
- };
1393
- /**
1394
- * Remove cached template element for an HTML string or id
1395
- * @param template HTML string or id for a template element
1788
+ * Remove cached template element for an _HTML_ string or _ID_
1789
+ *
1790
+ * @param template _HTML_ string or ID for a template element
1396
1791
  */
1397
- html$1.remove = (template) => {
1792
+ function removeHtmlTemplate(template) {
1398
1793
  templates.delete(template);
1399
- };
1400
- function isTagged(value) {
1401
- return Array.isArray(value) && Array.isArray(value.raw);
1402
1794
  }
1403
1795
  function replaceComments(origin, replacements) {
1404
1796
  const nodes = [...origin];
@@ -1422,16 +1814,14 @@ const TEMPLATE_TAG = "template";
1422
1814
  const TEMPORARY_ELEMENT = "<toretto-temporary></toretto-temporary>";
1423
1815
  const templates = new SizedMap(128);
1424
1816
  let parser;
1425
- window.templates = templates;
1817
+ html.clear = clearHtmlTemplates;
1818
+ html.remove = removeHtmlTemplate;
1426
1819
  //#endregion
1427
1820
  //#region src/constants.ts
1428
1821
  const ARRAY_COMPARISON_ADDED = "added";
1429
1822
  const ARRAY_COMPARISON_DISSIMILAR = "dissimilar";
1430
1823
  const ARRAY_COMPARISON_REMOVED = "removed";
1431
- const CHANGE_INPUTS = new Set(["checkbox", "radio"]);
1432
- const ERROR_FRAGMENT = "Fragment function must return a Fragment instance";
1433
- const ERROR_IDENTIFIER_DUPLICATE = "Duplicate identifier found: '<>'";
1434
- const ERROR_IDENTIFIER_TYPE = "Identifier cannot be null or undefined";
1824
+ const CHANGE_INPUTS = /* @__PURE__ */ new Set(["checkbox", "radio"]);
1435
1825
  const EVENT_CHANGE = "change";
1436
1826
  const EVENT_INPUT = "input";
1437
1827
  const EVENT_SUBMIT = "submit";
@@ -1457,8 +1847,16 @@ const EXPRESSION_EVENT_OPTIONS_CAPTURE = /^c(?:apture)$/i;
1457
1847
  const EXPRESSION_EVENT_OPTIONS_ONCE = /^o(?:nce)$/i;
1458
1848
  const EXPRESSION_EVENT_PREFIX = /^@/;
1459
1849
  const EXPRESSION_TEXTAREA_VALUE = /(?:<|&lt;)!--abydon\.(\d+)--(?:>|&gt;)/;
1460
- const NAME_FRAGMENT = "$fragment";
1461
- const NAME_FRAGMENTS = "$fragments";
1850
+ const MESSAGE_FRAGMENT_VALUE = "Fragment template must be a string or a template strings array";
1851
+ const MESSAGE_FRAGMENTS_FRAGMENT_RESULT = "Fragment function must return a Fragment instance";
1852
+ const MESSAGE_FRAGMENTS_FRAGMENT_TYPE = "Fragment handler must be a function";
1853
+ const MESSAGE_FRAGMENTS_IDENTIFIER_RESULT_DUPLICATE = "Duplicate identifier found: '<>'";
1854
+ const MESSAGE_FRAGMENTS_IDENTIFIER_RESULT_TYPE = "Identifier cannot be null or undefined";
1855
+ const MESSAGE_FRAGMENTS_IDENTIFIER_TYPE = "Identifier handler must be a function";
1856
+ const MESSAGE_FRAGMENTS_VALUE = "Fragments array must be a reactive array";
1857
+ const NAME_FRAGMENT = "fragment";
1858
+ const NAME_FRAGMENTS = "fragments";
1859
+ const SYMBOL = Symbol("abydon");
1462
1860
  const WHITESPACE = /\s+/g;
1463
1861
  //#endregion
1464
1862
  //#region src/helpers/index.ts
@@ -1471,6 +1869,7 @@ function compareArrays(first, second) {
1471
1869
  }
1472
1870
  /**
1473
1871
  * Is the value a _Fragment_?
1872
+ *
1474
1873
  * @param value Value to check
1475
1874
  * @returns `true` if the value is a _Fragment_, otherwise `false`
1476
1875
  */
@@ -1479,6 +1878,7 @@ function isFragment(value) {
1479
1878
  }
1480
1879
  /**
1481
1880
  * Is the value a _Fragments_ instance?
1881
+ *
1482
1882
  * @param value Value to check
1483
1883
  * @returns `true` if the value is a _Fragments_ instance, otherwise `false`
1484
1884
  */
@@ -1486,7 +1886,7 @@ function isFragments(value) {
1486
1886
  return isNamed(value, NAME_FRAGMENTS);
1487
1887
  }
1488
1888
  function isNamed(value, name) {
1489
- return typeof value === "object" && value != null && name in value && value[name] === true;
1889
+ return typeof value === "object" && value !== null && SYMBOL in value && value[SYMBOL].name === name;
1490
1890
  }
1491
1891
  function setComputedValue(data, callback, after) {
1492
1892
  const computation = computed(callback);
@@ -1495,25 +1895,50 @@ function setComputedValue(data, callback, after) {
1495
1895
  }
1496
1896
  //#endregion
1497
1897
  //#region src/fragments.ts
1498
- var Fragments = class {
1499
- #state;
1500
- constructor(items, identify, fragment) {
1501
- Object.defineProperty(this, NAME_FRAGMENTS, { value: true });
1502
- this.#state = {
1503
- fragment,
1504
- identify,
1505
- array: items,
1506
- instances: {},
1507
- mapped: array([]),
1508
- subscriber: void 0
1509
- };
1510
- fragmentsStates.set(this, this.#state);
1511
- initializeFragments(this.#state);
1512
- }
1513
- };
1514
- function handleFragments(item, remove) {
1515
- const state = isFragments(item) ? fragmentsStates.get(item) : item;
1516
- (remove ? removeFragments : initializeFragments)(state);
1898
+ function Fragments(items, identify, fragment) {
1899
+ this[SYMBOL] = {
1900
+ fragment,
1901
+ identify,
1902
+ array: items,
1903
+ instances: {},
1904
+ mapped: array([]),
1905
+ name: NAME_FRAGMENTS,
1906
+ subscription: void 0
1907
+ };
1908
+ initializeFragments.call(this);
1909
+ }
1910
+ Fragments.prototype.remove = removeFragments;
1911
+ /**
1912
+ * Create a _Fragments_ instance from a reactive array
1913
+ *
1914
+ * _A Fragments instance can be used to efficiently render a list of items that may change over time, using unique identifiers to track each item, only adding, removing, or updating each related Fragment._
1915
+ *
1916
+ * @example
1917
+ * ```ts
1918
+ * const fruits = array(['Apple', 'Banana', 'Cherry']);
1919
+ * const items = fragments(
1920
+ * fruits,
1921
+ * fruit => fruit, // Identifies a unique item
1922
+ * fruit => html`<p>${fruit}</p>`, // Creates a Fragment from an item
1923
+ * );
1924
+ * html`${items}`.appendTo(document.body) // Renders '<p>Apple</p><p>Banana</p><p>Cherry</p>'
1925
+ * fruits.push(['Date', 'Elderberry', 'Fig']); // Appends '<p>Date</p><p>Elderberry</p><p>Fig</p>'
1926
+ * // without re-rendering the existing Fragments
1927
+ * ```
1928
+ *
1929
+ * @param array Reactive array
1930
+ * @param identify Function to identify item uniquely _(non-nullable)_
1931
+ * @param fragment Function to create _Fragment_ from item
1932
+ * @returns _Fragments_
1933
+ */
1934
+ function fragments(array, identify, fragment) {
1935
+ if (!isReactiveArray(array)) throw new TypeError(MESSAGE_FRAGMENTS_VALUE);
1936
+ if (typeof identify !== "function") throw new TypeError(MESSAGE_FRAGMENTS_IDENTIFIER_TYPE);
1937
+ if (typeof fragment !== "function") throw new TypeError(MESSAGE_FRAGMENTS_FRAGMENT_TYPE);
1938
+ return new Fragments(array, identify, fragment);
1939
+ }
1940
+ function handleFragments(instance, remove) {
1941
+ (remove ? removeFragments : initializeFragments).call(instance);
1517
1942
  }
1518
1943
  function handleItems(state, items) {
1519
1944
  const keys = /* @__PURE__ */ new Set();
@@ -1522,13 +1947,13 @@ function handleItems(state, items) {
1522
1947
  for (let index = 0; index < length; index += 1) {
1523
1948
  const item = items[index];
1524
1949
  const identifier = state.identify(item);
1525
- if (identifier == null) throw new TypeError(ERROR_IDENTIFIER_TYPE);
1950
+ if (identifier == null) throw new TypeError(MESSAGE_FRAGMENTS_IDENTIFIER_RESULT_TYPE);
1526
1951
  const key = getString(identifier);
1527
- if (keys.has(key)) throw new Error(ERROR_IDENTIFIER_DUPLICATE.replace("<>", key));
1952
+ if (keys.has(key)) throw new Error(MESSAGE_FRAGMENTS_IDENTIFIER_RESULT_DUPLICATE.replace("<>", key));
1528
1953
  let instance = state.instances[key];
1529
1954
  if (instance == null) {
1530
1955
  instance = state.fragment(item);
1531
- if (!isFragment(instance)) throw new Error(ERROR_FRAGMENT);
1956
+ if (!isFragment(instance)) throw new Error(MESSAGE_FRAGMENTS_FRAGMENT_RESULT);
1532
1957
  }
1533
1958
  instance.configure({ identifier: key });
1534
1959
  state.instances[key] = instance;
@@ -1538,15 +1963,18 @@ function handleItems(state, items) {
1538
1963
  state.mapped.set(mapped);
1539
1964
  updateFragments(state, keys);
1540
1965
  }
1541
- function initializeFragments(state) {
1542
- state.subscriber ??= state.array.subscribe((items) => {
1966
+ function initializeFragments() {
1967
+ const state = this[SYMBOL];
1968
+ state.subscription ??= state.array.subscribe((items) => {
1543
1969
  handleItems(state, items);
1544
1970
  });
1545
1971
  }
1546
- function removeFragments(state) {
1547
- state.subscriber?.();
1972
+ function removeFragments() {
1973
+ const state = this[SYMBOL];
1974
+ state.subscription?.unsubscribe();
1975
+ state.mapped.set([]);
1548
1976
  updateFragments(state);
1549
- state.subscriber = void 0;
1977
+ state.subscription = void 0;
1550
1978
  }
1551
1979
  function updateFragments(state, active) {
1552
1980
  const next = {};
@@ -1556,12 +1984,29 @@ function updateFragments(state, active) {
1556
1984
  for (let index = 0; index < length; index += 1) {
1557
1985
  const key = keys[index];
1558
1986
  if (active?.has(key)) next[key] = previous[key];
1559
- else previous[key].remove();
1987
+ else if (active == null) previous[key].remove();
1560
1988
  }
1561
1989
  state.instances = next;
1562
1990
  active?.clear();
1563
1991
  }
1564
- const fragmentsStates = /* @__PURE__ */ new WeakMap();
1992
+ //#endregion
1993
+ //#region node_modules/@oscarpalmer/toretto/dist/is.mjs
1994
+ /**
1995
+ * Is the value a child node?
1996
+ *
1997
+ * @param value Value to check
1998
+ * @returns `true` if it's a child node, otherwise `false`
1999
+ */
2000
+ function isChildNode(value) {
2001
+ return value instanceof Node && CHILD_NODE_TYPES.has(value.nodeType);
2002
+ }
2003
+ const CHILD_NODE_TYPES = /* @__PURE__ */ new Set([
2004
+ Node.ELEMENT_NODE,
2005
+ Node.TEXT_NODE,
2006
+ Node.PROCESSING_INSTRUCTION_NODE,
2007
+ Node.COMMENT_NODE,
2008
+ Node.DOCUMENT_TYPE_NODE
2009
+ ]);
1565
2010
  //#endregion
1566
2011
  //#region src/helpers/dom.ts
1567
2012
  function createNodes(value) {
@@ -1580,10 +2025,58 @@ function replaceNodes(from, to) {
1580
2025
  return to;
1581
2026
  }
1582
2027
  //#endregion
2028
+ //#region node_modules/@oscarpalmer/toretto/dist/internal/aria.mjs
2029
+ /**
2030
+ * List of _ARIA_ attributes that can be treated as boolean values
2031
+ */
2032
+ const ariaBooleanAttributes = Object.freeze([
2033
+ "aria-atomic",
2034
+ "aria-busy",
2035
+ "aria-checked",
2036
+ "aria-current",
2037
+ "aria-disabled",
2038
+ "aria-expanded",
2039
+ "aria-haspopup",
2040
+ "aria-hidden",
2041
+ "aria-invalid",
2042
+ "aria-modal",
2043
+ "aria-multiline",
2044
+ "aria-multiselectable",
2045
+ "aria-pressed",
2046
+ "aria-readonly",
2047
+ "aria-required",
2048
+ "aria-selected"
2049
+ ]);
2050
+ new Set(ariaBooleanAttributes);
2051
+ /**
2052
+ * List of _ARIA_ attributes that can be treated as numerical values
2053
+ */
2054
+ const ariaNumericalAttributes = Object.freeze([
2055
+ "aria-colcount",
2056
+ "aria-colindex",
2057
+ "aria-colspan",
2058
+ "aria-level",
2059
+ "aria-posinset",
2060
+ "aria-rowcount",
2061
+ "aria-rowindex",
2062
+ "aria-rowspan",
2063
+ "aria-setsize",
2064
+ "aria-valuemax",
2065
+ "aria-valuemin",
2066
+ "aria-valuenow"
2067
+ ]);
2068
+ new Set(ariaNumericalAttributes);
2069
+ //#endregion
1583
2070
  //#region node_modules/@oscarpalmer/toretto/dist/internal/get-value.mjs
1584
2071
  function getBoolean(value, defaultValue) {
1585
2072
  return typeof value === "boolean" ? value : defaultValue ?? false;
1586
2073
  }
2074
+ function getStyleValue$1(element, property, computed) {
2075
+ if (property.startsWith(CSS_VARIABLE_PREFIX)) return element.style.getPropertyValue(property);
2076
+ const name = camelCase(property);
2077
+ return computed ? getComputedStyle(element)[name] : element.style[name];
2078
+ }
2079
+ const CSS_VARIABLE_PREFIX = "--";
1587
2080
  //#endregion
1588
2081
  //#region node_modules/@oscarpalmer/toretto/dist/event/delegation.mjs
1589
2082
  function addDelegatedHandler(doc, type, name, passive) {
@@ -1600,7 +2093,7 @@ function addDelegatedListener(target, type, name, listener, passive) {
1600
2093
  };
1601
2094
  }
1602
2095
  function delegatedEventHandler(event) {
1603
- const key = `${EVENT_PREFIX}${event.type}${this ? EVENT_SUFFIX_PASSIVE : EVENT_SUFFIX_ACTIVE}`;
2096
+ const key = `@${event.type}${this ? EVENT_SUFFIX_PASSIVE : EVENT_SUFFIX_ACTIVE}`;
1604
2097
  const items = event.composedPath();
1605
2098
  const { length } = items;
1606
2099
  let cancelled = false;
@@ -1635,7 +2128,7 @@ function delegatedEventHandler(event) {
1635
2128
  }
1636
2129
  }
1637
2130
  function getDelegatedName(target, type, options) {
1638
- if (isEventTarget(target) && EVENT_TYPES.has(type) && !options.capture && !options.once && options.signal == null) return `${EVENT_PREFIX}${type}${options.passive ? EVENT_SUFFIX_PASSIVE : EVENT_SUFFIX_ACTIVE}`;
2131
+ if (isEventTarget(target) && EVENT_TYPES.has(type) && !options.capture && !options.once && options.signal == null) return `@${type}${options.passive ? EVENT_SUFFIX_PASSIVE : EVENT_SUFFIX_ACTIVE}`;
1639
2132
  }
1640
2133
  function removeDelegatedListener(target, name, listener) {
1641
2134
  const handlers = target[name];
@@ -1645,10 +2138,9 @@ function removeDelegatedListener(target, name, listener) {
1645
2138
  return true;
1646
2139
  }
1647
2140
  const DELEGATED = /* @__PURE__ */ new Set();
1648
- const EVENT_PREFIX = "@";
1649
2141
  const EVENT_SUFFIX_ACTIVE = ":active";
1650
2142
  const EVENT_SUFFIX_PASSIVE = ":passive";
1651
- const EVENT_TYPES = new Set([
2143
+ const EVENT_TYPES = /* @__PURE__ */ new Set([
1652
2144
  "beforeinput",
1653
2145
  "click",
1654
2146
  "dblclick",
@@ -1730,27 +2222,89 @@ function mapEvent(element, name, value) {
1730
2222
  }
1731
2223
  //#endregion
1732
2224
  //#region node_modules/@oscarpalmer/toretto/dist/style.mjs
2225
+ function StyleToggler(element, styles) {
2226
+ this[STYLE_SYMBOL] = {
2227
+ element,
2228
+ styles,
2229
+ active: false,
2230
+ keys: Object.keys(styles),
2231
+ values: {}
2232
+ };
2233
+ }
2234
+ StyleToggler.prototype.remove = removeStyleTogglerValues;
2235
+ StyleToggler.prototype.set = setStyleTogglerValues;
2236
+ /**
2237
+ * Get styles from an element
2238
+ *
2239
+ * @param element Element to get styles from
2240
+ * @param names Styles to get
2241
+ * @param computed Get computed styles? _(defaults to `false`)_
2242
+ * @returns Style values
2243
+ */
2244
+ function getStyles(element, first, second) {
2245
+ if (!(element instanceof Element)) return {};
2246
+ if (first == null || typeof first === "boolean") return first === true ? getComputedStyle(element) : element.style;
2247
+ const { length } = first;
2248
+ const styles = {};
2249
+ for (let index = 0; index < length; index += 1) {
2250
+ const name = first[index];
2251
+ if (typeof name === "string") styles[name] = getStyleValue$1(element, name, second === true);
2252
+ }
2253
+ return styles;
2254
+ }
2255
+ function removeStyleTogglerValues() {
2256
+ toggleStyleValues(this, false);
2257
+ }
1733
2258
  /**
1734
2259
  * Set a style on an element
2260
+ *
1735
2261
  * @param element Element to set the style on
1736
- * @param property Style name
2262
+ * @param name Style name
1737
2263
  * @param value Style value
1738
2264
  */
1739
- function setStyle(element, property, value) {
1740
- setElementValues(element, property, value, null, updateStyleProperty, true);
2265
+ function setStyle(element, name, value) {
2266
+ setElementValues(element, name, value, null, updateStyleProperty, true);
2267
+ }
2268
+ function setStyleTogglerValues() {
2269
+ toggleStyleValues(this, true);
2270
+ }
2271
+ /**
2272
+ * Set styles on an element
2273
+ *
2274
+ * @param element Element to set the styles on
2275
+ * @param styles Styles to set
2276
+ */
2277
+ function setStyles(element, styles) {
2278
+ setElementValues(element, styles, null, null, updateStyleProperty, true);
2279
+ }
2280
+ function toggleStyleValues(instance, active) {
2281
+ const state = instance[STYLE_SYMBOL];
2282
+ if (state.active === active) return;
2283
+ state.active = active;
2284
+ let next;
2285
+ if (active) {
2286
+ state.values = getStyles(state.element, state.keys);
2287
+ next = state.styles;
2288
+ } else {
2289
+ next = { ...state.values };
2290
+ state.values = {};
2291
+ for (let index = 0; index < state.keys.length; index += 1) state.values[state.keys[index]] = void 0;
2292
+ }
2293
+ setStyles(state.element, next);
1741
2294
  }
1742
2295
  function updateStyleProperty(element, key, value) {
1743
- updateElementValue(element, key, value, function(property, style) {
1744
- if (property.startsWith(VARIABLE_PREFIX)) this.style.setProperty(property, getString(style));
1745
- else this.style[property] = getString(style);
1746
- }, function(property) {
1747
- if (property.startsWith(VARIABLE_PREFIX)) this.style.removeProperty(property);
1748
- else this.style[property] = "";
1749
- if (this.getAttribute(ATTRIBUTE_STYLE) === "") this.removeAttribute(ATTRIBUTE_STYLE);
1750
- }, false, false);
1751
- }
1752
- const ATTRIBUTE_STYLE = "style";
1753
- const VARIABLE_PREFIX = "--";
2296
+ updateElementValue(element, key, value, function(name, style) {
2297
+ if (name.startsWith(STYLE_VARIABLE_PREFIX)) this.style.setProperty(name, getString(style));
2298
+ else this.style[name] = getString(style);
2299
+ }, function(name) {
2300
+ if (name.startsWith(STYLE_VARIABLE_PREFIX)) this.style.removeProperty(name);
2301
+ else this.style[name] = "";
2302
+ if (this.getAttribute(STYLE_ATTRIBUTE) === "") this.removeAttribute(STYLE_ATTRIBUTE);
2303
+ }, false);
2304
+ }
2305
+ const STYLE_ATTRIBUTE = "style";
2306
+ const STYLE_SYMBOL = Symbol(STYLE_ATTRIBUTE);
2307
+ const STYLE_VARIABLE_PREFIX = "--";
1754
2308
  //#endregion
1755
2309
  //#region src/attribute/value.ts
1756
2310
  function getStyleValue(value, unit, isVariable) {
@@ -1769,9 +2323,7 @@ function setAttribute(data, element, name, value) {
1769
2323
  case EXPRESSION_ATTRIBUTE_STYLE_PREFIX.test(name):
1770
2324
  setStyleValues(data, element, name, value);
1771
2325
  return;
1772
- default:
1773
- setValue(data, element, name, value);
1774
- break;
2326
+ default: setValue(data, element, name, value);
1775
2327
  }
1776
2328
  }
1777
2329
  function setClassValues(data, element, name, value) {
@@ -1794,7 +2346,7 @@ function setValue(data, element, name, value) {
1794
2346
  });
1795
2347
  }
1796
2348
  function updateValue(data, value, updater) {
1797
- if (isReactive(value)) data.mora.subscribers.add(value.subscribe(updater));
2349
+ if (isReactive(value)) data.mora.subscriptions.add(value.subscribe(updater));
1798
2350
  else updater(value);
1799
2351
  }
1800
2352
  //#endregion
@@ -1819,16 +2371,14 @@ function mapAttributes(data, element, ignoreValue) {
1819
2371
  for (let index = 0; index < length; index += 1) {
1820
2372
  const { name, value } = attributes[index];
1821
2373
  const actualName = name.replace(EXPRESSION_ABYDON_ATTRIBUTE_PREFIX, "");
1822
- const actualValue = getValue(data, value);
1823
2374
  if (actualName !== name) element.removeAttribute(name);
1824
- if (actualName === "value" && ignoreValue) continue;
2375
+ if (isNullableOrWhitespace(value) || actualName === "value" && ignoreValue) continue;
2376
+ const actualValue = getValue(data, value);
1825
2377
  switch (true) {
1826
2378
  case EXPRESSION_EVENT_PREFIX.test(actualName):
1827
2379
  mapEvent(element, actualName, actualValue);
1828
2380
  break;
1829
- default:
1830
- mapAttributeValue(data, element, actualName, actualValue);
1831
- break;
2381
+ default: mapAttributeValue(data, element, actualName, actualValue);
1832
2382
  }
1833
2383
  }
1834
2384
  }
@@ -1849,8 +2399,10 @@ function addToArray(identifiers, items, nodes, added) {
1849
2399
  const { length } = next;
1850
2400
  for (let index = 0; index < length; index += 1) {
1851
2401
  const node = next[index];
1852
- if (!(added && identifiers.previous.set.has(node.identifier))) if (index === 0 && before) position.before(node.value);
1853
- else position.after(node.value);
2402
+ if (!(added && identifiers.previous.set.has(node.identifier))) {
2403
+ if (index === 0 && before) position.before(node.value);
2404
+ else position.after(node.value);
2405
+ }
1854
2406
  position = node.value;
1855
2407
  }
1856
2408
  }
@@ -1911,7 +2463,7 @@ function removeFragmentsItems(fragments) {
1911
2463
  function setArray(item, comment, value) {
1912
2464
  if (value.length === 0) return removeArray(item, comment);
1913
2465
  const { next, previous, template } = getArrayData(item, value);
1914
- if (template.empty || item.nodes == null || previous.array.some((identifier) => identifier == null)) {
2466
+ if (template.empty || item.nodes == null || item.fragments == null || previous.array.some((identifier) => identifier == null)) {
1915
2467
  const fragments = (item.fragments ?? []).slice();
1916
2468
  const result = {
1917
2469
  fragments: template.empty ? void 0 : template.items,
@@ -1924,7 +2476,7 @@ function setArray(item, comment, value) {
1924
2476
  next,
1925
2477
  previous
1926
2478
  }, {
1927
- fragments: item.fragments ?? [],
2479
+ fragments: item.fragments,
1928
2480
  templates: template.items
1929
2481
  }, item.nodes);
1930
2482
  }
@@ -1934,7 +2486,7 @@ function setNodes(item, comment, next) {
1934
2486
  function setReactiveValue(data, comment, reactive) {
1935
2487
  let item = data.items.find((item) => item.nodes?.includes(comment));
1936
2488
  item ??= {};
1937
- data.mora.subscribers.add(reactive.subscribe((value) => {
2489
+ data.mora.subscriptions.add(reactive.subscribe((value) => {
1938
2490
  if (Array.isArray(value)) setReactiveValueForArray(item, comment, value);
1939
2491
  else setReactiveValueForSingle(item, comment, value);
1940
2492
  }));
@@ -1957,8 +2509,7 @@ function setText(item, comment, value) {
1957
2509
  item.text ??= new Text();
1958
2510
  item.text.textContent = valueIsNullable ? "" : getString(value);
1959
2511
  const result = valueIsNullable ? [comment] : [item.text];
1960
- replaceNodes(item.nodes ?? [comment], result);
1961
- return result;
2512
+ return replaceNodes(item.nodes ?? [comment], result);
1962
2513
  }
1963
2514
  //#endregion
1964
2515
  //#region src/node/index.ts
@@ -2002,9 +2553,7 @@ function mapValue(data, comment, value) {
2002
2553
  case isReactive(value):
2003
2554
  setReactiveValue(data, comment, value);
2004
2555
  break;
2005
- default:
2006
- replaceComment(data, comment, value);
2007
- break;
2556
+ default: replaceComment(data, comment, value);
2008
2557
  }
2009
2558
  }
2010
2559
  function replaceComment(data, comment, value) {
@@ -2022,9 +2571,8 @@ function setComputedNode(data, comment, callback) {
2022
2571
  });
2023
2572
  }
2024
2573
  function setFragmentsNode(data, comment, fragments) {
2025
- const state = fragmentsStates.get(fragments);
2026
- handleFragments(state, false);
2027
- setReactiveValue(data, comment, state.mapped);
2574
+ handleFragments(fragments, false);
2575
+ setReactiveValue(data, comment, fragments[SYMBOL].mapped);
2028
2576
  }
2029
2577
  //#endregion
2030
2578
  //#region src/parse.ts
@@ -2058,173 +2606,98 @@ function transformExpression(prefix, index) {
2058
2606
  }
2059
2607
  //#endregion
2060
2608
  //#region src/fragment.ts
2061
- var Fragment = class {
2062
- #data;
2063
- #configuration = {
2609
+ function Fragment(strings, expressions) {
2610
+ this[SYMBOL] = {
2611
+ expressions,
2612
+ strings,
2613
+ cache: true,
2064
2614
  identifier: void 0,
2065
- cache: true
2615
+ items: [],
2616
+ mora: {
2617
+ subscriptions: /* @__PURE__ */ new Set(),
2618
+ values: /* @__PURE__ */ new Set()
2619
+ },
2620
+ name: NAME_FRAGMENT,
2621
+ values: []
2066
2622
  };
2067
- /**
2068
- * Is template caching enabled?
2069
- */
2070
- get cache() {
2071
- return this.#configuration.cache;
2072
- }
2073
- /**
2074
- * Identifier for the _Fragment_
2075
- *
2076
- * _An identifier can be used to uniquely identify a Fragment, which helps prevent re-rendering in reactive arrays and Fragments_
2077
- */
2078
- get identifier() {
2079
- return this.#configuration.identifier;
2080
- }
2081
- constructor(strings, expressions) {
2082
- Object.defineProperty(this, NAME_FRAGMENT, { value: true });
2083
- this.#data = {
2084
- expressions,
2085
- strings,
2086
- items: [],
2087
- mora: {
2088
- subscribers: /* @__PURE__ */ new Set(),
2089
- values: /* @__PURE__ */ new Set()
2090
- },
2091
- values: []
2092
- };
2093
- }
2094
- /**
2095
- * Insert the _Fragment_ after the given element
2096
- * @param element Element to insert after
2097
- */
2098
- after(element) {
2099
- element.after(...this.get());
2100
- }
2101
- /**
2102
- * Append the _Fragment_ to the given element
2103
- * @param element Element to append to
2104
- */
2105
- appendTo(element) {
2106
- element.append(...this.get());
2107
- }
2108
- /**
2109
- * Insert the _Fragment_ before the given element
2110
- * @param element Element to insert before
2111
- */
2112
- before(element) {
2113
- element.before(...this.get());
2114
- }
2115
- /**
2116
- * Configure the _Fragment_
2117
- *
2118
- * _Returns the Fragment instance for chaining_
2119
- * @param configuration Configuration options
2120
- * @returns _Fragment_
2121
- */
2122
- configure(configuration) {
2123
- const actual = isPlainObject(configuration) ? configuration : {};
2124
- if ("identifier" in actual) this.#configuration.identifier = actual.identifier;
2125
- if (typeof actual.cache === "boolean") this.#configuration.cache = actual.cache;
2126
- return this;
2127
- }
2128
- /**
2129
- * Get a list of the _Fragment_'s nodes
2130
- * @returns List of nodes
2131
- */
2132
- get() {
2133
- const data = this.#data;
2134
- if (data.items.length === 0) {
2135
- const templated = html$1(parse(data), { cache: this.#configuration.cache });
2136
- data.items.splice(0, data.items.length, ...templated.map((node) => ({ nodes: [node] })));
2137
- mapNodes(data, data.items.flatMap((item) => item.nodes));
2138
- }
2139
- return data.items.flatMap((item) => item.fragments?.flatMap((fragment) => fragment.get()) ?? item.nodes);
2140
- }
2141
- /**
2142
- * Prepend the _Fragment_ to the given element
2143
- * @param element Element to prepend to
2144
- */
2145
- prependTo(element) {
2146
- element.prepend(...this.get());
2147
- }
2148
- /**
2149
- * Remove the _Fragment_ _(and all its descendants)_ from the _DOM_
2150
- *
2151
- * - _Any events, reactive values, and Fragments will also be cleaned up and removed_
2152
- * - _After being removed, the Fragment can be re-inserted into the DOM_
2153
- */
2154
- remove() {
2155
- removeFragment(this.#data);
2623
+ }
2624
+ Fragment.prototype.after = insertFragmentAfter;
2625
+ Fragment.prototype.appendTo = appendFragmentTo;
2626
+ Fragment.prototype.before = insertFragmentBefore;
2627
+ Fragment.prototype.configure = configureFragment;
2628
+ Fragment.prototype.get = getFragmentNodes;
2629
+ Fragment.prototype.prependTo = prependFragmentTo;
2630
+ Fragment.prototype.remove = removeFragment;
2631
+ Object.defineProperties(Fragment.prototype, {
2632
+ cache: {
2633
+ enumerable: true,
2634
+ get: getFragmentCache
2635
+ },
2636
+ identifier: {
2637
+ enumerable: true,
2638
+ get: getFragmentIdentifier
2639
+ }
2640
+ });
2641
+ function appendFragmentTo(element) {
2642
+ element.append(...this.get());
2643
+ }
2644
+ function configureFragment(configuration) {
2645
+ const state = this[SYMBOL];
2646
+ const actual = isPlainObject(configuration) ? configuration : {};
2647
+ if ("identifier" in actual) state.identifier = actual.identifier;
2648
+ if (typeof actual.cache === "boolean") state.cache = actual.cache;
2649
+ return this;
2650
+ }
2651
+ function fragment(template, ...values) {
2652
+ if (typeof template !== "string" && isNonTemplateStringsArray(template)) throw new TypeError(MESSAGE_FRAGMENT_VALUE);
2653
+ return new Fragment(template, values);
2654
+ }
2655
+ function getFragmentCache() {
2656
+ return this[SYMBOL].cache;
2657
+ }
2658
+ function getFragmentIdentifier() {
2659
+ return this[SYMBOL].identifier;
2660
+ }
2661
+ function getFragmentNodes() {
2662
+ const state = this[SYMBOL];
2663
+ if (state.items.length === 0) {
2664
+ const templated = html(parse(state), { cache: state.cache });
2665
+ state.items.splice(0, state.items.length, ...templated.map((node) => ({ nodes: [node] })));
2666
+ mapNodes(state, state.items.flatMap((item) => item.nodes));
2156
2667
  }
2157
- };
2158
- function removeFragment(data) {
2159
- removeMora(data);
2160
- let { length } = data.items;
2668
+ return state.items.flatMap((item) => item.fragments?.flatMap((fragment) => fragment.get()) ?? item.nodes);
2669
+ }
2670
+ function insertFragmentAfter(element) {
2671
+ element.after(...this.get());
2672
+ }
2673
+ function insertFragmentBefore(element) {
2674
+ element.before(...this.get());
2675
+ }
2676
+ function prependFragmentTo(element) {
2677
+ element.prepend(...this.get());
2678
+ }
2679
+ function removeFragment() {
2680
+ const state = this[SYMBOL];
2681
+ removeMora(state);
2682
+ let { length } = state.items;
2161
2683
  for (let index = 0; index < length; index += 1) {
2162
- const { fragments, nodes } = data.items[index];
2684
+ const { fragments, nodes } = state.items[index];
2163
2685
  const fragmentsLength = fragments?.length ?? 0;
2164
2686
  for (let fragmentIndex = 0; fragmentIndex < fragmentsLength; fragmentIndex += 1) fragments?.[fragmentIndex]?.remove();
2165
2687
  removeNodes(nodes);
2166
2688
  }
2167
- data.items.length = 0;
2168
- length = data.values.length;
2689
+ state.items.length = 0;
2690
+ length = state.values.length;
2169
2691
  for (let index = 0; index < length; index += 1) {
2170
- const value = data.values[index];
2692
+ const value = state.values[index];
2171
2693
  if (isFragments(value)) handleFragments(value, true);
2172
2694
  }
2173
2695
  }
2174
- function removeMora(data) {
2175
- const unsubscribers = [...data.mora.subscribers];
2176
- data.mora.subscribers.clear();
2177
- data.mora.values.clear();
2178
- for (const unsubscribe of unsubscribers) unsubscribe();
2179
- }
2180
- //#endregion
2181
- //#region src/index.ts
2182
- /**
2183
- * Create a _Fragments_ instance from a reactive array
2184
- *
2185
- * _A Fragments instance can be used to efficiently render a list of items that may change over time, using unique identifiers to track each item, only adding, removing, or updating each related Fragment._
2186
- *
2187
- * @example
2188
- * ```ts
2189
- * const fruits = array(['Apple', 'Banana', 'Cherry']);
2190
- * const items = fragments(
2191
- * fruits,
2192
- * fruit => fruit, // Identifies a unique item
2193
- * fruit => html`<p>${fruit}</p>`, // Creates a Fragment from an item
2194
- * );
2195
- * html`${items}`.appendTo(document.body) // Renders '<p>Apple</p><p>Banana</p><p>Cherry</p>'
2196
- * fruits.push(['Date', 'Elderberry', 'Fig']); // Appends '<p>Date</p><p>Elderberry</p><p>Fig</p>'
2197
- * // without re-rendering the existing Fragments
2198
- * ```
2199
- *
2200
- * @param array Reactive array
2201
- * @param identify Function to identify item uniquely _(non-nullable)_
2202
- * @param fragment Function to create _Fragment_ from item
2203
- * @returns _Fragments_
2204
- */
2205
- function fragments(array, identify, fragment) {
2206
- if (!isArray(array)) throw new TypeError("Fragments array must be a reactive array");
2207
- if (typeof identify !== "function") throw new TypeError("Fragments identify must be a function");
2208
- if (typeof fragment !== "function") throw new TypeError("Fragments fragment must be a function");
2209
- return new Fragments(array, identify, fragment);
2210
- }
2211
- /**
2212
- * Create a _Fragment_ from a template
2213
- *
2214
- * _A Fragment can be used to efficiently render a template that may change over time, only updating the necessary parts of the DOM._
2215
- *
2216
- * @example
2217
- * ```ts
2218
- * const name = signal('World');
2219
- * const fragment = html`<p>Hello, ${name}!</p>`;
2220
- * fragment.appendTo(document.body); // Renders '<p>Hello, World!</p>'
2221
- * name.set('Alice'); // Replaces 'World' with 'Alice'
2222
- * ```
2223
- *
2224
- * @returns _Fragment_
2225
- */
2226
- function html(template, ...values) {
2227
- return new Fragment(template, values);
2696
+ function removeMora(state) {
2697
+ const subscriptions = [...state.mora.subscriptions];
2698
+ state.mora.subscriptions.clear();
2699
+ state.mora.values.clear();
2700
+ for (const subscription of subscriptions) subscription.unsubscribe();
2228
2701
  }
2229
2702
  //#endregion
2230
- export { array, computed, effect, fragments, html, isArray, isComputed, isEffect, isFragment, isFragments, isReactive, isSignal, signal, startBatch, stopBatch, store };
2703
+ export { array, computed, effect, fragment, fragment as html, fragments, isComputed, isEffect, isFragment, isFragments, isReactive, isReactiveArray, isReactiveStore, isReadonlySignal, isSignal, signal, startBatch, stopBatch, store };