@oscarpalmer/mora 0.29.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 (48) 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 -18
  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 +22 -5
  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 +448 -421
  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 -49
  23. package/dist/value/reactive.mjs +10 -54
  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 +7 -8
  29. package/src/batch.ts +22 -9
  30. package/src/constants.ts +3 -4
  31. package/src/effect.ts +35 -40
  32. package/src/helpers/is.ts +11 -10
  33. package/src/helpers/proxy.ts +23 -18
  34. package/src/helpers/value.ts +39 -5
  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 -77
  41. package/src/value/signal.ts +34 -71
  42. package/src/value/store.ts +84 -177
  43. package/types/constants.d.ts +1 -1
  44. package/types/index.d.ts +1 -1
  45. package/types/value/array.d.ts +1 -1
  46. package/types/value/computed.d.ts +3 -0
  47. package/types/value/signal.d.ts +1 -1
  48. package/types/value/store.d.ts +1 -1
@@ -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,189 +147,114 @@ 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);
112
- }
113
- }
114
- /**
115
- * Start batching effects
116
- *
117
- * _(Use {@link stopBatch} to flush and run batched effects)_
118
- */
119
- function startBatch() {
120
- BATCH.depth += 1;
121
- }
122
- /**
123
- * Stop batching effects and flush _(run)_ them
124
- */
125
- function stopBatch() {
126
- if (BATCH.depth > 0) BATCH.depth -= 1;
127
- flushHandlers();
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
+ };
128
164
  }
129
165
  //#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);
138
- }
139
- destroy() {
140
- this.callback = noop;
141
- this.state = void 0;
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;
142
187
  }
143
- };
144
- function noop() {}
145
- function subscribe(state, callback) {
146
- if (typeof callback !== "function" || state.subscriptions.has(callback)) return noop;
147
- state.subscriptions.set(callback, new Subscription(state, callback));
148
- return () => {
149
- unsubscribe(state, callback);
150
- };
188
+ return findIndex ? -1 : void 0;
151
189
  }
152
- function unsubscribe(state, callback) {
153
- state.subscriptions.get(callback)?.destroy();
154
- state.subscriptions.delete(callback);
155
- }
156
- //#endregion
157
- //#region src/value/reactive.ts
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
190
+ function findValues(type, array, parameters, mapper) {
191
+ const result = {
192
+ matched: [],
193
+ notMatched: []
170
194
  };
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();
197
- }
198
- /**
199
- * String representation of the value
200
- * @return Value as string
201
- */
202
- toString() {
203
- return String(this.get());
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;
204
202
  }
205
- /**
206
- * Unsubscribe from changes
207
- * @param callback Callback to unsubscribe
208
- */
209
- unsubscribe(callback) {
210
- unsubscribe(this.state, callback);
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;
211
212
  }
212
- };
213
- //#endregion
214
- //#region src/value/computed.ts
215
- var Computed = class extends Reactive {
216
- effect = {
217
- dirty: true,
218
- instance: void 0
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]
219
230
  };
220
- constructor(callback, options) {
221
- super(NAME_COMPUTED, void 0, options);
222
- this.effect.instance = effect(() => {
223
- if (this.effect.dirty) {
224
- setValue$1(this, this.state, callback);
225
- this.effect.dirty = false;
226
- }
227
- });
228
- }
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;
237
- }
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);
247
231
  }
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();
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);
255
239
  }
