@oscarpalmer/mora 0.36.0 → 0.38.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.
package/dist/batch.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  import { BATCH } from "./constants.mjs";
2
2
  import { runEffect } from "./effect.mjs";
3
3
  import { getFrozenValue, peekSignalValue } from "./helpers/value.mjs";
4
+ import "@oscarpalmer/atoms/result";
4
5
  //#region src/batch.ts
5
6
  function flushHandlers() {
6
7
  if (BATCH.flushing) return;
@@ -1,4 +1,5 @@
1
1
  import { Active, Batch, SubscriptionType } from "./models.mjs";
2
+ import { SubscriptionProperty } from "@oscarpalmer/atoms/subscription";
2
3
  //#region src/constants.d.ts
3
4
  export declare const ACTIVE: Active;
4
5
  export declare const ARRAY_THRESHOLD = 100;
@@ -17,12 +18,9 @@ export declare const NAME_STORE = "store";
17
18
  export declare const NAME_SUBSCRIPTION = "subscription";
18
19
  export declare const NAME_ALL: Set<string>;
19
20
  export declare const PROPERTY_LENGTH = "length";
20
- export declare const SYMBOL_EFFECT: unique symbol;
21
- export declare const SYMBOL_STATE: unique symbol;
22
- export declare const SUBSCRIPTION_PROPERTY: {
23
- key: string;
24
- value: string;
25
- };
21
+ export declare const SYMBOL_EFFECT: symbol;
22
+ export declare const SYMBOL_STATE: symbol;
23
+ export declare const SUBSCRIPTION_PROPERTY: SubscriptionProperty;
26
24
  export declare const SUBSCRIPTION_TYPE_COPY: SubscriptionType;
27
25
  export declare const SUBSCRIPTION_TYPE_FROZEN: SubscriptionType;
28
26
  export declare const SUBSCRIPTION_TYPE_ORIGINAL: SubscriptionType;
package/dist/effect.d.mts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Effect, EffectState } from "./models.mjs";
2
2
  import { GenericCallback } from "@oscarpalmer/atoms/models";
3
3
  //#region src/effect.d.ts
4
- declare function Effect(this: any, callback: GenericCallback): void;
5
4
  /**
6
5
  * Create an effect
7
6
  *
package/dist/effect.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { ACTIVE, NAME_EFFECT, NAME_MORA, SYMBOL_STATE } from "./constants.mjs";
2
+ import "@oscarpalmer/atoms/result";
2
3
  //#region src/effect.ts
3
4
  function Effect(callback) {
4
5
  this[SYMBOL_STATE] = { callback };
@@ -1,9 +1,9 @@
1
1
  import { InternalArray, InternalComputed, InternalStore } from "../models.mjs";
2
2
  import { Key } from "@oscarpalmer/atoms/models";
3
3
  //#region src/helpers/proxy.d.ts
4
- export declare function emitProxyValues(this: InternalArray | InternalStore): void;
5
4
  export declare function getReactiveValueInProxy(instance: InternalArray | InternalStore, key: Key): InternalComputed;
6
5
  export declare function getValueInProxy(this: InternalArray | InternalStore, first?: unknown): unknown;
6
+ export declare function notifyProxyValue(this: InternalArray | InternalStore): void;
7
7
  export declare function peekValueInProxy(this: InternalArray | InternalStore, first?: unknown, second?: boolean): unknown;
8
8
  export declare function setProxyValue(this: InternalArray | InternalStore, first?: unknown, second?: unknown): void;
9
9
  export declare function setValueInProxy(instance: InternalArray | InternalStore, target: object, property: PropertyKey, value: unknown): boolean;
@@ -1,17 +1,10 @@
1
- import { SYMBOL_STATE } from "../constants.mjs";
1
+ import { SYMBOL_EFFECT, SYMBOL_STATE } from "../constants.mjs";
2
2
  import { emitValue, getSignalValue, peekSignalValue } from "./value.mjs";
3
3
  import { startBatch, stopBatch } from "../batch.mjs";
4
4
  import { internalComputed } from "../value/computed.mjs";
5
+ import "@oscarpalmer/atoms/result";
5
6
  import { isKey, isPlainObject } from "@oscarpalmer/atoms/is";
6
7
  //#region src/helpers/proxy.ts
7
- function emitProxyValues() {
8
- const state = this[SYMBOL_STATE];
9
- state.mapped ??= /* @__PURE__ */ new Map();
10
- const values = [...state.mapped.values()];
11
- const { length } = values;
12
- for (let index = 0; index < length; index += 1) values[index][1].dirty = true;
13
- emitValue(this);
14
- }
15
8
  function getReactiveValueInProxy(instance, key) {
16
9
  const state = instance[SYMBOL_STATE];
17
10
  state.mapped ??= /* @__PURE__ */ new Map();
@@ -21,7 +14,7 @@ function getReactiveValueInProxy(instance, key) {
21
14
  item = internalComputed(() => state.isArray ? instance.get().at(key) : instance.get()[key]);
22
15
  state.mapped.set(mapKey, item);
23
16
  }
24
- return item[0];
17
+ return item;
25
18
  }
