@oscarpalmer/mora 0.28.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/batch.mjs +15 -6
  2. package/dist/constants.d.mts +0 -1
  3. package/dist/constants.mjs +4 -3
  4. package/dist/effect.d.mts +5 -8
  5. package/dist/effect.mjs +23 -19
  6. package/dist/helpers/is.d.mts +9 -9
  7. package/dist/helpers/is.mjs +6 -0
  8. package/dist/helpers/proxy.d.mts +5 -9
  9. package/dist/helpers/proxy.mjs +4 -4
  10. package/dist/helpers/value.d.mts +3 -3
  11. package/dist/helpers/value.mjs +21 -3
  12. package/dist/index.d.mts +7 -8
  13. package/dist/index.mjs +1 -1
  14. package/dist/models.d.mts +356 -18
  15. package/dist/mora.full.mjs +458 -409
  16. package/dist/subscription.d.mts +1 -9
  17. package/dist/subscription.mjs +14 -15
  18. package/dist/value/array.d.mts +5 -133
  19. package/dist/value/array.mjs +91 -137
  20. package/dist/value/computed.d.mts +4 -12
  21. package/dist/value/computed.mjs +54 -50
  22. package/dist/value/reactive.d.mts +3 -38
  23. package/dist/value/reactive.mjs +10 -49
  24. package/dist/value/signal.d.mts +5 -21
  25. package/dist/value/signal.mjs +27 -49
  26. package/dist/value/store.d.mts +9 -92
  27. package/dist/value/store.mjs +42 -49
  28. package/package.json +8 -8
  29. package/src/batch.ts +22 -9
  30. package/src/constants.ts +3 -4
  31. package/src/effect.ts +31 -26
  32. package/src/helpers/is.ts +11 -10
  33. package/src/helpers/proxy.ts +23 -18
  34. package/src/helpers/value.ts +38 -3
  35. package/src/index.ts +6 -7
  36. package/src/models.ts +431 -16
  37. package/src/subscription.ts +20 -20
  38. package/src/value/array.ts +183 -265
  39. package/src/value/computed.ts +80 -74
  40. package/src/value/reactive.ts +16 -64
  41. package/src/value/signal.ts +34 -71
  42. package/src/value/store.ts +84 -177
@@ -2,15 +2,16 @@
2
2
  const ACTIVE = {};