256
- function setValue$1(instance, state, callback) {
257
- const previousComputed = ACTIVE.computed;
258
- ACTIVE.computed = instance;
259
- try {
260
- const value = callback();
261
- if (value instanceof Promise) {
262
- state.promise = value;
263
- value.then((resolvedValue) => {
264
- if (state.promise === value) {
265
- state.promise = void 0;
266
- setAndEmit$1(state, resolvedValue);
267
- }
268
- }).catch(() => {
269
- if (state.promise === value) state.promise = void 0;
270
- });
271
- } else setAndEmit$1(state, value);
272
- } finally {
273
- ACTIVE.computed = previousComputed;
274
- }
240
+ indexOf.last = lastIndexOf;
241
+ function lastIndexOf(array, ...parameters) {
242
+ return findValue(FIND_VALUE_INDEX, array, parameters, true);
275
243
  }
276
244
  //#endregion
277
245
  //#region node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
278
246
  /**
279
- * Is the value a key?
247
+ * Is the value a _Key_?
248
+ *
280
249
  * @param value Value to check
281
- * @returns `true` if the value is a `Key` _(`number` or `string`)_, otherwise `false`
250
+ * @returns `true` if the value is a _Key_ _(`number` or `string`)_, otherwise `false`
282
251
  */
283
252
  function isKey(value) {
284
253
  return typeof value === "number" || typeof value === "string";
285
254
  }
286
255
  /**
287
256
  * Is the value a plain object?
257
+ *
288
258
  * @param value Value to check
289
259
  * @returns `true` if the value is a plain object, otherwise `false`
290
260
  */
@@ -295,26 +265,38 @@ function isPlainObject(value) {
295
265
  return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
296
266
  }
297
267
  //#endregion
298
- //#region node_modules/@oscarpalmer/atoms/dist/math.mjs
299
- /**
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
304
- */
305
- function round(value, decimals) {
306
- return roundNumber(Math.round, value, decimals);
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;
307
285
  }
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;
286
+ function filter(array, ...parameters) {
287
+ return findValues("all", array, parameters).matched;
313
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() {}
314
296
  //#endregion
315
297
  //#region src/helpers/value.ts
316
298
  function emitValue(state) {
317
- for (const computed of state.computeds) computed.effect.dirty = true;
299
+ for (const computed of state.computeds) computed.dirty = true;
318
300
  for (const effect of state.effects) BATCH.handlers.add(effect);
319
301
  for (const [, subscription] of state.subscriptions) BATCH.handlers.add(subscription);
320
302
  if (BATCH.depth === 0) flushHandlers();
@@ -324,7 +306,7 @@ function equalArrays(state, first, second) {
324
306
  if (length !== second.length) return false;
325
307
  let offset = 0;
326
308
  if (length >= 100) {
327
- offset = round(length / 10);
309
+ offset = Math.round(length / 10);
328
310
  offset = offset > 25 ? 25 : offset;
329
311
  for (let index = 0; index < offset; index += 1) if (!state.equal(first[index], second[index])) return false;
330
312
  }
@@ -332,26 +314,150 @@ function equalArrays(state, first, second) {
332
314
  for (let index = offset; index < length; index += 1) if (!state.equal(first[index], second[index])) return false;
333
315
  return true;
334
316
  }
335
- function getValue(state) {
317
+ function getSimpleValue(state) {
336
318
  if (ACTIVE.computed != null) state.computeds.add(ACTIVE.computed);
337
319
  if (ACTIVE.effect != null) state.effects.add(ACTIVE.effect);
338
320
  return state.value;
339
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?.();
338
+ }
339
+ }
340
+ //#endregion
341
+ //#region src/subscription.ts
342
+ function noop() {}
343
+ function subscribe(state, callback) {
344
+ if (typeof callback !== "function" || state.subscriptions.has(callback)) return noop;
345
+ state.subscriptions.set(callback, subscription(state, callback));
346
+ return () => {
347
+ unsubscribe(state, callback);
348
+ };
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
+ }
362
+ function unsubscribe(state, callback) {
363
+ state.subscriptions.get(callback)?.destroy();
364
+ state.subscriptions.delete(callback);
365
+ }
366
+ //#endregion
367
+ //#region src/value/reactive.ts
368
+ function reactive(value, options) {
369
+ const state = {
370
+ computeds: /* @__PURE__ */ new Set(),
371
+ effects: /* @__PURE__ */ new Set(),
372
+ equal: typeof options === "object" && typeof options?.equal === "function" ? options.equal : Object.is,
373
+ subscriptions: /* @__PURE__ */ new Map(),
374
+ value
375
+ };
376
+ return [{
377
+ toJSON: () => state.value,
378
+ toString: () => String(state.value)
379
+ }, state];
380
+ }
381
+ //#endregion
382
+ //#region src/value/computed.ts
383
+ /**
384
+ * Create a computed value
385
+ *
386
+ * @param callback Callback to compute the value
387
+ * @param options Reactivity options
388
+ * @returns Computed value
389
+ */
390
+ function 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);
437
+ }
438
+ function setAndEmit$1(state, value) {
439
+ if (state.equal(state.value, value)) return;
440
+ state.value = value;
441
+ for (const computed of state.computeds) computed.dirty = true;
442
+ for (const effect of state.effects) BATCH.handlers.add(effect);
443
+ for (const [, subscription] of state.subscriptions) subscription.callback(value);
444
+ flushHandlers();
445
+ }
340
446
  //#endregion
341
447
  //#region src/helpers/proxy.ts
342
448
  function emityProxyValues(state, mapped) {
343
449
  const values = [...mapped.values()];
344
450
  const { length } = values;
345
- 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;
346
452
  emitValue(state);
347
453
  }
348
454
  function getReactiveValueInProxy(reactive, mapped, key, isArray) {
349
455
  let item = mapped.get(key);
350
456
  if (item == null) {
351
- item = computed(() => isArray ? reactive.get().at(key) : reactive.get()[key]);
457
+ item = internalComputed(() => isArray ? reactive.get().at(key) : reactive.get()[key]);
352
458
  mapped.set(key, item);
353
459
  }
354
- return item;
460
+ return item[0];
355
461
  }
356
462
  function setProxyValue(array, state, isObject, isProperty, setObject, setProperty, first, second) {
357
463
  if (array && first === "length") {
@@ -407,189 +513,106 @@ function setValueInProxy(parameters) {
407
513
  }
408
514
  //#endregion
409
515
  //#region src/value/signal.ts
410
- var Signal = class extends Reactive {
411
- constructor(value, options) {
412
- super(NAME_SIGNAL, value, options);
413
- }
414
- /**
415
- * @inheritdoc
416
- */
417
- get() {
418
- return getValue(this.state);
419
- }
420
- /**
421
- * Set the value
422
- * @param value New value
423
- */
424
- set(value) {
425
- setValue(this.state, value);
426
- }
427
- /**
428
- * Update the value _(based on the current value)_
429
- * @param callback Callback to update the value
430
- */
431
- update(callback) {
432
- this.set(callback(this.state.value));
433
- }
434
- };
435
516
  function setAndEmit(state, value) {
436
517
  if (!state.equal(state.value, value)) {
437
518
  state.value = value;
438
519
  emitValue(state);
439
520
  }
440
521
  }
441
- function setValue(state, value) {
442
- try {
443
- let actual = value;
444
- if (typeof value === "function") actual = value();
445
- if (actual instanceof Promise) {
446
- state.promise = actual;
447
- actual.then((value) => {
448
- if (actual === state.promise) {
449
- state.promise = void 0;
450
- setAndEmit(state, value);
451
- }
452
- }).catch(() => {
453
- if (actual === state.promise) state.promise = void 0;
454
- });
455
- } else setAndEmit(state, actual);
456
- } catch {}
457
- }
458
522
  function signal(value, options) {
459
- const instance = new Signal(void 0, options);
460
- instance.set(value);
461
- 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);
462
545
  }
463
546
  //#endregion
464
547
  //#region src/value/array.ts
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(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, 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;
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);
579
- }
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);
587
- }
588
- };
589
548
  function array(value, options) {
590
- 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
+ });
591
610
  instance.set(value);
