@oscarpalmer/mora 0.36.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,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,9 @@
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
5
  import { isKey, isPlainObject } from "@oscarpalmer/atoms/is";
6
6
  //#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
7
  function getReactiveValueInProxy(instance, key) {
16
8
  const state = instance[SYMBOL_STATE];
17
9
  state.mapped ??= /* @__PURE__ */ new Map();
@@ -21,7 +13,7 @@ function getReactiveValueInProxy(instance, key) {
21
13
  item = internalComputed(() => state.isArray ? instance.get().at(key) : instance.get()[key]);
22
14
  state.mapped.set(mapKey, item);
23
15
  }
24
- return item[0];
16
+ return item;
25
17
  }
26
18
  function getValueInProxy(first) {
27
19
  let signal;
@@ -34,6 +26,17 @@ function isProxyKey(isArray, value) {
34
26
  function isProxyObject(isArray, value) {
35
27
  return value == null || (isArray ? Array.isArray(value) : isPlainObject(value));
36
28
  }
29
+ function notifyProxyValue() {
30
+ const state = this[SYMBOL_STATE];
31
+ state.mapped ??= /* @__PURE__ */ new Map();
32
+ const values = [...state.mapped.values()];
33
+ const { length } = values;
34
+ for (let index = 0; index < length; index += 1) {
35
+ values[index][SYMBOL_EFFECT].dirty = true;
36
+ values[index][SYMBOL_EFFECT].notify = true;
37
+ }
38
+ emitValue(this, true);
39
+ }
37
40
  function peekValueInProxy(first, second) {
38
41
  const state = this[SYMBOL_STATE];
39
42
  let value;
@@ -132,4 +135,4 @@ function updateProxyValue(callback) {
132
135
  setProxyValue.call(this, callback(this[SYMBOL_STATE].value));
133
136
  }
134
137
  //#endregion
135
- export { emitProxyValues, getReactiveValueInProxy, getValueInProxy, peekValueInProxy, setProxyValue, setValueInProxy, updateProxyValue };
138
+ 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,18 @@
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
3
  import { isPlainObject } from "@oscarpalmer/atoms/is";
4
4
  //#region src/helpers/value.ts
5
- function emitValue(instance) {
5
+ function emitValue(instance, notify) {
6
6
  const state = instance[SYMBOL_STATE];
7
7
  if (state.computeds != null && state.computeds.size > 0) for (const computed of state.computeds) computed.dirty = true;
8
8
  if (state.effects != null && state.effects.size > 0) for (const effect of state.effects) BATCH.handlers.set(effect, effect);
9
+ if (notify ?? false) {
10
+ const mapped = instance[SYMBOL_STATE].mapped;
11
+ for (const [, item] of mapped) {
12
+ const fx = item[SYMBOL_EFFECT];
13
+ BATCH.handlers.set(fx.instance, fx.instance);
14
+ }
15
+ }
9
16
  for (const type of SUBSCRIPTION_TYPES) {
10
17
  const subscriptions = state.subscriptions?.values.to.keyed?.get(type);
11
18
  if (subscriptions != null && subscriptions.size > 0) for (const [subscription, callback] of subscriptions) BATCH.handlers.set(subscription, {
@@ -56,7 +63,7 @@ function getSignalValue() {
56
63
  function getStringValue(json) {
57
64
  return json === true ? JSON.stringify(this[SYMBOL_STATE].value) : String(this[SYMBOL_STATE].value);
58
65
  }
59
- function handleSignal(instance, origin, setValue, onAfter) {
66
+ function handleSignal(instance, origin, setValue, onAfter, notify) {
60
67
  const state = instance[SYMBOL_STATE];
61
68
  try {
62
69
  let actual = typeof origin === "function" ? origin() : origin;
@@ -65,12 +72,12 @@ function handleSignal(instance, origin, setValue, onAfter) {
65
72
  actual.then((value) => {
66
73
  if (actual === state.promise) {
67
74
  state.promise = void 0;
68
- setValue(instance, value);
75
+ setValue(instance, value, notify ?? false);
69
76
  }
70
77
  }).catch(() => {
71
78
  if (actual === state.promise) state.promise = void 0;
72
79
  });
73
- } else setValue(instance, actual);
80
+ } else setValue(instance, actual, notify ?? false);
74
81
  } catch {} finally {
75
82
  onAfter?.();
76
83
  }
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 = {
@@ -266,7 +267,7 @@ export type ReactiveOptions<Value> = {
266
267
  export type ReactiveProxyState = {
267
268
  isArray: boolean;
268
269
  length?: Signal<number>;
269
- mapped?: Map<string, [InternalComputed, ComputedEffect]>;
270
+ mapped?: Map<string, InternalComputed>;
270
271
  } & SignalState;
271
272
  export type ReactiveState<Value = unknown, Item = Value> = {
272
273
  computeds?: Set<ComputedEffect>;
@@ -109,10 +109,17 @@ function isPlainObject(value) {
109
109
  }
110
110
  //#endregion
111
111
  //#region src/helpers/value.ts
112
- function emitValue(instance) {
112
+ function emitValue(instance, notify) {
113
113
  const state = instance[SYMBOL_STATE];
114
114
  if (state.computeds != null && state.computeds.size > 0) for (const computed of state.computeds) computed.dirty = true;
115
115
  if (state.effects != null && state.effects.size > 0) for (const effect of state.effects) BATCH.handlers.set(effect, effect);
116
+ if (notify ?? false) {
117
+ const mapped = instance[SYMBOL_STATE].mapped;
118
+ for (const [, item] of mapped) {
119
+ const fx = item[SYMBOL_EFFECT];
120
+ BATCH.handlers.set(fx.instance, fx.instance);
121
+ }
122
+ }
116
123
  for (const type of SUBSCRIPTION_TYPES) {
117
124
  const subscriptions = state.subscriptions?.values.to.keyed?.get(type);
118
125
  if (subscriptions != null && subscriptions.size > 0) for (const [subscription, callback] of subscriptions) BATCH.handlers.set(subscription, {
@@ -163,7 +170,7 @@ function getSignalValue() {
163
170
  function getStringValue(json) {
164
171
  return json === true ? JSON.stringify(this[SYMBOL_STATE].value) : String(this[SYMBOL_STATE].value);
165
172
  }
166
- function handleSignal(instance, origin, setValue, onAfter) {
173
+ function handleSignal(instance, origin, setValue, onAfter, notify) {
167
174
  const state = instance[SYMBOL_STATE];
168
175
  try {
169
176
  let actual = typeof origin === "function" ? origin() : origin;
@@ -172,12 +179,12 @@ function handleSignal(instance, origin, setValue, onAfter) {
172
179
  actual.then((value) => {
173
180
  if (actual === state.promise) {
174
181
  state.promise = void 0;
175
- setValue(instance, value);
182
+ setValue(instance, value, notify ?? false);
176
183
  }
177
184
  }).catch(() => {
178
185
  if (actual === state.promise) state.promise = void 0;
179
186
  });
180
- } else setValue(instance, actual);
187
+ } else setValue(instance, actual, notify ?? false);
181
188
  } catch {} finally {
182
189
  onAfter?.();
183
190
  }
@@ -701,17 +708,17 @@ Computed.prototype.toString = getStringValue;
701
708
  * @returns Computed value
702
709
  */
703
710
  function computed(callback, options) {
704
- return getComputed(callback, options)[0];
711
+ return getComputed(callback, options);
705
712
  }
706
713
  function getComputed(callback, options) {
707
714
  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]];
715
+ return new Computed(callback, options);
710
716
  }
711
717
  function getComputedEffect(instance, callback) {
712
718
  const fx = {
713
719
  dirty: true,
714
- instance: void 0
720
+ instance: void 0,
721
+ notify: false
715
722
  };
716
723
  fx.instance = internalEffect(() => {
717
724
  if (fx.dirty) {
@@ -719,7 +726,8 @@ function getComputedEffect(instance, callback) {
719
726
  ACTIVE.computed = fx;
720
727
  handleSignal(instance, callback, setAndEmit$1, () => {
721
728
  ACTIVE.computed = previousComputed;
722
- });
729
+ fx.notify = false;
730
+ }, fx.notify);
723
731
  fx.dirty = false;
724
732
  }
725
733
  });
@@ -742,9 +750,9 @@ function getComputedValue() {
742
750
  function internalComputed(callback, options) {
743
751
  return getComputed(callback, options);
744
752
  }
745
- function setAndEmit$1(instance, value) {
753
+ function setAndEmit$1(instance, value, notify) {
746
754
  const state = instance[SYMBOL_STATE];
747
- if ((state.equal ?? Object.is)(state.value, value)) return;
755
+ if (!notify && (state.equal ?? Object.is)(state.value, value)) return;
748
756
  state.value = value;
749
757
  if (state.computeds != null && state.computeds.size > 0) for (const computed of state.computeds) computed.dirty = true;
750
758
  if (state.effects != null && state.effects.size > 0) for (const effect of state.effects) BATCH.handlers.set(effect, effect);
@@ -760,14 +768,6 @@ function setAndEmit$1(instance, value) {
760
768
  }
761
769
  //#endregion
762
770
  //#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
771
  function getReactiveValueInProxy(instance, key) {
772
772
  const state = instance[SYMBOL_STATE];
773
773
  state.mapped ??= /* @__PURE__ */ new Map();
@@ -777,7 +777,7 @@ function getReactiveValueInProxy(instance, key) {
777
777
  item = internalComputed(() => state.isArray ? instance.get().at(key) : instance.get()[key]);
778
778
  state.mapped.set(mapKey, item);
779
779
  }
780
- return item[0];
780
+ return item;
781
781
  }
782
782
  function getValueInProxy(first) {
783
783
  let signal;
@@ -790,6 +790,17 @@ function isProxyKey(isArray, value) {
790
790
  function isProxyObject(isArray, value) {
791
791
  return value == null || (isArray ? Array.isArray(value) : isPlainObject(value));
792
792
  }
793
+ function notifyProxyValue() {
794
+ const state = this[SYMBOL_STATE];
795
+ state.mapped ??= /* @__PURE__ */ new Map();
796
+ const values = [...state.mapped.values()];
797
+ const { length } = values;
798
+ for (let index = 0; index < length; index += 1) {
799
+ values[index][SYMBOL_EFFECT].dirty = true;
800
+ values[index][SYMBOL_EFFECT].notify = true;
801
+ }
802
+ emitValue(this, true);
803
+ }
793
804
  function peekValueInProxy(first, second) {
794
805
  const state = this[SYMBOL_STATE];
795
806
  let value;
@@ -977,7 +988,7 @@ ReactiveArray.prototype.clear = clearArrayValues;
977
988
  ReactiveArray.prototype.filter = filterArrayValues;
978
989
  ReactiveArray.prototype.get = getArrayValues;
979
990
  ReactiveArray.prototype.map = mapArrayValues;
980
- ReactiveArray.prototype.notify = emitProxyValues;
991
+ ReactiveArray.prototype.notify = notifyProxyValue;
981
992
  ReactiveArray.prototype.peek = peekArrayValue;
982
993
  ReactiveArray.prototype.pop = popArrayValue;
983
994
  ReactiveArray.prototype.push = pushArrayValues;
@@ -1061,7 +1072,7 @@ function ReactiveStore(value, options) {
1061
1072
  ReactiveStore.prototype[NAME_MORA] = NAME_STORE;
1062
1073
  ReactiveStore.prototype.asReadonly = getReadonlySignal;
1063
1074
  ReactiveStore.prototype.get = getValueInProxy;
1064
- ReactiveStore.prototype.notify = emitProxyValues;
1075
+ ReactiveStore.prototype.notify = notifyProxyValue;
1065
1076
  ReactiveStore.prototype.peek = peekValueInProxy;
1066
1077
  ReactiveStore.prototype.set = setProxyValue;
1067
1078
  ReactiveStore.prototype.subscribe = subscribeToProxy;
@@ -3,7 +3,7 @@ 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
9
  import { select } from "@oscarpalmer/atoms/array";
@@ -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,4 +1,4 @@
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
4
  declare function Computed(this: any, callback: GenericCallback, options?: ReactiveOptions<unknown>): void;
@@ -10,5 +10,5 @@ declare function Computed(this: any, callback: GenericCallback, options?: Reacti
10
10
  * @returns Computed value
11
11
  */
12
12
  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];
13
+ export declare function internalComputed(callback: GenericCallback, options?: ReactiveOptions<unknown>): InternalComputed;
14
14
  //#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);
@@ -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.37.0",
4
4
  "description": "Signals and stuff…",
5
5
  "keywords": [
6
6
  "reactive",
@@ -6,28 +6,13 @@ import type {
6
6
  PlainObject,
7
7
  } from '@oscarpalmer/atoms/models';
8
8
  import {startBatch, stopBatch} from '../batch';
9
- import {PROPERTY_LENGTH, SYMBOL_STATE} from '../constants';
9
+ import {PROPERTY_LENGTH, SYMBOL_EFFECT, SYMBOL_STATE} from '../constants';
10
10
  import type {InternalArray, InternalComputed, InternalStore, ReactiveProxyState} from '../models';
11
11
  import {internalComputed} from '../value/computed';
12
12
  import {emitValue, getSignalValue, peekSignalValue} from './value';
13
13
 
14
14
  // #region Functions
15
15
 
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
16
  export function getReactiveValueInProxy(
32
17
  instance: InternalArray | InternalStore,
33
18
  key: Key,
@@ -50,7 +35,7 @@ export function getReactiveValueInProxy(
50
35
  state.mapped.set(mapKey, item);
51
36
  }
52
37
 
53
- return item[0];
38
+ return item;
54
39
  }
55
40
 
56
41
  export function getValueInProxy(this: InternalArray | InternalStore, first?: unknown): unknown {
@@ -71,6 +56,22 @@ function isProxyObject(isArray: boolean, value: unknown): value is ArrayOrPlainO
71
56
  return value == null || (isArray ? Array.isArray(value) : isPlainObject(value));
72
57
  }
73
58
 
59
+ export function notifyProxyValue(this: InternalArray | InternalStore): void {
60
+ const state = this[SYMBOL_STATE];
61
+
62
+ state.mapped ??= new Map();
63
+
64
+ const values = [...state.mapped.values()];
65
+ const {length} = values;
66
+
67
+ for (let index = 0; index < length; index += 1) {
68
+ values[index][SYMBOL_EFFECT].dirty = true;
69
+ values[index][SYMBOL_EFFECT].notify = true;
70
+ }
71
+
72
+ emitValue(this, true);
73
+ }
74
+
74
75
  export function peekValueInProxy(
75
76
  this: InternalArray | InternalStore,
76
77
  first?: unknown,
@@ -9,13 +9,20 @@ import {
9
9
  SUBSCRIPTION_TYPE_FROZEN,
10
10
  SUBSCRIPTION_TYPES,
11
11
  SUBSCRIPTION_TYPES_COPY,
12
+ SYMBOL_EFFECT,
12
13
  SYMBOL_STATE,
13
14
  } from '../constants';
14
- import type {InternalStateful} from '../models';
15
+ import type {InternalArray, InternalComputed, InternalStateful, InternalStore} from '../models';
16
+
17
+ // #region Types
18
+
19
+ type SetValue = (instance: InternalStateful, value: unknown, notify: boolean) => void;
20
+
21
+ // #endregion
15
22
 
16
23
  // #region Functions
17
24
 
18
- export function emitValue(instance: InternalStateful): void {
25
+ export function emitValue(instance: InternalStateful, notify?: boolean): void {
19
26
  const state = instance[SYMBOL_STATE];
20
27
 
21
28
  if (state.computeds != null && state.computeds.size > 0) {
@@ -30,6 +37,18 @@ export function emitValue(instance: InternalStateful): void {
30
37
  }
31
38
  }
32
39
 
40
+ if (notify ?? false) {
41
+ const proxy = instance as InternalArray | InternalStore;
42
+ const state = proxy[SYMBOL_STATE];
43
+ const mapped = state.mapped as Map<unknown, InternalComputed>;
44
+
45
+ for (const [, item] of mapped) {
46
+ const fx = item[SYMBOL_EFFECT];
47
+
48
+ BATCH.handlers.set(fx.instance, fx.instance);
49
+ }
50
+ }
51
+
33
52
  for (const type of SUBSCRIPTION_TYPES) {
34
53
  const subscriptions = state.subscriptions?.values.to.keyed?.get(type);
35
54
 
@@ -136,8 +155,9 @@ export function getStringValue(this: InternalStateful, json?: boolean): string {
136
155
  export function handleSignal(
137
156
  instance: InternalStateful,
138
157
  origin: unknown,
139
- setValue: (instance: InternalStateful, value: unknown) => void,
158
+ setValue: SetValue,
140
159
  onAfter?: () => void,
160
+ notify?: boolean,
141
161
  ): void {
142
162
  const state = instance[SYMBOL_STATE];
143
163
 
@@ -152,7 +172,7 @@ export function handleSignal(
152
172
  if (actual === state.promise) {
153
173
  state.promise = undefined;
154
174
 
155
- setValue(instance, value);
175
+ setValue(instance, value, notify ?? false);
156
176
  }
157
177
  })
158
178
  .catch(() => {
@@ -161,7 +181,7 @@ export function handleSignal(
161
181
  }
162
182
  });
163
183
  } else {
164
- setValue(instance, actual);
184
+ setValue(instance, actual, notify ?? false);
165
185
  }
166
186
  } catch {
167
187
  // ?
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 = {};
@@ -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> = {
@@ -10,7 +10,7 @@ import {
10
10
  } from '../constants';
11
11
  import {getState} from '../helpers/misc';
12
12
  import {
13
- emitProxyValues,
13
+ notifyProxyValue,
14
14
  getValueInProxy,
15
15
  peekValueInProxy,
16
16
  setProxyValue,
@@ -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;
@@ -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
 
@@ -2,7 +2,7 @@ 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,
5
+ notifyProxyValue,
6
6
  getValueInProxy,
7
7
  peekValueInProxy,
8
8
  setProxyValue,
@@ -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;