3
3
  const BATCH = {
4
4
  depth: 0,
5
+ flushing: false,
5
6
  handlers: /* @__PURE__ */ new Set()
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",
@@ -24,7 +25,7 @@ const NAME_EFFECT = "effect";
24
25
  const NAME_MORA = "$mora";
25
26
  const NAME_SIGNAL = "signal";
26
27
  const NAME_STORE = "store";
27
- const NAME_ALL = new Set([
28
+ const NAME_ALL = /* @__PURE__ */ new Set([
28
29
  NAME_ARRAY,
29
30
  NAME_COMPUTED,
30
31
  NAME_SIGNAL,
@@ -32,34 +33,74 @@ const NAME_ALL = new Set([
32
33
  ]);
33
34
  //#endregion
34
35
  //#region src/effect.ts
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) {
36
+ /**
37
+ * Create an effect
38
+ *
39
+ * @param callback Callback for handling signal effects
40
+ * @returns Effect
41
+ */
42
+ function effect(callback) {
43
+ if (typeof callback !== "function") throw new TypeError("Effect callback must be a function");
44
+ return getEffect(callback)[0];
45
+ }
46
+ function getEffect(callback) {
47
+ const state = { callback };
48
+ const instance = Object.freeze({ $mora: NAME_EFFECT });
49
+ runEffect(state);
50
+ return [instance, state];
51
+ }
52
+ function internalEffect(callback) {
53
+ return getEffect(callback)[1];
54
+ }
55
+ function runEffect(state) {
43
56
  const previousEffect = ACTIVE.effect;
44
- ACTIVE.effect = effect;
57
+ ACTIVE.effect = state;
45
58
  try {
46
- effect.state.callback();
59
+ state.callback();
47
60
  } finally {
48
61
  ACTIVE.effect = previousEffect;
49
62
  }
50
63
  }
64
+ //#endregion
65
+ //#region src/batch.ts
66
+ function flushHandlers() {
67
+ if (BATCH.flushing) return;
68
+ BATCH.flushing = true;
69
+ try {
70
+ while (BATCH.depth === 0 && BATCH.handlers.size > 0) {
71
+ const handlers = [...BATCH.handlers];
72
+ const { length } = handlers;
73
+ BATCH.handlers.clear();
74
+ for (let index = 0; index < length; index += 1) {
75
+ const handler = handlers[index];
76
+ if (typeof handler.destroy === "function") handler.callback(handler.state.value);
77
+ else runEffect(handler);
78
+ }
79
+ }
80
+ } finally {
81
+ BATCH.flushing = false;
82
+ }
83
+ }
51
84
  /**
52
- * Create an effect
53
- * @param callback Callback for handling signal effects
54
- * @returns Effect
85
+ * Start batching effects
86
+ *
87
+ * _(Use {@link stopBatch} to flush and run batched effects)_
55
88
  */
56
- function effect(callback) {
57
- return typeof callback === "function" ? new Effect(callback) : void 0;
89
+ function startBatch() {
90
+ BATCH.depth += 1;
91
+ }
92
+ /**
93
+ * Stop batching effects and flush _(run)_ them
94
+ */
95
+ function stopBatch() {
96
+ if (BATCH.depth > 0) BATCH.depth -= 1;
97
+ flushHandlers();
58
98
  }
59
99
  //#endregion
60
100
  //#region src/helpers/is.ts
61
101
  /**
62
102
  * Is the value a reactive array?
103
+ *
63
104
  * @param value Value to check
64
105
  * @returns True if value is a {@link ReactiveArray}
65
106
  */
@@ -68,6 +109,7 @@ function isArray(value) {
68
109
  }
69
110
  /**
70
111
  * Is the value a computed signal?
112
+ *
71
113
  * @param value Value to check
72
114
  * @returns True if value is a {@link Computed}
73
115
  */
@@ -76,6 +118,7 @@ function isComputed(value) {
76
118
  }
77
119
  /**
78
120
  * Is the value an effect?
121
+ *
79
122
  * @param value Value to check
80
123
  * @returns True if value is an {@link Effect}
81
124
  */
@@ -87,6 +130,7 @@ function isMora(value, name) {
87
130
  }
88
131
  /**
89
132
  * Is the value reactive?
133
+ *
90
134
  * @param value Value to check
91
135
  * @returns True if value is a {@link Reactive}
92
136
  */
@@ -95,6 +139,7 @@ function isReactive(value) {
95
139
  }
96
140
  /**
97
141
  * Is the value a signal?
142
+ *
98
143
  * @param value Value to check
99
144
  * @returns True if value is a {@link Signal}
100
145
  */
@@ -102,213 +147,317 @@ function isSignal(value) {
102
147
  return isMora(value, NAME_SIGNAL);
103
148
  }
104
149
  //#endregion
105
- //#region src/batch.ts
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);
150
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/array/callbacks.mjs
151
+ function getArrayCallback(value) {
152
+ switch (typeof value) {
153
+ case "function": return value;
154
+ case "number":
155
+ case "string": return typeof value === "string" && value.includes(".") ? void 0 : (obj) => obj[value];
156
+ }
157
+ }
158
+ function getArrayCallbacks(bool, key, value) {
159
+ if (typeof bool === "function") return { bool };
160
+ return {
161
+ keyed: getArrayCallback(key),
162
+ value: getArrayCallback(value)
163
+ };
164
+ }
165
+ //#endregion
166
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/array/find.mjs
167
+ function findValue(type, array, parameters, reversed) {
168
+ const findIndex = type === FIND_VALUE_INDEX;
169
+ if (!Array.isArray(array) || array.length === 0) return findIndex ? -1 : void 0;
170
+ const { bool, key, value } = getFindParameters(parameters);
171
+ const callbacks = getArrayCallbacks(bool, key);
172
+ if (callbacks?.bool == null && callbacks?.keyed == null) {
173
+ if (findIndex) return reversed ? array.lastIndexOf(value) : array.indexOf(value);
174
+ return reversed ? array.findLast((item) => Object.is(item, value)) : array.find((item) => Object.is(item, value));
175
+ }
176
+ if (callbacks.bool != null) {
177
+ const index = reversed ? array.findLastIndex(callbacks.bool) : array.findIndex(callbacks.bool);
178
+ return findIndex ? index : array[index];
179
+ }
180
+ return findValueInArray(array, callbacks.keyed, value, findIndex, reversed);
181
+ }
182
+ function findValueInArray(array, callback, value, findIndex, reversed) {
183
+ const { length } = array;
184
+ for (let index = 0; index < length; index += 1) {
185
+ const item = reversed ? array.at(-(index + 1)) : array[index];
186
+ if (Object.is(callback?.(item, index, array), value)) return findIndex ? index : item;
187
+ }
188
+ return findIndex ? -1 : void 0;
189
+ }
190
+ function findValues(type, array, parameters, mapper) {
191
+ const result = {
192
+ matched: [],
193
+ notMatched: []
194
+ };
195
+ if (!Array.isArray(array) || array.length === 0) return result;
196
+ const { length } = array;
197
+ const { bool, key, value } = getFindParameters(parameters);
198
+ const callbacks = getArrayCallbacks(bool, key);
199
+ if (type === "unique" && callbacks?.keyed == null && length >= UNIQUE_THRESHOLD) {
200
+ result.matched = [...new Set(array)];
201
+ return result;
202
+ }
203
+ const mapCallback = getArrayCallback(mapper);
204
+ if (callbacks?.bool != null || type === "all" && key == null) {
205
+ const callback = callbacks?.bool ?? ((item) => Object.is(item, value));
206
+ for (let index = 0; index < length; index += 1) {
207
+ const item = array[index];
208
+ if (callback(item, index, array)) result.matched.push(mapCallback?.(item, index, array) ?? item);
209
+ else result.notMatched.push(item);
210
+ }
211
+ return result;
112
212
  }
213
+ const keys = /* @__PURE__ */ new Set();
214
+ for (let index = 0; index < length; index += 1) {
215
+ const item = array[index];
216
+ const keyed = callbacks?.keyed?.(item, index, array) ?? item;
217
+ if (type === "all" && Object.is(keyed, value) || type === "unique" && !keys.has(keyed)) {
218
+ keys.add(keyed);
219
+ result.matched.push(mapCallback?.(item, index, array) ?? item);
220
+ } else result.notMatched.push(item);
221
+ }
222
+ return result;
223
+ }
224
+ function getFindParameters(original) {
225
+ const { length } = original;
226
+ return {
227
+ bool: length === 1 && typeof original[0] === "function" ? original[0] : void 0,
228
+ key: length === 2 ? original[0] : void 0,
229
+ value: length === 1 && typeof original[0] !== "function" ? original[0] : original[1]
230
+ };
231
+ }
232
+ const FIND_VALUE_INDEX = "index";
233
+ const FIND_VALUE_ITEM = "item";
234
+ const UNIQUE_THRESHOLD = 100;
235
+ //#endregion
236
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/array/index-of.mjs
237
+ function indexOf(array, ...parameters) {
238
+ return findValue(FIND_VALUE_INDEX, array, parameters, false);
113
239
  }
240
+ indexOf.last = lastIndexOf;
241
+ function lastIndexOf(array, ...parameters) {
242
+ return findValue(FIND_VALUE_INDEX, array, parameters, true);
243
+ }
244
+ //#endregion
245
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
114
246
  /**
115
- * Start batching effects
247
+ * Is the value a _Key_?
116
248
  *
117
- * _(Use {@link stopBatch} to flush and run batched effects)_
249
+ * @param value Value to check
250
+ * @returns `true` if the value is a _Key_ _(`number` or `string`)_, otherwise `false`
118
251
  */
119
- function startBatch() {
120
- BATCH.depth += 1;
252
+ function isKey(value) {
253
+ return typeof value === "number" || typeof value === "string";
121
254
  }
122
255
  /**
123
- * Stop batching effects and flush _(run)_ them
256
+ * Is the value a plain object?
257
+ *
258
+ * @param value Value to check
259
+ * @returns `true` if the value is a plain object, otherwise `false`
124
260
  */
125
- function stopBatch() {
126
- if (BATCH.depth > 0) BATCH.depth -= 1;
127
- flushHandlers();
261
+ function isPlainObject(value) {
262
+ if (value === null || typeof value !== "object") return false;
263
+ if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
264
+ const prototype = Object.getPrototypeOf(value);
265
+ return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
128
266
  }
129
267
  //#endregion
130
- //#region src/subscription.ts
131
- var Subscription = class {
132
- callback;
133
- state;
134
- constructor(state, callback) {
135
- this.state = state;
136
- this.callback = callback;
137
- callback(state.value);
268
+ //#region node_modules/@oscarpalmer/atoms/dist/array/find.mjs
269
+ function find(array, ...parameters) {
270
+ return findValue(FIND_VALUE_ITEM, array, parameters, false);
271
+ }
272
+ find.last = findLast;
273
+ function findLast(array, ...parameters) {
274
+ return findValue(FIND_VALUE_ITEM, array, parameters, true);
275
+ }
276
+ //#endregion
277
+ //#region node_modules/@oscarpalmer/atoms/dist/array/select.mjs
278
+ function select(array, ...parameters) {
279
+ return findValues("all", array, parameters, parameters.pop()).matched;
280
+ }
281
+ //#endregion
282
+ //#region node_modules/@oscarpalmer/atoms/dist/array/filter.mjs
283
+ function exclude(array, ...parameters) {
284
+ return findValues("all", array, parameters).notMatched;
285
+ }
286
+ function filter(array, ...parameters) {
287
+ return findValues("all", array, parameters).matched;
288
+ }
289
+ filter.remove = exclude;
290
+ //#endregion
291
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/function/misc.mjs
292
+ /**
293
+ * A function that does nothing, which can be useful, I guess…
294
+ */
295
+ function noop$1() {}
296
+ //#endregion
297
+ //#region src/helpers/value.ts
298
+ function emitValue(state) {
299
+ for (const computed of state.computeds) computed.dirty = true;
300
+ for (const effect of state.effects) BATCH.handlers.add(effect);
301
+ for (const [, subscription] of state.subscriptions) BATCH.handlers.add(subscription);
302
+ if (BATCH.depth === 0) flushHandlers();
303
+ }
304
+ function equalArrays(state, first, second) {
305
+ let { length } = first;
306
+ if (length !== second.length) return false;
307
+ let offset = 0;
308
+ if (length >= 100) {
309
+ offset = Math.round(length / 10);
310
+ offset = offset > 25 ? 25 : offset;
311
+ for (let index = 0; index < offset; index += 1) if (!state.equal(first[index], second[index])) return false;
138
312
  }
139
- destroy() {
140
- this.callback = noop;
141
- this.state = void 0;
313
+ length -= offset;
314
+ for (let index = offset; index < length; index += 1) if (!state.equal(first[index], second[index])) return false;
315
+ return true;
316
+ }
317
+ function getSimpleValue(state) {
318
+ if (ACTIVE.computed != null) state.computeds.add(ACTIVE.computed);
319
+ if (ACTIVE.effect != null) state.effects.add(ACTIVE.effect);
320
+ return state.value;
321
+ }
322
+ function handleSimpleValue(state, origin, setValue, onAfter) {
323
+ try {
324
+ let actual = typeof origin === "function" ? origin() : origin;
325
+ if (actual instanceof Promise) {
326
+ state.promise = actual;
327
+ actual.then((value) => {
328
+ if (actual === state.promise) {
329
+ state.promise = void 0;
330
+ setValue(state, value);
331
+ }
332
+ }).catch(() => {
333
+ if (actual === state.promise) state.promise = void 0;
334
+ });
335
+ } else setValue(state, actual);
336
+ } catch {} finally {
337
+ onAfter?.();
142
338
  }
143
- };
339
+ }
340
+ //#endregion
341
+ //#region src/subscription.ts
144
342
  function noop() {}
145
343
  function subscribe(state, callback) {
146
344
  if (typeof callback !== "function" || state.subscriptions.has(callback)) return noop;
147
- state.subscriptions.set(callback, new Subscription(state, callback));
345
+ state.subscriptions.set(callback, subscription(state, callback));
148
346
  return () => {
149
347
  unsubscribe(state, callback);
150
348
  };
151
349
  }
350
+ function subscription(state, callback) {
351
+ const instance = {
352
+ callback,
353
+ state,
354
+ destroy: () => {
355
+ instance.callback = noop;
356
+ instance.state = void 0;
357
+ }
358
+ };
359
+ callback(state.value);
360
+ return instance;
361
+ }
152
362
  function unsubscribe(state, callback) {
153
363
  state.subscriptions.get(callback)?.destroy();
154
364
  state.subscriptions.delete(callback);
155
365
  }
156
366
  //#endregion
157
367
  //#region src/value/reactive.ts
158
- var Reactive = class {
159
- state = {
368
+ function reactive(value, options) {
369
+ const state = {
160
370
  computeds: /* @__PURE__ */ new Set(),
161
371
  effects: /* @__PURE__ */ new Set(),
162
- equal: Object.is,
372
+ equal: typeof options === "object" && typeof options?.equal === "function" ? options.equal : Object.is,
163
373
  subscriptions: /* @__PURE__ */ new Map(),
164
- value: void 0
374
+ value
165
375
  };
166
- constructor(name, value, options) {
167
- this.state.value = value;
168
- if (typeof options === "object" && typeof options.equal === "function") this.state.equal = options.equal;
169
- Object.defineProperty(this, NAME_MORA, { value: name });
170
- }
171
- /**
172
- * Get the value _(without reactivity)_
173
- * @return Current value
174
- */
175
- peek() {
176
- return this.state.value;
177
- }
178
- /**
179
- * Subscribe to changes
180
- * @param callback Callback for changes
181
- * @return Unsubscribe callback
182
- */
183
- subscribe(callback) {
184
- return subscribe(this.state, callback);
185
- }
186
- /**
187
- * JSON representation of the value
188
- * @return JSON value
189
- */
190
- toJSON() {
191
- return this.get();
192
- }
193
- /**
194
- * String representation of the value
195
- * @return Value as string
196
- */
197
- toString() {
198
- return String(this.get());
199
- }
200
- /**
201
- * Unsubscribe from changes
202
- * @param callback Callback to unsubscribe
203
- */
204
- unsubscribe(callback) {
205
- unsubscribe(this.state, callback);
206
- }
207
- };
376
+ return [{
377
+ toJSON: () => state.value,
378
+ toString: () => String(state.value)
379
+ }, state];
380
+ }
208
381
  //#endregion
209
382
  //#region src/value/computed.ts
210
- var Computed = class extends Reactive {
211
- effect = {
212
- dirty: true,
213
- instance: void 0
214
- };
215
- constructor(callback, options) {
216
- super(NAME_COMPUTED, void 0, options);
217
- this.effect.instance = effect(() => {
218
- if (this.effect.dirty) {
219
- setValue$1(this, this.state, callback);
220
- this.effect.dirty = false;
221
- }
222
- });
223
- }
224
- /**
225
- * @inheritdoc
226
- */
227
- get() {
228
- if (ACTIVE.computed != null && this !== ACTIVE.computed) this.state.computeds.add(ACTIVE.computed);
229
- if (ACTIVE.effect != null && ACTIVE.effect !== this.effect.instance) this.state.effects.add(ACTIVE.effect);
230
- if (this.effect.dirty && BATCH.depth === 0) runEffect(this.effect.instance);
231
- return this.state.value;
232
- }
233
- };
234
383
  /**
235
384
  * Create a computed value
385
+ *
236
386
  * @param callback Callback to compute the value
237
387
  * @param options Reactivity options
238
388
  * @returns Computed value
239
389
  */
240
390
  function computed(callback, options) {
241
- return new Computed(callback, options);
391
+ return getComputed(callback, options)[0];
392
+ }
393
+ function getComputed(callback, options) {
394
+ const [rx, state] = reactive(void 0, options);
395
+ let fx;
396
+ const instance = {
397
+ ...rx,
398
+ get: () => getValue(state, fx),
399
+ peek: () => state.value,
400
+ subscribe: (callback) => subscribe(state, callback),
401
+ unsubscribe: (callback) => {
402
+ state.subscriptions.delete(callback);
403
+ }
404
+ };
405
+ Object.defineProperty(instance, NAME_MORA, {
406
+ enumerable: false,
407
+ value: NAME_COMPUTED
408
+ });
409
+ fx = getComputedEffect(state, callback);
410
+ return [Object.freeze(instance), fx];
411
+ }
412
+ function getComputedEffect(state, callback) {
413
+ const fx = {
414
+ dirty: true,
415
+ instance: void 0
416
+ };
417
+ fx.instance = internalEffect(() => {
418
+ if (fx.dirty) {
419
+ const previousComputed = ACTIVE.computed;
420
+ ACTIVE.computed = fx;
421
+ handleSimpleValue(state, callback, setAndEmit$1, () => {
422
+ ACTIVE.computed = previousComputed;
423
+ });
424
+ fx.dirty = false;
425
+ }
426
+ });
427
+ return fx;
428
+ }
429
+ function getValue(state, fx) {
430
+ if (ACTIVE.computed != null && fx !== ACTIVE.computed) state.computeds.add(ACTIVE.computed);
431
+ if (ACTIVE.effect != null && ACTIVE.effect !== fx.instance) state.effects.add(ACTIVE.effect);
432
+ if (fx.dirty && BATCH.depth === 0) runEffect(fx.instance);
433
+ return state.value;
434
+ }
435
+ function internalComputed(callback, options) {
436
+ return getComputed(callback, options);
242
437
  }
243
438
  function setAndEmit$1(state, value) {
244
439
  if (state.equal(state.value, value)) return;
245
440
  state.value = value;
246
- for (const computed of state.computeds) computed.effect.dirty = true;
441
+ for (const computed of state.computeds) computed.dirty = true;
247
442
  for (const effect of state.effects) BATCH.handlers.add(effect);
248
443
  for (const [, subscription] of state.subscriptions) subscription.callback(value);
249
444
  flushHandlers();
250
445
  }
251
- function setValue$1(instance, state, callback) {
252
- const previousComputed = ACTIVE.computed;
253
- ACTIVE.computed = instance;
254
- try {
255
- const value = callback();
256
- if (value instanceof Promise) {
257
- state.promise = value;
258
- value.then((resolvedValue) => {
259
- if (state.promise === value) {
260
- state.promise = void 0;
261
- setAndEmit$1(state, resolvedValue);
262
- }
263
- }).catch(() => {
264
- if (state.promise === value) state.promise = void 0;
265
- });
266
- } else setAndEmit$1(state, value);
267
- } finally {
268
- ACTIVE.computed = previousComputed;
269
- }
270
- }
271
- //#endregion
272
- //#region src/helpers/value.ts
273
- function emitValue(state) {
274
- for (const computed of state.computeds) computed.effect.dirty = true;
275
- for (const effect of state.effects) BATCH.handlers.add(effect);
276
- for (const [, subscription] of state.subscriptions) BATCH.handlers.add(subscription);
277
- if (BATCH.depth === 0) flushHandlers();
278
- }
279
- function equalArrays(state, first, second) {
280
- let { length } = first;
281
- if (length !== second.length) return false;
282
- let offset = 0;
283
- if (length >= 100) {
284
- offset = Math.round(length / 10);
285
- offset = offset > 25 ? 25 : offset;
286
- for (let index = 0; index < offset; index += 1) if (!state.equal(first[index], second[index])) return false;
287
- }
288
- length -= offset;
289
- for (let index = offset; index < length; index += 1) if (!state.equal(first[index], second[index])) return false;
290
- return true;
291
- }
292
- function getValue(state) {
293
- if (ACTIVE.computed != null) state.computeds.add(ACTIVE.computed);
294
- if (ACTIVE.effect != null) state.effects.add(ACTIVE.effect);
295
- return state.value;
296
- }
297
446
  //#endregion
298
447
  //#region src/helpers/proxy.ts
299
448
  function emityProxyValues(state, mapped) {
300
449
  const values = [...mapped.values()];
301
450
  const { length } = values;
302
- for (let index = 0; index < length; index += 1) values[index].effect.dirty = true;
451
+ for (let index = 0; index < length; index += 1) values[index][1].dirty = true;
303
452
  emitValue(state);
304
453
  }
305
454
  function getReactiveValueInProxy(reactive, mapped, key, isArray) {
306
455
  let item = mapped.get(key);
307
456
  if (item == null) {
308
- item = computed(() => isArray ? reactive.get().at(key) : reactive.get()[key]);
457
+ item = internalComputed(() => isArray ? reactive.get().at(key) : reactive.get()[key]);
309
458
  mapped.set(key, item);
310
459
  }
311
- return item;
460
+ return item[0];
312
461
  }
313
462
  function setProxyValue(array, state, isObject, isProperty, setObject, setProperty, first, second) {
314
463
  if (array && first === "length") {
@@ -364,189 +513,106 @@ function setValueInProxy(parameters) {
364
513
  }
365
514
  //#endregion
366
515
  //#region src/value/signal.ts
367
- var Signal = class extends Reactive {
368
- constructor(value, options) {
369
- super(NAME_SIGNAL, value, options);
370
- }
371
- /**
372
- * @inheritdoc
373
- */
374
- get() {
375
- return getValue(this.state);
376
- }
377
- /**
378
- * Set the value
379
- * @param value New value
380
- */
381
- set(value) {
382
- setValue(this.state, value);
383
- }
384
- /**
385
- * Update the value _(based on the current value)_
386
- * @param callback Callback to update the value
387
- */
388
- update(callback) {
389
- this.set(callback(this.state.value));
390
- }
391
- };
392
516
  function setAndEmit(state, value) {
393
517
  if (!state.equal(state.value, value)) {
394
518
  state.value = value;
395
519
  emitValue(state);
396
520
  }
397
521
  }
398
- function setValue(state, value) {
399
- try {
400
- let actual = value;
401
- if (typeof value === "function") actual = value();
402
- if (actual instanceof Promise) {
403
- state.promise = actual;
404
- actual.then((value) => {
405
- if (actual === state.promise) {
406
- state.promise = void 0;
407
- setAndEmit(state, value);
408
- }
409
- }).catch(() => {
410
- if (actual === state.promise) state.promise = void 0;
411
- });
412
- } else setAndEmit(state, actual);
413
- } catch {}
414
- }
415
522
  function signal(value, options) {
416
- const instance = new Signal(void 0, options);
417
- instance.set(value);
418
- return instance;
523
+ const [rx, state] = reactive(void 0, options);
524
+ const instance = {
525
+ ...rx,
526
+ get: () => getSimpleValue(state),
527
+ peek: () => state.value,
528
+ set: (value) => {
529
+ handleSimpleValue(state, value, setAndEmit);
530
+ },
531
+ update: (callback) => {
532
+ handleSimpleValue(state, callback(state.value), setAndEmit);
533
+ },
534
+ subscribe: (callback) => subscribe(state, callback),
535
+ unsubscribe: (callback) => {
536
+ state.subscriptions.delete(callback);
537
+ }
538
+ };
539
+ Object.defineProperty(instance, NAME_MORA, {
540
+ enumerable: false,
541
+ value: NAME_SIGNAL
542
+ });
543
+ handleSimpleValue(state, value, setAndEmit);
544
+ return Object.freeze(instance);
419
545
  }
420
546
  //#endregion
421
547
  //#region src/value/array.ts
422
- var ReactiveArray = class extends Reactive {
423
- #indiced = /* @__PURE__ */ new Map();
424
- #size = signal(0);
425
- /**
426
- * The length of the array
427
- */
428
- get length() {
429
- return this.#size.get();
430
- }
431
- /**
432
- * Set the length of the array
433
- */
434
- set length(value) {
435
- if (typeof value === "number" && value >= 0 && value !== this.state.value.length) this.get().length = value;
436
- }
437
- constructor(value, options) {
438
- super(NAME_ARRAY, new Proxy(value, {
439
- get: (target, property) => METHODS_UPDATE.has(property) ? updateArray(property, target, this.state, this.#size) : Reflect.get(target, property),
440
- set: (target, property, value) => setValueInProxy({
441
- property,
442
- target,
443
- value,
444
- isArray: true,
445
- state: this.state,
446
- length: this.#size
447
- })
448
- }), options);
449
- this.#size.set(value.length);
450
- }
451
- /**
452
- * Clear the array
453
- */
454
- clear() {
455
- this.length = 0;
456
- }
457
- /**
458
- * Create a computed, filtered array
459
- * @param callback Callback to evaluate each item
460
- * @return Computed array of filtered items
461
- */
462
- filter(callback) {
463
- return computed(() => this.get().filter(callback));
464
- }
465
- get(first) {
466
- if (typeof first === "number") return getReactiveValueInProxy(this, this.#indiced, first, true).get();
467
- return first === "length" ? this.length : getValue(this.state);
468
- }
469
- /**
470
- * Create a computed, mapped array
471
- * @param callback Callback to transform each item
472
- * @return Computed array of mapped items
473
- */
474
- map(callback) {
475
- return computed(() => this.get().map(callback));
476
- }
477
- /**
478
- * Notify dependents of changes
479
- *
480
- * _This bypasses equality checks and will immediately notify dependents.
481
- * Use this only if you're modifying nested data that would be ignored by equality checks._
482
- */
483
- notify() {
484
- emityProxyValues(this.state, this.#indiced);
485
- }
486
- peek(value) {
487
- if (value === "length") return this.#size.peek();
488
- return typeof value === "number" ? this.state.value.at(value) : this.state.value.slice();
489
- }
490
- /**
491
- * Remove and return the last item of the array
492
- * @returns Removed item, or `undefined` if the array is empty
493
- */
494
- pop() {
495
- return this.state.value.pop();
496
- }
497
- /**
498
- * Add items to the end of the array
499
- * @param items Items to add
500
- * @returns New array length
501
- */
502
- push(...items) {
503
- return this.state.value.push(...items);
504
- }
505
- set(first, second) {
506
- setProxyValue(true, this.state, isArrayValue, isArrayIndex, setArray, setAtIndex, first, second);
507
- }
508
- /**
509
- * Remove and return the first item of the array
510
- * @returns Removed item, or `undefined` if the array is empty
511
- */
512
- shift() {
513
- return this.state.value.shift();
514
- }
515
- /**
516
- * Remove and return items from the array _(and optionally add new items)_
517
- * @param from Index to start removing items from
518
- * @param to Index to stop removing items at _(defaults to the end of the array)_
519
- * @param items Optional items to add
520
- * @returns Removed items
521
- */
522
- splice(from, to, ...items) {
523
- return this.state.value.splice(from, to ?? this.state.value.length, ...items);
524
- }
525
- subscribe(first, second) {
526
- if (typeof first === "number" && typeof second === "function") return getReactiveValueInProxy(this, this.#indiced, first, true).subscribe(second);
527
- return typeof first === "function" ? subscribe(this.state, first) : noop;
528
- }
529
- /**
530
- * Add items to the beginning of the array
531
- * @param items Items to add
532
- * @returns New array length
533
- */
534
- unshift(...items) {
535
- return this.state.value.unshift(...items);
536
- }
537
- /**
538
- * Update the value _(based on the current value)_
539
- * @param callback Callback to update the value
540
- */
541
- update(callback) {
542
- const updated = callback(this.state.value);
543
- if (updated == null || Array.isArray(updated)) this.set(updated);
544
- }
545
- };
546
548
  function array(value, options) {
547
- const instance = new ReactiveArray([], options);
549
+ const [rx, state] = reactive([], options);
550
+ const indiced = /* @__PURE__ */ new Map();
551
+ const length = signal(0);
552
+ state.value = new Proxy([], {
553
+ get: (target, property) => METHODS_UPDATE.has(property) ? updateArray(property, target, state, length) : Reflect.get(target, property),
554
+ set: (target, property, value) => setValueInProxy({
555
+ length,
556
+ property,
557
+ state,
558
+ target,
559
+ value,
560
+ isArray: true
561
+ })
562
+ });
563
+ function get(value) {
564
+ return getArrayValue(instance, indiced, state, length, value);
565
+ }
566
+ const instance = {
567
+ ...rx,
568
+ length: state.value.length,
569
+ at: (index) => get(index),
570
+ clear: () => {
571
+ state.value.length = 0;
572
+ },
573
+ filter: (callback) => computed(() => filter(get(), callback)),
574
+ get: (value) => get(value),
575
+ map: (callback) => computed(() => get().map(callback)),
576
+ notify: () => {
577
+ emityProxyValues(state, indiced);
578
+ },
579
+ peek: (value) => peekArrayValue(state, length, value),
580
+ pop: () => state.value.pop(),
581
+ push: (...items) => state.value.push(...items),
582
+ select: (filter, map) => computed(() => select(get(), filter, map)),
583
+ set: (first, second) => {
584
+ setProxyValue(true, state, isArrayValue, isArrayIndex, setArray, setAtIndex, first, second);
585
+ },
586
+ shift: () => state.value.shift(),
587
+ splice: (from, to, ...items) => state.value.splice(from, to ?? state.value.length, ...items),
588
+ subscribe: (first, second) => {
589
+ if (typeof first === "number" && typeof second === "function") return getReactiveValueInProxy(instance, indiced, first, true).subscribe(second);
590
+ return typeof first === "function" ? subscribe(state, first) : noop$1;
591
+ },
592
+ unshift: (...items) => state.value.unshift(...items),
593
+ unsubscribe: (first, second) => {
594
+ if (typeof first === "number" && typeof second === "function") getReactiveValueInProxy(instance, indiced, first, true)?.unsubscribe(second);
595
+ else if (typeof first === "function") unsubscribe(state, first);
596
+ },
597
+ update: (callback) => updateArrayValue(instance, state, callback)
598
+ };
599
+ Object.defineProperties(instance, {
600
+ [NAME_MORA]: {
601
+ enumerable: false,
602
+ value: NAME_ARRAY
603
+ },
604
+ length: {
605
+ enumerable: true,
606
+ get: () => length.get(),
607
+ set: (value) => setArrayLength(state, value)
608
+ }
609
+ });
548
610
  instance.set(value);
549
- return instance;
611
+ return Object.freeze(instance);
612
+ }
613
+ function getArrayValue(instance, indiced, state, length, first) {
614
+ if (typeof first === "number") return getReactiveValueInProxy(instance, indiced, first, true).get();
615
+ return first === "length" ? length.get() : getSimpleValue(state);
550
616
  }
551
617
  function isArrayIndex(value) {
552
618
  return typeof value === "number";
@@ -554,6 +620,20 @@ function isArrayIndex(value) {
554
620
  function isArrayValue(value) {
555
621
  return value == null || Array.isArray(value);
556
622
  }
623
+ function peekArrayValue(state, length, value) {
624
+ if (value === "length") return length.peek();
625
+ return typeof value === "number" ? state.value.at(value) : state.value.slice();
626
+ }
627
+ function setArray(state, value) {
628
+ state.value.splice(0, state.value.length, ...value ?? []);
629
+ }
630
+ function setArrayLength(state, value) {
631
+ if (typeof value === "number" && value >= 0 && value !== state.value.length) state.value.length = value;
632
+ }
633
+ function setAtIndex(state, index, value) {
634
+ const actual = index < 0 ? state.value.length + index : index;
635
+ if (actual > -1) state.value[actual] = value;
636
+ }
557
637
  function updateArray(type, array, state, length) {
558
638
  const affectsLength = METHODS_AFFECTING_LENGTH.has(type);
559
639
  const previousArray = affectsLength ? [] : array.slice();
@@ -567,78 +647,12 @@ function updateArray(type, array, state, length) {
567
647
  return result;
568
648
  };
569
649
  }
570
- function setArray(state, value) {
571
- state.value.splice(0, state.value.length, ...value ?? []);
572
- }
573
- function setAtIndex(state, index, value) {
574
- const actual = index < 0 ? state.value.length + index : index;
575
- if (actual > -1) state.value[actual] = value;
576
- }
577
- //#endregion
578
- //#region node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
579
- /**
580
- * Is the value a key?
581
- * @param value Value to check
582
- * @returns `true` if the value is a `Key` _(`number` or `string`)_, otherwise `false`
583
- */
584
- function isKey(value) {
585
- return typeof value === "number" || typeof value === "string";
586
- }
587
- /**
588
- * Is the value a plain object?
589
- * @param value Value to check
590
- * @returns `true` if the value is a plain object, otherwise `false`
591
- */
592
- function isPlainObject(value) {
593
- if (value === null || typeof value !== "object") return false;
594
- if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
595
- const prototype = Object.getPrototypeOf(value);
596
- return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
650
+ function updateArrayValue(instance, state, callback) {
651
+ const updated = callback(state.value);
652
+ if (updated == null || Array.isArray(updated)) instance.set(updated);
597
653
  }
598
654
  //#endregion
599
655
  //#region src/value/store.ts
600
- var Store = class extends Reactive {
601
- #keyed = /* @__PURE__ */ new Map();
602
- constructor(value, options) {
603
- super(NAME_STORE, new Proxy(value, { set: (target, property, value) => setValueInProxy({
604
- target,
605
- property,
606
- value,
607
- isArray: false,
608
- state: this.state
609
- }) }), options);
610
- }
611
- get(key) {
612
- return isKey(key) ? getReactiveValueInProxy(this, this.#keyed, key, false).get() : getValue(this.state);
613
- }
614
- /**
615
- * Notify dependents of changes
616
- *
617
- * _This bypasses equality checks and will immediately notify dependents.
618
- * Use this only if you're modifying nested data that would be ignored by equality checks._
619
- */
620
- notify() {
621
- emityProxyValues(this.state, this.#keyed);
622
- }
623
- peek(key) {
624
- return isKey(key) ? this.state.value[key] : { ...this.state.value };
625
- }
626
- set(first, second) {
627
- setProxyValue(false, this.state, isStoreObject, isKey, setObject, setProperty, first, second);
628
- }
629
- subscribe(first, second) {
630
- if (isKey(first) && typeof second === "function") return getReactiveValueInProxy(this, this.#keyed, first, false).subscribe(second);
631
- return typeof first === "function" ? subscribe(this.state, first) : noop;
632
- }
633
- /**
634
- * Update the value _(based on the current value)_
635
- * @param callback Callback to update the value
636
- */
637
- update(callback) {
638
- const updated = callback(this.state.value);
639
- if (updated == null || isPlainObject(updated)) setObject(this.state, updated);
640
- }
641
- };
642
656
  function isStoreObject(value) {
643
657
  return value == null || isPlainObject(value);
644
658
  }
@@ -664,9 +678,44 @@ function setProperty(state, key, value) {
664
678
  state.value[key] = value;
665
679
  }
666
680
  function store(value, options) {
667
- const instance = new Store({}, options);
681
+ const [rx, state] = reactive(void 0, options);
682
+ const keyed = /* @__PURE__ */ new Map();
683
+ state.value = new Proxy({}, { set: (target, property, value) => setValueInProxy({
684
+ target,
685
+ property,
686
+ state,
687
+ value,
688
+ isArray: false
689
+ }) });
690
+ const instance = {
691
+ ...rx,
692
+ get: (value) => isKey(value) ? getReactiveValueInProxy(instance, keyed, value, false).get() : getSimpleValue(state),
693
+ notify() {
694
+ emityProxyValues(state, keyed);
695
+ },
696
+ peek: (value) => isKey(value) ? state.value[value] : { ...state.value },
697
+ set: (first, second) => {
698
+ setProxyValue(false, state, isStoreObject, isKey, setObject, setProperty, first, second);
699
+ },
700
+ subscribe: (first, second) => {
701
+ if (isKey(first) && typeof second === "function") return getReactiveValueInProxy(instance, keyed, first, false).subscribe(second);
702
+ return typeof first === "function" ? subscribe(state, first) : noop;
703
+ },
704
+ unsubscribe: (first, second) => {
705
+ if (isKey(first) && typeof second === "function") getReactiveValueInProxy(instance, keyed, first, false)?.unsubscribe(second);
706
+ else if (typeof first === "function") unsubscribe(state, first);
707
+ },
708
+ update: (callback) => {
709
+ const updated = callback(state.value);
710
+ if (updated == null || isPlainObject(updated)) setObject(state, updated);
711
+ }
712
+ };
713
+ Object.defineProperty(instance, NAME_MORA, {
714
+ enumerable: false,
715
+ value: NAME_STORE
716
+ });
668
717
  instance.set(value);
669
- return instance;
718
+ return Object.freeze(instance);
670
719
  }
671
720
  //#endregion
672
721
  export { array, computed, effect, isArray, isComputed, isEffect, isReactive, isSignal, signal, startBatch, stopBatch, store };