592
- 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);
593
616
  }
594
617
  function isArrayIndex(value) {
595
618
  return typeof value === "number";
@@ -597,6 +620,20 @@ function isArrayIndex(value) {
597
620
  function isArrayValue(value) {
598
621
  return value == null || Array.isArray(value);
599
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
+ }
600
637
  function updateArray(type, array, state, length) {
601
638
  const affectsLength = METHODS_AFFECTING_LENGTH.has(type);
602
639
  const previousArray = affectsLength ? [] : array.slice();
@@ -610,57 +647,12 @@ function updateArray(type, array, state, length) {
610
647
  return result;
611
648
  };
612
649
  }
613
- function setArray(state, value) {
614
- state.value.splice(0, state.value.length, ...value ?? []);
615
- }
616
- function setAtIndex(state, index, value) {
617
- const actual = index < 0 ? state.value.length + index : index;
618
- if (actual > -1) state.value[actual] = value;
650
+ function updateArrayValue(instance, state, callback) {
651
+ const updated = callback(state.value);
652
+ if (updated == null || Array.isArray(updated)) instance.set(updated);
619
653
  }
620
654
  //#endregion
621
655
  //#region src/value/store.ts
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);
632
- }
633
- get(key) {
634
- return isKey(key) ? getReactiveValueInProxy(this, this.#keyed, key, false).get() : getValue(this.state);
635
- }
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);
644
- }
645
- peek(key) {
646
- return isKey(key) ? this.state.value[key] : { ...this.state.value };
647
- }
648
- set(first, second) {
649
- setProxyValue(false, this.state, isStoreObject, isKey, setObject, setProperty, first, second);
650
- }
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;
654
- }
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(updated)) setObject(this.state, updated);
662
- }
663
- };
664
656
  function isStoreObject(value) {
665
657
  return value == null || isPlainObject(value);
666
658
  }
@@ -686,9 +678,44 @@ function setProperty(state, key, value) {
686
678
  state.value[key] = value;
687
679
  }
688
680
  function store(value, options) {
689
- 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
+ });
690
717
  instance.set(value);
691
- return instance;
718
+ return Object.freeze(instance);
692
719
  }
693
720
  //#endregion
694
721
  export { array, computed, effect, isArray, isComputed, isEffect, isReactive, isSignal, signal, startBatch, stopBatch, store };