26
19
  function getValueInProxy(first) {
27
20
  let signal;
@@ -34,6 +27,17 @@ function isProxyKey(isArray, value) {
34
27
  function isProxyObject(isArray, value) {
35
28
  return value == null || (isArray ? Array.isArray(value) : isPlainObject(value));
36
29
  }
30
+ function notifyProxyValue() {
31
+ const state = this[SYMBOL_STATE];
32
+ state.mapped ??= /* @__PURE__ */ new Map();
33
+ const values = [...state.mapped.values()];
34
+ const { length } = values;
35
+ for (let index = 0; index < length; index += 1) {
36
+ values[index][SYMBOL_EFFECT].dirty = true;
37
+ values[index][SYMBOL_EFFECT].notify = true;
38
+ }
39
+ emitValue(this, true);
40
+ }
37
41
  function peekValueInProxy(first, second) {
38
42
  const state = this[SYMBOL_STATE];
39
43
  let value;
@@ -132,4 +136,4 @@ function updateProxyValue(callback) {
132
136
  setProxyValue.call(this, callback(this[SYMBOL_STATE].value));
133
137
  }
134
138
  //#endregion
135
- export { emitProxyValues, getReactiveValueInProxy, getValueInProxy, peekValueInProxy, setProxyValue, setValueInProxy, updateProxyValue };
139
+ export { getReactiveValueInProxy, getValueInProxy, notifyProxyValue, peekValueInProxy, setProxyValue, setValueInProxy, updateProxyValue };
@@ -1,12 +1,13 @@
1
1
  import { InternalStateful } from "../models.mjs";
2
2
  //#region src/helpers/value.d.ts
3
- export declare function emitValue(instance: InternalStateful): void;
3
+ type SetValue = (instance: InternalStateful, value: unknown, notify: boolean) => void;
4
+ export declare function emitValue(instance: InternalStateful, notify?: boolean): void;
4
5
  export declare function equalArrays(first: unknown[], second: unknown[], equal?: (first: unknown, second: unknown) => boolean): boolean;
5
6
  export declare function getFrozenValue(value: unknown): unknown;
6
7
  export declare function getJsonValue(this: InternalStateful): unknown;
7
8
  export declare function getSignalValue(this: InternalStateful): unknown;
8
9
  export declare function getStringValue(this: InternalStateful, json?: boolean): string;
9
- export declare function handleSignal(instance: InternalStateful, origin: unknown, setValue: (instance: InternalStateful, value: unknown) => void, onAfter?: () => void): void;
10
+ export declare function handleSignal(instance: InternalStateful, origin: unknown, setValue: SetValue, onAfter?: () => void, notify?: boolean): void;
10
11
  export declare function peekSignalValue(this: InternalStateful | [InternalStateful, unknown], copy?: boolean): unknown;
11
12
  export declare function updateSignal(instance: InternalStateful, callback: (value: unknown) => unknown, setValue: (instance: InternalStateful, value: unknown) => void): void;
12
13
  //#endregion
@@ -1,11 +1,20 @@
1
- import { ACTIVE, BATCH, SUBSCRIPTION_TYPES, SUBSCRIPTION_TYPES_COPY, SUBSCRIPTION_TYPE_FROZEN, SYMBOL_STATE } from "../constants.mjs";
1
+ import { ACTIVE, BATCH, SUBSCRIPTION_TYPES, SUBSCRIPTION_TYPES_COPY, SUBSCRIPTION_TYPE_FROZEN, SYMBOL_EFFECT, SYMBOL_STATE } from "../constants.mjs";
2
2
  import { flushHandlers } from "../batch.mjs";
3
+ import "@oscarpalmer/atoms/result";
3
4
  import { isPlainObject } from "@oscarpalmer/atoms/is";
5
+ import { round } from "@oscarpalmer/atoms/math";
4
6
  //#region src/helpers/value.ts
5
- function emitValue(instance) {
7
+ function emitValue(instance, notify) {
6
8
  const state = instance[SYMBOL_STATE];
7
9
  if (state.computeds != null && state.computeds.size > 0) for (const computed of state.computeds) computed.dirty = true;
8
10
  if (state.effects != null && state.effects.size > 0) for (const effect of state.effects) BATCH.handlers.set(effect, effect);
11
+ if (notify ?? false) {
12
+ const mapped = instance[SYMBOL_STATE].mapped;
13
+ for (const [, item] of mapped) {
14
+ const fx = item[SYMBOL_EFFECT];
15
+ BATCH.handlers.set(fx.instance, fx.instance);
16
+ }
17
+ }
9
18
  for (const type of SUBSCRIPTION_TYPES) {
10
19
  const subscriptions = state.subscriptions?.values.to.keyed?.get(type);
11
20
  if (subscriptions != null && subscriptions.size > 0) for (const [subscription, callback] of subscriptions) BATCH.handlers.set(subscription, {
@@ -24,7 +33,7 @@ function equalArrays(first, second, equal) {
24
33
  const eq = equal ?? Object.is;
25
34
  let offset = 0;
26
35
  if (length >= 100) {
27
- offset = Math.round(length / 10);
36
+ offset = round(length / 10);
28
37
  offset = offset > 25 ? 25 : offset;
29
38
  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;
30
39
  }
@@ -56,7 +65,7 @@ function getSignalValue() {
56
65
  function getStringValue(json) {
57
66
  return json === true ? JSON.stringify(this[SYMBOL_STATE].value) : String(this[SYMBOL_STATE].value);
58
67
  }
59
- function handleSignal(instance, origin, setValue, onAfter) {
68
+ function handleSignal(instance, origin, setValue, onAfter, notify) {
60
69
  const state = instance[SYMBOL_STATE];
61
70
  try {
62
71
  let actual = typeof origin === "function" ? origin() : origin;
@@ -65,12 +74,12 @@ function handleSignal(instance, origin, setValue, onAfter) {
65
74
  actual.then((value) => {
66
75
  if (actual === state.promise) {
67
76
  state.promise = void 0;
68
- setValue(instance, value);
77
+ setValue(instance, value, notify ?? false);
69
78
  }
70
79
  }).catch(() => {
71
80
  if (actual === state.promise) state.promise = void 0;
72
81
  });
73
- } else setValue(instance, actual);
82
+ } else setValue(instance, actual, notify ?? false);
74
83
  } catch {} finally {
75
84
  onAfter?.();
76
85
  }
package/dist/models.d.mts CHANGED
@@ -15,6 +15,7 @@ export type Computed<Value> = Reactive<Value>;
15
15
  export type ComputedEffect = {
16
16
  dirty: boolean;
17
17
  instance: EffectState;
18
+ notify: boolean;
18
19
  };
19
20
  export type Effect = {};
20
21
  export type EffectState = {
@@ -25,8 +26,7 @@ export type InternalArray = {
25
26
  } & ReactiveArray<unknown>;
26
27
  export type InternalComputed = {
27
28
  [SYMBOL_EFFECT]: ComputedEffect;
28
- [SYMBOL_STATE]: SignalState;
29
- } & Computed<unknown>;
29
+ } & Computed<unknown> & InternalStateful;
30
30
  export type InternalReadonly = {
31
31
  frozen: boolean;
32
32
  } & InternalStateful & ReadonlySignal<unknown>;
@@ -266,7 +266,7 @@ export type ReactiveOptions<Value> = {
266
266
  export type ReactiveProxyState = {
267
267
  isArray: boolean;
268
268
  length?: Signal<number>;
269
- mapped?: Map<string, [InternalComputed, ComputedEffect]>;
269
+ mapped?: Map<string, InternalComputed>;
270
270
  } & SignalState;
271
271
  export type ReactiveState<Value = unknown, Item = Value> = {
272
272
  computeds?: Set<ComputedEffect>;
@@ -446,5 +446,5 @@ export type StoredSubscription = {
446
446
  state: SignalState;
447
447
  };
448
448
  export type Subscriber<Value> = (value: Value, subscription: Subscription) => void;
449
- export type SubscriptionType = 'copy' | 'frozen' | 'original' | 'readonly';
449
+ export type SubscriptionType = "copy" | "frozen" | "original" | "readonly";
450
450
  //#endregion
@@ -1,3 +1,85 @@
1
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
2
+ /**
3
+ * Is the value a _Key_?
4
+ *
5
+ * @param value Value to check
6
+ * @returns `true` if the value is a _Key_ _(`number` or `string`)_, otherwise `false`
7
+ */
8
+ function isKey(value) {
9
+ return typeof value === "number" || typeof value === "string";
10
+ }
11
+ /**
12
+ * Is the value a plain object?
13
+ *
14
+ * @param value Value to check
15
+ * @returns `true` if the value is a plain object, otherwise `false`
16
+ */
17
+ function isPlainObject(value) {
18
+ if (value === null || typeof value !== "object") return false;
19
+ if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
20
+ const prototype = Object.getPrototypeOf(value);
21
+ return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
22
+ }
23
+ //#endregion
24
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/result/misc.mjs
25
+ function error(value, original) {
26
+ return getError(value, original);
27
+ }
28
+ function getError(value, original) {
29
+ const errorResult = {
30
+ error: value,
31
+ ok: false
32
+ };
33
+ if (original instanceof Error) errorResult.original = original;
34
+ return errorResult;
35
+ }
36
+ function isError(value, extended) {
37
+ return isResultValue(value, false) && (extended === true ? value.original instanceof Error : true);
38
+ }
39
+ function isOk(value) {
40
+ return isResultValue(value, true);
41
+ }
42
+ function isResultValue(value, okValue) {
43
+ return isPlainObject(value) && value.ok === okValue && (okValue ? RESULT_PROPERTY_VALUE : RESULT_PROPERTY_ERROR) in value;
44
+ }
45
+ /**
46
+ * Creates an ok result
47
+ *
48
+ * @param value Value
49
+ * @returns Ok result
50
+ */
51
+ function ok(value) {
52
+ return {
53
+ ok: true,
54
+ value
55
+ };
56
+ }
57
+ const RESULT_PROPERTY_ERROR = "error";
58
+ const RESULT_PROPERTY_VALUE = "value";
59
+ error.is = isError;
60
+ ok.is = isOk;
61
+ //#endregion
62
+ //#region node_modules/@oscarpalmer/atoms/dist/result/index.mjs
63
+ async function asyncAttempt(value, err) {
64
+ try {
65
+ let result;
66
+ if (typeof value === "function") result = value();
67
+ else result = value;
68
+ if (result instanceof Promise) result = await result;
69
+ return ok(result);
70
+ } catch (thrown) {
71
+ return getError(err ?? thrown, err == null ? void 0 : thrown);
72
+ }
73
+ }
74
+ function attempt(callback, err) {
75
+ try {
76
+ return ok(callback());
77
+ } catch (thrown) {
78
+ return getError(err ?? thrown, err == null ? void 0 : thrown);
79
+ }
80
+ }
81
+ attempt.async = asyncAttempt;
82
+ //#endregion
1
83
  //#region src/constants.ts
2
84
  const ACTIVE = {};
3
85
  const BATCH = {
@@ -84,35 +166,55 @@ function runEffect(state) {
84
166
  ACTIVE.effect = previousEffect;
85
167
  }
86
168
  }
169
+ function getAbsoluteValue(condition, aggregation, value, notNumber, item) {
170
+ if (notNumber || condition(aggregation, value)) {
171
+ if (aggregation.array) {
172
+ aggregation.items ??= {};
173
+ aggregation.items[value] ??= [];
174
+ aggregation.items[value].push(item);
175
+ }
176
+ return value;
177
+ }
178
+ return aggregation.value;
179
+ }
180
+ function isMaxValue(aggregation, value) {
181
+ return aggregation.array ? value >= aggregation.value : value > aggregation.value;
182
+ }
183
+ function isMinValue(aggregation, value) {
184
+ return aggregation.array ? value <= aggregation.value : value < aggregation.value;
185
+ }
186
+ getAbsoluteValue.bind(void 0, isMaxValue), getAbsoluteValue.bind(void 0, isMinValue);
87
187
  //#endregion
88
- //#region node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
188
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/math/misc.mjs
89
189
  /**
90
- * Is the value a _Key_?
190
+ * Round a number
91
191
  *
92
- * @param value Value to check
93
- * @returns `true` if the value is a _Key_ _(`number` or `string`)_, otherwise `false`
192
+ * @param value Number to round
193
+ * @param decimals Number of decimal places to round to _(defaults to `0`)_
194
+ * @returns Rounded number, or `Number.NaN` if the value if unable to be rounded
94
195
  */
95
- function isKey(value) {
96
- return typeof value === "number" || typeof value === "string";
196
+ function round(value, decimals) {
197
+ return roundNumber(Math.round, value, decimals);
97
198
  }
98
- /**
99
- * Is the value a plain object?
100
- *
101
- * @param value Value to check
102
- * @returns `true` if the value is a plain object, otherwise `false`
103
- */
104
- function isPlainObject(value) {
105
- if (value === null || typeof value !== "object") return false;
106
- if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
107
- const prototype = Object.getPrototypeOf(value);
108
- return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
199
+ function roundNumber(callback, value, decimals) {
200
+ if (typeof value !== "number") return NaN;
201
+ if (typeof decimals !== "number" || decimals < 1) return callback(value);
202
+ const mod = 10 ** decimals;
203
+ return callback((value + Number.EPSILON) * mod) / mod;
109
204
  }
110
205
  //#endregion
111
206
  //#region src/helpers/value.ts
112
- function emitValue(instance) {
207
+ function emitValue(instance, notify) {
113
208
  const state = instance[SYMBOL_STATE];
114
209
  if (state.computeds != null && state.computeds.size > 0) for (const computed of state.computeds) computed.dirty = true;
115
210
  if (state.effects != null && state.effects.size > 0) for (const effect of state.effects) BATCH.handlers.set(effect, effect);
211
+ if (notify ?? false) {
212
+ const mapped = instance[SYMBOL_STATE].mapped;
213
+ for (const [, item] of mapped) {
214
+ const fx = item[SYMBOL_EFFECT];
215
+ BATCH.handlers.set(fx.instance, fx.instance);
216
+ }
217
+ }
116
218
  for (const type of SUBSCRIPTION_TYPES) {
117
219
  const subscriptions = state.subscriptions?.values.to.keyed?.get(type);
118
220
  if (subscriptions != null && subscriptions.size > 0) for (const [subscription, callback] of subscriptions) BATCH.handlers.set(subscription, {
@@ -131,7 +233,7 @@ function equalArrays(first, second, equal) {
131
233
  const eq = equal ?? Object.is;
132
234
  let offset = 0;
133
235
  if (length >= 100) {
134
- offset = Math.round(length / 10);
236
+ offset = round(length / 10);
135
237
  offset = offset > 25 ? 25 : offset;
136
238
  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;
137
239
  }
@@ -163,7 +265,7 @@ function getSignalValue() {
163
265
  function getStringValue(json) {
164
266
  return json === true ? JSON.stringify(this[SYMBOL_STATE].value) : String(this[SYMBOL_STATE].value);
165
267
  }
166
- function handleSignal(instance, origin, setValue, onAfter) {
268
+ function handleSignal(instance, origin, setValue, onAfter, notify) {
167
269
  const state = instance[SYMBOL_STATE];
168
270
  try {
169
271
  let actual = typeof origin === "function" ? origin() : origin;
@@ -172,12 +274,12 @@ function handleSignal(instance, origin, setValue, onAfter) {
172
274
  actual.then((value) => {
173
275
  if (actual === state.promise) {
174
276
  state.promise = void 0;
175
- setValue(instance, value);
277
+ setValue(instance, value, notify ?? false);
176
278
  }
177
279
  }).catch(() => {
178
280
  if (actual === state.promise) state.promise = void 0;
179
281
  });
180
- } else setValue(instance, actual);
282
+ } else setValue(instance, actual, notify ?? false);
181
283
  } catch {} finally {
182
284
  onAfter?.();
183
285
  }
@@ -324,29 +426,6 @@ function createFindParameters(original) {
324
426
  value: length === 1 && typeof original[0] !== "function" ? original[0] : original[1]
325
427
  };
326
428
  }
327
- function findValue(type, array, parameters, reversed) {
328
- const findIndex = type === FIND_VALUE_INDEX;
329
- if (!Array.isArray(array) || array.length === 0) return findIndex ? -1 : void 0;
330
- const { bool, key, value } = createFindParameters(parameters);
331
- const callbacks = getArrayCallbacks(bool, key);
332
- if (callbacks?.bool == null && callbacks?.keyed == null) {
333
- if (findIndex) return reversed ? array.lastIndexOf(value) : array.indexOf(value);
334
- return reversed ? array.findLast((item) => Object.is(item, value)) : array.find((item) => Object.is(item, value));
335
- }
336
- if (callbacks.bool != null) {
337
- const index = reversed ? array.findLastIndex(callbacks.bool) : array.findIndex(callbacks.bool);
338
- return findIndex ? index : array[index];
339
- }
340
- return findValueInArray(array, callbacks.keyed, value, findIndex, reversed);
341
- }
342
- function findValueInArray(array, callback, value, findIndex, reversed) {
343
- const { length } = array;
344
- for (let index = 0; index < length; index += 1) {
345
- const item = reversed ? array.at(-(index + 1)) : array[index];
346
- if (Object.is(callback?.(item, index, array), value)) return findIndex ? index : item;
347
- }
348
- return findIndex ? -1 : void 0;
349
- }
350
429
  function findValues(type, array, parameters, mapper) {
351
430
  const result = {
352
431
  matched: [],
@@ -393,54 +472,34 @@ function findValues(type, array, parameters, mapper) {
393
472
  }
394
473
  return result;
395
474
  }
396
- const FIND_VALUE_INDEX = "index";
397
- const FIND_VALUE_ITEM = "item";
398
475
  const FIND_UNIQUE_THRESHOLD = 100;
399
476
  //#endregion
400
- //#region node_modules/@oscarpalmer/atoms/dist/internal/array/index-of.mjs
401
- function indexOf(array, ...parameters) {
402
- return findValue(FIND_VALUE_INDEX, array, parameters, false);
403
- }
404
- function lastIndexOf(array, ...parameters) {
405
- return findValue(FIND_VALUE_INDEX, array, parameters, true);
406
- }
407
- indexOf.last = lastIndexOf;
408
- //#endregion
409
- //#region node_modules/@oscarpalmer/atoms/dist/array/find.mjs
410
- function find(array, ...parameters) {
411
- return findValue(FIND_VALUE_ITEM, array, parameters, false);
477
+ //#region node_modules/@oscarpalmer/atoms/dist/array/filter.mjs
478
+ function exclude(array, ...parameters) {
479
+ return findValues("all", array, parameters).notMatched;
412
480
  }
413
- function findLast(array, ...parameters) {
414
- return findValue(FIND_VALUE_ITEM, array, parameters, true);
481
+ function filter(array, ...parameters) {
482
+ return findValues("all", array, parameters).matched;
415
483
  }
416
- find.last = findLast;
484
+ filter.remove = exclude;
417
485
  //#endregion
418
486
  //#region node_modules/@oscarpalmer/atoms/dist/array/select.mjs
419
- function reverseSelect(array, ...parameters) {
487
+ function filterAndMap(array, ...parameters) {
488
+ return selectValues(array, parameters);
489
+ }
490
+ function mapAndFilter(array, ...parameters) {
420
491
  return findValues("all", array, parameters, {
421
492
  callback: parameters.shift(),
422
493
  reverse: true
423
494
  }).matched;
424
495
  }
425
- function select(array, ...parameters) {
426
- return selectValues(array, parameters);
427
- }
428
496
  function selectValues(array, parameters) {
429
497
  return findValues("all", array, parameters, {
430
498
  callback: parameters.pop(),
431
499
  reverse: false
432
500
  }).matched;
433
501
  }
434
- select.reverse = reverseSelect;
435
- //#endregion
436
- //#region node_modules/@oscarpalmer/atoms/dist/array/filter.mjs
437
- function exclude(array, ...parameters) {
438
- return findValues("all", array, parameters).notMatched;
439
- }
440
- function filter(array, ...parameters) {
441
- return findValues("all", array, parameters).matched;
442
- }
443
- filter.remove = exclude;
502
+ filterAndMap.reverse = mapAndFilter;
444
503
  //#endregion
445
504
  //#region src/helpers/misc.ts
446
505
  function getState(value, options) {
@@ -701,17 +760,17 @@ Computed.prototype.toString = getStringValue;
701
760
  * @returns Computed value
702
761
  */
703
762
  function computed(callback, options) {
704
- return getComputed(callback, options)[0];
763
+ return getComputed(callback, options);
705
764
  }
706
765
  function getComputed(callback, options) {
707
766
  if (typeof callback !== "function") throw new TypeError("Computed callback must be a function");
708
- const instance = new Computed(callback, options);
709
- return [instance, instance[SYMBOL_EFFECT]];
767
+ return new Computed(callback, options);
710
768
  }
711
769
  function getComputedEffect(instance, callback) {
712
770
  const fx = {
713
771
  dirty: true,
714
- instance: void 0
772
+ instance: void 0,
773
+ notify: false
715
774
  };
716
775
  fx.instance = internalEffect(() => {
717
776
  if (fx.dirty) {
@@ -719,7 +778,8 @@ function getComputedEffect(instance, callback) {
719
778
  ACTIVE.computed = fx;
720
779
  handleSignal(instance, callback, setAndEmit$1, () => {
721
780
  ACTIVE.computed = previousComputed;
722
- });
781
+ fx.notify = false;
782
+ }, fx.notify);
723
783
  fx.dirty = false;
724
784
  }
725
785
  });
@@ -742,9 +802,9 @@ function getComputedValue() {
742
802
  function internalComputed(callback, options) {
743
803
  return getComputed(callback, options);
744
804
  }
745
- function setAndEmit$1(instance, value) {
805
+ function setAndEmit$1(instance, value, notify) {
746
806
  const state = instance[SYMBOL_STATE];
747
- if ((state.equal ?? Object.is)(state.value, value)) return;
807
+ if (!notify && (state.equal ?? Object.is)(state.value, value)) return;
748
808
  state.value = value;
749
809
  if (state.computeds != null && state.computeds.size > 0) for (const computed of state.computeds) computed.dirty = true;
750
810
  if (state.effects != null && state.effects.size > 0) for (const effect of state.effects) BATCH.handlers.set(effect, effect);
@@ -760,14 +820,6 @@ function setAndEmit$1(instance, value) {
760
820
  }
761
821
  //#endregion
762
822
  //#region src/helpers/proxy.ts
763
- function emitProxyValues() {
764
- const state = this[SYMBOL_STATE];
765
- state.mapped ??= /* @__PURE__ */ new Map();
766
- const values = [...state.mapped.values()];
767
- const { length } = values;
768
- for (let index = 0; index < length; index += 1) values[index][1].dirty = true;
769
- emitValue(this);
770
- }
771
823
  function getReactiveValueInProxy(instance, key) {
772
824
  const state = instance[SYMBOL_STATE];
773
825
  state.mapped ??= /* @__PURE__ */ new Map();
@@ -777,7 +829,7 @@ function getReactiveValueInProxy(instance, key) {
777
829
  item = internalComputed(() => state.isArray ? instance.get().at(key) : instance.get()[key]);
778
830
  state.mapped.set(mapKey, item);
779
831
  }
780
- return item[0];
832
+ return item;
781
833
  }
782
834
  function getValueInProxy(first) {
783
835
  let signal;
@@ -790,6 +842,17 @@ function isProxyKey(isArray, value) {
790
842
  function isProxyObject(isArray, value) {
791
843
  return value == null || (isArray ? Array.isArray(value) : isPlainObject(value));
792
844
  }
845
+ function notifyProxyValue() {
846
+ const state = this[SYMBOL_STATE];
847
+ state.mapped ??= /* @__PURE__ */ new Map();
848
+ const values = [...state.mapped.values()];
849
+ const { length } = values;
850
+ for (let index = 0; index < length; index += 1) {
851
+ values[index][SYMBOL_EFFECT].dirty = true;
852
+ values[index][SYMBOL_EFFECT].notify = true;
853
+ }
854
+ emitValue(this, true);
855
+ }
793
856
  function peekValueInProxy(first, second) {
794
857
  const state = this[SYMBOL_STATE];
795
858
  let value;
@@ -977,7 +1040,7 @@ ReactiveArray.prototype.clear = clearArrayValues;
977
1040
  ReactiveArray.prototype.filter = filterArrayValues;
978
1041
  ReactiveArray.prototype.get = getArrayValues;
979
1042
  ReactiveArray.prototype.map = mapArrayValues;
980
- ReactiveArray.prototype.notify = emitProxyValues;
1043
+ ReactiveArray.prototype.notify = notifyProxyValue;
981
1044
  ReactiveArray.prototype.peek = peekArrayValue;
982
1045
  ReactiveArray.prototype.pop = popArrayValue;
983
1046
  ReactiveArray.prototype.push = pushArrayValues;
@@ -1018,7 +1081,7 @@ function pushArrayValues(...items) {
1018
1081
  return this[SYMBOL_STATE].value.push(...items);
1019
1082
  }
1020
1083
  function selectArrayValues(filter, map) {
1021
- return computed(() => select(getArrayValues.call(this), filter, map));
1084
+ return computed(() => filterAndMap(getArrayValues.call(this), filter, map));
1022
1085
  }
1023
1086
  function setArrayLength(value) {
1024
1087
  const values = this[SYMBOL_STATE].value;
@@ -1061,7 +1124,7 @@ function ReactiveStore(value, options) {
1061
1124
  ReactiveStore.prototype[NAME_MORA] = NAME_STORE;
1062
1125
  ReactiveStore.prototype.asReadonly = getReadonlySignal;
1063
1126
  ReactiveStore.prototype.get = getValueInProxy;
1064
- ReactiveStore.prototype.notify = emitProxyValues;
1127
+ ReactiveStore.prototype.notify = notifyProxyValue;
1065
1128
  ReactiveStore.prototype.peek = peekValueInProxy;
1066
1129
  ReactiveStore.prototype.set = setProxyValue;
1067
1130
  ReactiveStore.prototype.subscribe = subscribeToProxy;
@@ -1,6 +1,5 @@
1
1
  import { ReactiveArray, ReactiveOptions } from "../models.mjs";
2
2
  //#region src/value/array.d.ts
3
- declare function ReactiveArray(this: any, value: unknown, options?: ReactiveOptions<unknown>): void;
4
3
  /**
5
4
  * Create a reactive array from a function result
6
5
  *
@@ -3,11 +3,11 @@ import { emitValue, equalArrays, getJsonValue, getStringValue } from "../helpers
3
3
  import { getState } from "../helpers/misc.mjs";
4
4
  import { subscribeToProxy } from "../helpers/subscription.mjs";
5
5
  import { computed } from "./computed.mjs";
6
- import { emitProxyValues, getValueInProxy, peekValueInProxy, setProxyValue, setValueInProxy, updateProxyValue } from "../helpers/proxy.mjs";
6
+ import { getValueInProxy, notifyProxyValue, peekValueInProxy, setProxyValue, setValueInProxy, updateProxyValue } from "../helpers/proxy.mjs";
7
7
  import { getReadonlySignal } from "./readonly.mjs";
8
8
  import { signal } from "./signal.mjs";
9
- import { select } from "@oscarpalmer/atoms/array";
10
9
  import { filter } from "@oscarpalmer/atoms/array/filter";
10
+ import { select } from "@oscarpalmer/atoms/array/select";
11
11
  //#region src/value/array.ts
12
12
  function ReactiveArray(value, options) {
13
13
  this[SYMBOL_STATE] = {
@@ -33,7 +33,7 @@ ReactiveArray.prototype.clear = clearArrayValues;
33
33
  ReactiveArray.prototype.filter = filterArrayValues;
34
34
  ReactiveArray.prototype.get = getArrayValues;
35
35
  ReactiveArray.prototype.map = mapArrayValues;
36
- ReactiveArray.prototype.notify = emitProxyValues;
36
+ ReactiveArray.prototype.notify = notifyProxyValue;
37
37
  ReactiveArray.prototype.peek = peekArrayValue;
38
38
  ReactiveArray.prototype.pop = popArrayValue;
39
39
  ReactiveArray.prototype.push = pushArrayValues;
@@ -1,7 +1,6 @@
1
- import { Computed, ComputedEffect, InternalComputed, ReactiveOptions } from "../models.mjs";
1
+ import { Computed, InternalComputed, ReactiveOptions } from "../models.mjs";
2
2
  import { GenericCallback } from "@oscarpalmer/atoms/models";
3
3
  //#region src/value/computed.d.ts
4
- declare function Computed(this: any, callback: GenericCallback, options?: ReactiveOptions<unknown>): void;
5
4
  /**
6
5
  * Create a computed value
7
6
  *
@@ -10,5 +9,5 @@ declare function Computed(this: any, callback: GenericCallback, options?: Reacti
10
9
  * @returns Computed value
11
10
  */
12
11
  export declare function computed<Value>(callback: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Computed<Value>;
13
- export declare function internalComputed(callback: GenericCallback, options?: ReactiveOptions<unknown>): [InternalComputed, ComputedEffect];
12
+ export declare function internalComputed(callback: GenericCallback, options?: ReactiveOptions<unknown>): InternalComputed;
14
13
  //#endregion
@@ -23,17 +23,17 @@ Computed.prototype.toString = getStringValue;
23
23
  * @returns Computed value
24
24
  */
25
25
  function computed(callback, options) {
26
- return getComputed(callback, options)[0];
26
+ return getComputed(callback, options);
27
27
  }
28
28
  function getComputed(callback, options) {
29
29
  if (typeof callback !== "function") throw new TypeError("Computed callback must be a function");
30
- const instance = new Computed(callback, options);
31
- return [instance, instance[SYMBOL_EFFECT]];
30
+ return new Computed(callback, options);
32
31
  }
33
32
  function getComputedEffect(instance, callback) {
34
33
  const fx = {
35
34
  dirty: true,
36
- instance: void 0
35
+ instance: void 0,
36
+ notify: false
37
37
  };
38
38
  fx.instance = internalEffect(() => {
39
39
  if (fx.dirty) {
@@ -41,7 +41,8 @@ function getComputedEffect(instance, callback) {
41
41
  ACTIVE.computed = fx;
42
42
  handleSignal(instance, callback, setAndEmit, () => {
43
43
  ACTIVE.computed = previousComputed;
44
- });
44
+ fx.notify = false;
45
+ }, fx.notify);
45
46
  fx.dirty = false;
46
47
  }
47
48
  });
@@ -64,9 +65,9 @@ function getComputedValue() {
64
65
  function internalComputed(callback, options) {
65
66
  return getComputed(callback, options);
66
67
  }
67
- function setAndEmit(instance, value) {
68
+ function setAndEmit(instance, value, notify) {
68
69
  const state = instance[SYMBOL_STATE];
69
- if ((state.equal ?? Object.is)(state.value, value)) return;
70
+ if (!notify && (state.equal ?? Object.is)(state.value, value)) return;
70
71
  state.value = value;
71
72
  if (state.computeds != null && state.computeds.size > 0) for (const computed of state.computeds) computed.dirty = true;
72
73
  if (state.effects != null && state.effects.size > 0) for (const effect of state.effects) BATCH.handlers.set(effect, effect);
@@ -1,6 +1,5 @@
1
1
  import { ReactiveOptions, Signal } from "../models.mjs";
2
2
  //#region src/value/signal.d.ts
3
- declare function Signal(this: any, value: unknown, options?: ReactiveOptions<unknown>): void;
4
3
  /**
5
4
  * Create a reactive value from a function result
6
5
  *
@@ -1,7 +1,6 @@
1
1
  import { ReactiveOptions, ReactiveStore } from "../models.mjs";
2
2
  import { PlainObject } from "@oscarpalmer/atoms/models";
3
3
  //#region src/value/store.d.ts
4
- declare function ReactiveStore(this: any, value: never, options?: ReactiveOptions<unknown>): void;
5
4
  /**
6
5
  * Create a reactive store from a function result
7
6
  *
@@ -2,7 +2,7 @@ import { NAME_MORA, NAME_STORE, SYMBOL_STATE } from "../constants.mjs";
2
2
  import { getJsonValue, getStringValue } from "../helpers/value.mjs";
3
3
  import { getState } from "../helpers/misc.mjs";
4
4
  import { subscribeToProxy } from "../helpers/subscription.mjs";
5
- import { emitProxyValues, getValueInProxy, peekValueInProxy, setProxyValue, setValueInProxy, updateProxyValue } from "../helpers/proxy.mjs";
5
+ import { getValueInProxy, notifyProxyValue, peekValueInProxy, setProxyValue, setValueInProxy, updateProxyValue } from "../helpers/proxy.mjs";
6
6
  import { getReadonlySignal } from "./readonly.mjs";
7
7
  //#region src/value/store.ts
8
8
  function ReactiveStore(value, options) {
@@ -16,7 +16,7 @@ function ReactiveStore(value, options) {
16
16
  ReactiveStore.prototype[NAME_MORA] = NAME_STORE;
17
17
  ReactiveStore.prototype.asReadonly = getReadonlySignal;
18
18
  ReactiveStore.prototype.get = getValueInProxy;
19
- ReactiveStore.prototype.notify = emitProxyValues;
19
+ ReactiveStore.prototype.notify = notifyProxyValue;
20
20
  ReactiveStore.prototype.peek = peekValueInProxy;
21
21
  ReactiveStore.prototype.set = setProxyValue;
22
22
  ReactiveStore.prototype.subscribe = subscribeToProxy;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oscarpalmer/mora",
3
- "version": "0.36.0",
3
+ "version": "0.38.0",
4
4
  "description": "Signals and stuff…",
5
5
  "keywords": [
6
6
  "reactive",
@@ -39,17 +39,21 @@
39
39
  "test:leak": "vpx vp test run --detect-async-leaks --coverage"
40
40
  },
41
41
  "dependencies": {
42
- "@oscarpalmer/atoms": "^0.204"
42
+ "@oscarpalmer/atoms": "^0.205"
43
43
  },
44
44
  "devDependencies": {
45
- "@types/node": "^26.5",
46
- "@vitest/coverage-istanbul": "^4.1",
45
+ "@types/node": "^26.6",
46
+ "@vitest/coverage-istanbul": "5.0.1",
47
47
  "jsdom": "^30.1",
48
48
  "tsdown": "^0.23",
49
- "typescript": "^6",
50
- "vite": "npm:@voidzero-dev/vite-plus-core@latest",
51
- "vite-plus": "latest",
52
- "vitest": "npm:@voidzero-dev/vite-plus-test@latest"
49
+ "typescript": "^7",
50
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.0.0",
51
+ "vite-plus": "1.0.0",
52
+ "vitest": "5.0.1"
53
+ },
54
+ "overrides": {
55
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.0.0",
56
+ "vitest": "5.0.1"
53
57
  },
54
58
  "packageManager": "npm@11.19.0"
55
59
  }
package/src/batch.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import {attempt} from '@oscarpalmer/atoms/result';
1
2
  import {BATCH} from './constants';
2
3
  import {runEffect} from './effect';
3
4
  import {getFrozenValue, peekSignalValue} from './helpers/value';
package/src/constants.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type {SubscriptionProperty} from '@oscarpalmer/atoms/subscription';
1
2
  import type {Active, Batch, SubscriptionType} from './models';
2
3
 
3
4
  // #region Variables
@@ -16,14 +17,14 @@ export const BATCH: Batch = {
16
17
  handlers: new Map(),
17
18
  };
18
19
 
19
- export const METHODS_AFFECTING_LENGTH = new Set<string | symbol>([
20
+ export const METHODS_AFFECTING_LENGTH: Set<string | symbol> = new Set([
20
21
  'pop',
21
22
  'push',
22
23
  'shift',
23
24
  'unshift',
24
25
  ]);
25
26
 
26
- export const METHODS_UPDATE = new Set<string | symbol>([
27
+ export const METHODS_UPDATE: Set<string | symbol> = new Set([
27
28
  ...METHODS_AFFECTING_LENGTH,
28
29
  'copyWithin',
29
30
  'fill',
@@ -48,7 +49,7 @@ export const NAME_STORE = 'store';
48
49
 
49
50
  export const NAME_SUBSCRIPTION = 'subscription';
50
51
 
51
- export const NAME_ALL = new Set([
52
+ export const NAME_ALL: Set<string> = new Set([
52
53
  NAME_ARRAY,
53
54
  NAME_COMPUTED,
54
55
  NAME_READONLY,
@@ -58,11 +59,11 @@ export const NAME_ALL = new Set([
58
59
 
59
60
  export const PROPERTY_LENGTH = 'length';
60
61
 
61
- export const SYMBOL_EFFECT = Symbol('effect');
62
+ export const SYMBOL_EFFECT: symbol = Symbol('effect');
62
63
 
63
- export const SYMBOL_STATE = Symbol('state');
64
+ export const SYMBOL_STATE: symbol = Symbol('state');
64
65
 
65
- export const SUBSCRIPTION_PROPERTY = {
66
+ export const SUBSCRIPTION_PROPERTY: SubscriptionProperty = {
66
67
  key: NAME_MORA,
67
68
  value: NAME_SUBSCRIPTION,
68
69
  };
@@ -75,7 +76,7 @@ export const SUBSCRIPTION_TYPE_ORIGINAL: SubscriptionType = 'original';
75
76
 
76
77
  export const SUBSCRIPTION_TYPE_READONLY: SubscriptionType = 'readonly';
77
78
 
78
- export const SUBSCRIPTION_TYPES_COPY = new Set<SubscriptionType>([
79
+ export const SUBSCRIPTION_TYPES_COPY: Set<SubscriptionType> = new Set([
79
80
  SUBSCRIPTION_TYPE_COPY,
80
81
  SUBSCRIPTION_TYPE_READONLY,
81
82
  ]);
package/src/effect.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import type {GenericCallback} from '@oscarpalmer/atoms/models';
2
+ import {attempt} from '@oscarpalmer/atoms/result';
2
3
  import {ACTIVE, NAME_EFFECT, NAME_MORA, SYMBOL_STATE} from './constants';
3
4
  import type {Effect, EffectState} from './models';
4
5
 
5
6
  // #region Instance
6
7
 
7
- function Effect(this: any, callback: GenericCallback) {
8
+ function Effect(this: any, callback: GenericCallback): void {
8
9
  this[SYMBOL_STATE] = {callback};
9
10
 
10
11
  runEffect(this[SYMBOL_STATE]);
@@ -5,29 +5,15 @@ import type {
5
5
  Key,
6
6
  PlainObject,
7
7
  } from '@oscarpalmer/atoms/models';
8
+ import {attempt} from '@oscarpalmer/atoms/result';
8
9
  import {startBatch, stopBatch} from '../batch';
9
- import {PROPERTY_LENGTH, SYMBOL_STATE} from '../constants';
10
+ import {PROPERTY_LENGTH, SYMBOL_EFFECT, SYMBOL_STATE} from '../constants';
10
11
  import type {InternalArray, InternalComputed, InternalStore, ReactiveProxyState} from '../models';
11
12
  import {internalComputed} from '../value/computed';
12
13
  import {emitValue, getSignalValue, peekSignalValue} from './value';
13
14
 
14
15
  // #region Functions
15
16
 
16
- export function emitProxyValues(this: InternalArray | InternalStore): void {
17
- const state = this[SYMBOL_STATE];
18
-
19
- state.mapped ??= new Map();
20
-
21
- const values = [...state.mapped.values()];
22
- const {length} = values;
23
-
24
- for (let index = 0; index < length; index += 1) {
25
- values[index][1].dirty = true;
26
- }
27
-
28
- emitValue(this);
29
- }
30
-
31
17
  export function getReactiveValueInProxy(
32
18
  instance: InternalArray | InternalStore,
33
19
  key: Key,
@@ -50,7 +36,7 @@ export function getReactiveValueInProxy(
50
36
  state.mapped.set(mapKey, item);
51
37
  }
52
38
 
53
- return item[0];
39
+ return item;
54
40
  }
55
41
 
56
42
  export function getValueInProxy(this: InternalArray | InternalStore, first?: unknown): unknown {
@@ -71,6 +57,22 @@ function isProxyObject(isArray: boolean, value: unknown): value is ArrayOrPlainO
71
57
  return value == null || (isArray ? Array.isArray(value) : isPlainObject(value));
72
58
  }
73
59
 
60
+ export function notifyProxyValue(this: InternalArray | InternalStore): void {
61
+ const state = this[SYMBOL_STATE];
62
+
63
+ state.mapped ??= new Map();
64
+
65
+ const values = [...state.mapped.values()];
66
+ const {length} = values;
67
+
68
+ for (let index = 0; index < length; index += 1) {
69
+ values[index][SYMBOL_EFFECT].dirty = true;
70
+ values[index][SYMBOL_EFFECT].notify = true;
71
+ }
72
+
73
+ emitValue(this, true);
74
+ }
75
+
74
76
  export function peekValueInProxy(
75
77
  this: InternalArray | InternalStore,
76
78
  first?: unknown,
@@ -1,4 +1,6 @@
1
1
  import {isPlainObject} from '@oscarpalmer/atoms/is';
2
+ import {round} from '@oscarpalmer/atoms/math';
3
+ import {attempt} from '@oscarpalmer/atoms/result';
2
4
  import {flushHandlers} from '../batch';
3
5
  import {
4
6
  ACTIVE,
@@ -9,13 +11,20 @@ import {
9
11
  SUBSCRIPTION_TYPE_FROZEN,
10
12
  SUBSCRIPTION_TYPES,
11
13
  SUBSCRIPTION_TYPES_COPY,
14
+ SYMBOL_EFFECT,
12
15
  SYMBOL_STATE,
13
16
  } from '../constants';
14
- import type {InternalStateful} from '../models';
17
+ import type {InternalArray, InternalComputed, InternalStateful, InternalStore} from '../models';
18
+
19
+ // #region Types
20
+
21
+ type SetValue = (instance: InternalStateful, value: unknown, notify: boolean) => void;
22
+
23
+ // #endregion
15
24
 
16
25
  // #region Functions
17
26
 
18
- export function emitValue(instance: InternalStateful): void {
27
+ export function emitValue(instance: InternalStateful, notify?: boolean): void {
19
28
  const state = instance[SYMBOL_STATE];
20
29
 
21
30
  if (state.computeds != null && state.computeds.size > 0) {
@@ -30,6 +39,18 @@ export function emitValue(instance: InternalStateful): void {
30
39
  }
31
40
  }
32
41
 
42
+ if (notify ?? false) {
43
+ const proxy = instance as InternalArray | InternalStore;
44
+ const state = proxy[SYMBOL_STATE];
45
+ const mapped = state.mapped as Map<unknown, InternalComputed>;
46
+
47
+ for (const [, item] of mapped) {
48
+ const fx = item[SYMBOL_EFFECT];
49
+
50
+ BATCH.handlers.set(fx.instance, fx.instance);
51
+ }
52
+ }
53
+
33
54
  for (const type of SUBSCRIPTION_TYPES) {
34
55
  const subscriptions = state.subscriptions?.values.to.keyed?.get(type);
35
56
 
@@ -67,7 +88,7 @@ export function equalArrays(
67
88
  let offset = 0;
68
89
 
69
90
  if (length >= ARRAY_THRESHOLD) {
70
- offset = Math.round(length / ARRAY_PEEK);
91
+ offset = round(length / ARRAY_PEEK);
71
92
  offset = offset > ARRAY_OFFSET ? ARRAY_OFFSET : offset;
72
93
 
73
94
  for (let index = 0; index < offset; index += 1) {
@@ -136,8 +157,9 @@ export function getStringValue(this: InternalStateful, json?: boolean): string {
136
157
  export function handleSignal(
137
158
  instance: InternalStateful,
138
159
  origin: unknown,
139
- setValue: (instance: InternalStateful, value: unknown) => void,
160
+ setValue: SetValue,
140
161
  onAfter?: () => void,
162
+ notify?: boolean,
141
163
  ): void {
142
164
  const state = instance[SYMBOL_STATE];
143
165
 
@@ -152,7 +174,7 @@ export function handleSignal(
152
174
  if (actual === state.promise) {
153
175
  state.promise = undefined;
154
176
 
155
- setValue(instance, value);
177
+ setValue(instance, value, notify ?? false);
156
178
  }
157
179
  })
158
180
  .catch(() => {
@@ -161,7 +183,7 @@ export function handleSignal(
161
183
  }
162
184
  });
163
185
  } else {
164
- setValue(instance, actual);
186
+ setValue(instance, actual, notify ?? false);
165
187
  }
166
188
  } catch {
167
189
  // ?
package/src/models.ts CHANGED
@@ -20,6 +20,7 @@ export type Computed<Value> = Reactive<Value>;
20
20
  export type ComputedEffect = {
21
21
  dirty: boolean;
22
22
  instance: EffectState;
23
+ notify: boolean;
23
24
  };
24
25
 
25
26
  export type Effect = {};
@@ -34,8 +35,8 @@ export type InternalArray = {
34
35
 
35
36
  export type InternalComputed = {
36
37
  [SYMBOL_EFFECT]: ComputedEffect;
37
- [SYMBOL_STATE]: SignalState;
38
- } & Computed<unknown>;
38
+ } & Computed<unknown> &
39
+ InternalStateful;
39
40
 
40
41
  export type InternalReadonly = {
41
42
  frozen: boolean;
@@ -324,7 +325,7 @@ export type ReactiveOptions<Value> = {
324
325
  export type ReactiveProxyState = {
325
326
  isArray: boolean;
326
327
  length?: Signal<number>;
327
- mapped?: Map<string, [InternalComputed, ComputedEffect]>;
328
+ mapped?: Map<string, InternalComputed>;
328
329
  } & SignalState;
329
330
 
330
331
  export type ReactiveState<Value = unknown, Item = Value> = {
@@ -1,5 +1,5 @@
1
- import {select} from '@oscarpalmer/atoms/array';
2
1
  import {filter} from '@oscarpalmer/atoms/array/filter';
2
+ import {select} from '@oscarpalmer/atoms/array/select';
3
3
  import {
4
4
  METHODS_AFFECTING_LENGTH,
5
5
  METHODS_UPDATE,
@@ -10,8 +10,8 @@ import {
10
10
  } from '../constants';
11
11
  import {getState} from '../helpers/misc';
12
12
  import {
13
- emitProxyValues,
14
13
  getValueInProxy,
14
+ notifyProxyValue,
15
15
  peekValueInProxy,
16
16
  setProxyValue,
17
17
  setValueInProxy,
@@ -26,7 +26,7 @@ import {signal} from './signal';
26
26
 
27
27
  // #region Instance
28
28
 
29
- function ReactiveArray(this: any, value: unknown, options?: ReactiveOptions<unknown>) {
29
+ function ReactiveArray(this: any, value: unknown, options?: ReactiveOptions<unknown>): void {
30
30
  this[SYMBOL_STATE] = {
31
31
  ...getState(undefined, options),
32
32
  isArray: true,
@@ -58,7 +58,7 @@ ReactiveArray.prototype.clear = clearArrayValues;
58
58
  ReactiveArray.prototype.filter = filterArrayValues;
59
59
  ReactiveArray.prototype.get = getArrayValues;
60
60
  ReactiveArray.prototype.map = mapArrayValues;
61
- ReactiveArray.prototype.notify = emitProxyValues;
61
+ ReactiveArray.prototype.notify = notifyProxyValue;
62
62
  ReactiveArray.prototype.peek = peekArrayValue;
63
63
  ReactiveArray.prototype.pop = popArrayValue;
64
64
  ReactiveArray.prototype.push = pushArrayValues;
@@ -25,7 +25,7 @@ import type {
25
25
 
26
26
  // #region Instance
27
27
 
28
- function Computed(this: any, callback: GenericCallback, options?: ReactiveOptions<unknown>) {
28
+ function Computed(this: any, callback: GenericCallback, options?: ReactiveOptions<unknown>): void {
29
29
  this[SYMBOL_STATE] = getState(undefined, options);
30
30
  this[SYMBOL_EFFECT] = getComputedEffect(this, callback);
31
31
  }
@@ -53,21 +53,19 @@ export function computed<Value>(
53
53
  callback: () => Value | Promise<Value>,
54
54
  options?: ReactiveOptions<Value>,
55
55
  ): Computed<Value> {
56
- return getComputed(callback, options)[0] as Computed<Value>;
56
+ return getComputed(callback, options) as Computed<Value>;
57
57
  }
58
58
 
59
59
  function getComputed<Value>(
60
60
  callback: GenericCallback,
61
61
  options?: ReactiveOptions<Value>,
62
- ): [InternalComputed, ComputedEffect] {
62
+ ): InternalComputed {
63
63
  if (typeof callback !== 'function') {
64
64
  throw new TypeError('Computed callback must be a function');
65
65
  }
66
66
 
67
67
  // @ts-expect-error All good, no worries :-)
68
- const instance = new Computed(callback, options);
69
-
70
- return [instance, instance[SYMBOL_EFFECT]];
68
+ return new Computed(callback, options);
71
69
  }
72
70
 
73
71
  function getComputedEffect(
@@ -77,6 +75,7 @@ function getComputedEffect(
77
75
  const fx: ComputedEffect = {
78
76
  dirty: true,
79
77
  instance: undefined as never,
78
+ notify: false,
80
79
  };
81
80
 
82
81
  fx.instance = internalEffect(() => {
@@ -85,9 +84,17 @@ function getComputedEffect(
85
84
 
86
85
  ACTIVE.computed = fx;
87
86
 
88
- handleSignal(instance, callback, setAndEmit, () => {
89
- ACTIVE.computed = previousComputed;
90
- });
87
+ handleSignal(
88
+ instance,
89
+ callback,
90
+ setAndEmit,
91
+ () => {
92
+ ACTIVE.computed = previousComputed;
93
+
94
+ fx.notify = false;
95
+ },
96
+ fx.notify,
97
+ );
91
98
 
92
99
  fx.dirty = false;
93
100
  }
@@ -122,14 +129,14 @@ function getComputedValue(this: InternalComputed): unknown {
122
129
  export function internalComputed(
123
130
  callback: GenericCallback,
124
131
  options?: ReactiveOptions<unknown>,
125
- ): [InternalComputed, ComputedEffect] {
132
+ ): InternalComputed {
126
133
  return getComputed(callback, options);
127
134
  }
128
135
 
129
- function setAndEmit(instance: InternalStateful, value: unknown): void {
136
+ function setAndEmit(instance: InternalStateful, value: unknown, notify: boolean): void {
130
137
  const state = instance[SYMBOL_STATE];
131
138
 
132
- if ((state.equal ?? Object.is)(state.value, value)) {
139
+ if (!notify && (state.equal ?? Object.is)(state.value, value)) {
133
140
  return;
134
141
  }
135
142
 
@@ -25,7 +25,7 @@ type InternalReadonly = {
25
25
 
26
26
  // #region Instance
27
27
 
28
- function Readonly(this: any, state: SignalState, frozen: boolean) {
28
+ function Readonly(this: any, state: SignalState, frozen: boolean): void {
29
29
  this[SUBSCRIPTION_TYPE_FROZEN] = frozen;
30
30
  this[SYMBOL_STATE] = state;
31
31
  }
@@ -15,7 +15,7 @@ import {getReadonlySignal} from './readonly';
15
15
 
16
16
  // #region Instance
17
17
 
18
- function Signal(this: any, value: unknown, options?: ReactiveOptions<unknown>) {
18
+ function Signal(this: any, value: unknown, options?: ReactiveOptions<unknown>): void {
19
19
  this[SYMBOL_STATE] = getState(undefined, options);
20
20
 
21
21
  handleSignal(this, value, setAndEmit);
@@ -2,8 +2,8 @@ import type {PlainObject} from '@oscarpalmer/atoms/models';
2
2
  import {NAME_MORA, NAME_STORE, SYMBOL_STATE} from '../constants';
3
3
  import {getState} from '../helpers/misc';
4
4
  import {
5
- emitProxyValues,
6
5
  getValueInProxy,
6
+ notifyProxyValue,
7
7
  peekValueInProxy,
8
8
  setProxyValue,
9
9
  setValueInProxy,
@@ -16,7 +16,7 @@ import {getReadonlySignal} from './readonly';
16
16
 
17
17
  // #region Instance
18
18
 
19
- function ReactiveStore(this: any, value: never, options?: ReactiveOptions<unknown>) {
19
+ function ReactiveStore(this: any, value: never, options?: ReactiveOptions<unknown>): void {
20
20
  this[SYMBOL_STATE] = {
21
21
  ...getState(undefined, options),
22
22
  isArray: false,
@@ -36,7 +36,7 @@ ReactiveStore.prototype[NAME_MORA] = NAME_STORE;
36
36
 
37
37
  ReactiveStore.prototype.asReadonly = getReadonlySignal;
38
38
  ReactiveStore.prototype.get = getValueInProxy;
39
- ReactiveStore.prototype.notify = emitProxyValues;
39
+ ReactiveStore.prototype.notify = notifyProxyValue;
40
40
  ReactiveStore.prototype.peek = peekValueInProxy;
41
41
  ReactiveStore.prototype.set = setProxyValue;
42
42
  ReactiveStore.prototype.subscribe = subscribeToProxy;