@oscarpalmer/mora 0.37.0 → 0.39.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 (57) hide show
  1. package/dist/batch.d.mts +1 -3
  2. package/dist/batch.mjs +3 -3
  3. package/dist/constants.d.mts +16 -12
  4. package/dist/constants.mjs +12 -6
  5. package/dist/effect.d.mts +2 -4
  6. package/dist/effect.mjs +27 -7
  7. package/dist/helpers/is.d.mts +1 -3
  8. package/dist/helpers/is.mjs +8 -5
  9. package/dist/helpers/misc.d.mts +8 -4
  10. package/dist/helpers/misc.mjs +66 -4
  11. package/dist/helpers/proxy.d.mts +3 -4
  12. package/dist/helpers/proxy.mjs +26 -10
  13. package/dist/helpers/subscription.d.mts +1 -3
  14. package/dist/helpers/subscription.mjs +15 -7
  15. package/dist/helpers/value.d.mts +4 -5
  16. package/dist/helpers/value.mjs +19 -12
  17. package/dist/models.d.mts +39 -7
  18. package/dist/mora.full.mjs +565 -234
  19. package/dist/value/array.d.mts +1 -4
  20. package/dist/value/array.mjs +47 -23
  21. package/dist/value/computed.d.mts +1 -4
  22. package/dist/value/computed.mjs +17 -11
  23. package/dist/value/readonly.d.mts +2 -5
  24. package/dist/value/readonly.mjs +24 -16
  25. package/dist/value/signal.d.mts +1 -4
  26. package/dist/value/signal.mjs +9 -6
  27. package/dist/value/store.d.mts +1 -4
  28. package/dist/value/store.mjs +9 -6
  29. package/package.json +7 -10
  30. package/src/batch.ts +8 -3
  31. package/src/constants.ts +31 -20
  32. package/src/effect.ts +37 -6
  33. package/src/helpers/is.ts +18 -8
  34. package/src/helpers/misc.ts +121 -2
  35. package/src/helpers/proxy.ts +59 -8
  36. package/src/helpers/subscription.ts +34 -4
  37. package/src/helpers/value.ts +49 -14
  38. package/src/models.ts +43 -4
  39. package/src/value/array.ts +103 -24
  40. package/src/value/computed.ts +30 -11
  41. package/src/value/readonly.ts +38 -33
  42. package/src/value/signal.ts +12 -6
  43. package/src/value/store.ts +13 -7
  44. package/types/batch.d.ts +0 -11
  45. package/types/constants.d.ts +0 -16
  46. package/types/effect.d.ts +0 -13
  47. package/types/helpers/is.d.ts +0 -43
  48. package/types/helpers/proxy.d.ts +0 -11
  49. package/types/helpers/value.d.ts +0 -4
  50. package/types/index.d.ts +0 -9
  51. package/types/models.d.ts +0 -56
  52. package/types/subscription.d.ts +0 -11
  53. package/types/value/array.d.ts +0 -137
  54. package/types/value/computed.d.ts +0 -14
  55. package/types/value/reactive.d.ts +0 -36
  56. package/types/value/signal.d.ts +0 -26
  57. package/types/value/store.d.ts +0 -94
package/src/helpers/is.ts CHANGED
@@ -4,10 +4,11 @@ import {
4
4
  NAME_ARRAY,
5
5
  NAME_COMPUTED,
6
6
  NAME_EFFECT,
7
- NAME_MORA,
8
7
  NAME_READONLY,
9
8
  NAME_SIGNAL,
10
9
  NAME_STORE,
10
+ SYMBOL_READONLY,
11
+ SYMBOL_STATE,
11
12
  } from '../constants';
12
13
  import type {
13
14
  Computed,
@@ -41,13 +42,22 @@ export function isEffect(value: unknown): value is Effect {
41
42
  return isMora<Effect>(value, NAME_EFFECT);
42
43
  }
43
44
 
44
- function isMora<Instance>(value: unknown, name: string | Set<string>): value is Instance {
45
- return (
46
- typeof value === 'object' &&
47
- value != null &&
48
- NAME_MORA in value &&
49
- (typeof name === 'string' ? value[NAME_MORA] === name : name.has(value[NAME_MORA] as never))
50
- );
45
+ function isMora<Instance>(input: unknown, value: string | Set<string>): input is Instance {
46
+ if (typeof input !== 'object' || input === null) {
47
+ return false;
48
+ }
49
+
50
+ if (value === NAME_READONLY) {
51
+ return SYMBOL_READONLY in input;
52
+ }
53
+
54
+ if (!(SYMBOL_STATE in input)) {
55
+ return false;
56
+ }
57
+
58
+ const state = (input as PlainObject)[SYMBOL_STATE] as PlainObject;
59
+
60
+ return typeof value === 'string' ? state.name === value : value.has(state.name as never);
51
61
  }
52
62
 
53
63
  /**
@@ -1,10 +1,129 @@
1
- import type {ReactiveOptions, ReactiveState} from '../models';
1
+ import {noop} from '@oscarpalmer/atoms/function';
2
+ import type {PlainObject} from '@oscarpalmer/atoms/models';
3
+ import {SYMBOL_EFFECT, SYMBOL_READONLY, SYMBOL_STATE} from '../constants';
4
+ import {deactivateEffect} from '../effect';
5
+ import type {
6
+ InternalArray,
7
+ InternalComputed,
8
+ InternalReactive,
9
+ InternalReadonly,
10
+ InternalStore,
11
+ ReactiveOptions,
12
+ ReactiveState,
13
+ } from '../models';
14
+ import {peekSignalValue} from './value';
2
15
 
3
16
  // #region Functions
4
17
 
5
- export function getState(value: unknown, options?: ReactiveOptions<unknown>): ReactiveState {
18
+ export function deactivateComputed(this: InternalComputed): void {
19
+ const state = this[SYMBOL_STATE];
20
+
21
+ if (!state.active) {
22
+ return;
23
+ }
24
+
25
+ deactivateEffect(this[SYMBOL_EFFECT].instance);
26
+
27
+ deactivateReactive.call(this);
28
+ }
29
+
30
+ export function deactivateProxy(this: InternalArray | InternalStore): void {
31
+ const state = this[SYMBOL_STATE];
32
+
33
+ if (!state.active) {
34
+ return;
35
+ }
36
+
37
+ if (state.derived != null) {
38
+ for (const computed of state.derived) {
39
+ computed.deactivate();
40
+ }
41
+
42
+ state.derived.clear();
43
+
44
+ state.derived = undefined;
45
+ }
46
+
47
+ if (state.mapped != null) {
48
+ for (const [, computed] of state.mapped) {
49
+ computed.deactivate();
50
+ }
51
+
52
+ state.mapped.clear();
53
+
54
+ state.mapped = undefined;
55
+ }
56
+
57
+ deactivateReactive.call(this);
58
+ }
59
+
60
+ export function deactivateReactive(this: InternalReactive): void {
61
+ const state = this[SYMBOL_STATE];
62
+
63
+ if (!state.active) {
64
+ return;
65
+ }
66
+
67
+ state.active = false;
68
+
69
+ state.computeds?.clear();
70
+ state.effects?.clear();
71
+ state.promises?.clear();
72
+ state.readonlies?.frozen?.deactivate();
73
+ state.readonlies?.original?.deactivate();
74
+ state.subscriptions?.clear();
75
+
76
+ state.equal = noop as never;
77
+ state.promise = undefined;
78
+
79
+ state.computeds = undefined;
80
+ state.effects = undefined;
81
+ state.promises = undefined;
82
+ state.readonlies = undefined;
83
+ state.subscriptions = undefined;
84
+ }
85
+
86
+ export function deactivateReadonly(this: InternalReadonly): void {
87
+ const readonly = this[SYMBOL_READONLY];
88
+ const signal = this[SYMBOL_STATE];
89
+
90
+ if (!readonly.active) {
91
+ return;
92
+ }
93
+
94
+ (signal.readonlies as PlainObject)![readonly.name] = undefined;
95
+
96
+ if (readonly.subscriptions != null) {
97
+ for (const subscription of readonly.subscriptions) {
98
+ subscription.unsubscribe();
99
+ }
100
+
101
+ readonly.subscriptions.clear();
102
+
103
+ readonly.subscriptions = undefined;
104
+ }
105
+
106
+ readonly.active = false;
107
+ readonly.value = peekSignalValue.call(this, true);
108
+ }
109
+
110
+ export function getReactiveActive(this: InternalReactive): boolean {
111
+ return this[SYMBOL_STATE].active;
112
+ }
113
+
114
+ export function getReadonlyActive(this: InternalReadonly): boolean {
115
+ return this[SYMBOL_READONLY].active;
116
+ }
117
+
118
+ export function getState(
119
+ name: string,
120
+ value: unknown,
121
+ options?: ReactiveOptions<unknown>,
122
+ ): ReactiveState {
6
123
  return {
124
+ name,
7
125
  value,
126
+ active: true,
8
127
  equal:
9
128
  typeof options === 'object' && typeof options?.equal === 'function'
10
129
  ? options.equal
@@ -5,9 +5,17 @@ import type {
5
5
  Key,
6
6
  PlainObject,
7
7
  } from '@oscarpalmer/atoms/models';
8
+ import {getNumber} from '@oscarpalmer/atoms/number';
9
+ import {getString} from '@oscarpalmer/atoms/string';
8
10
  import {startBatch, stopBatch} from '../batch';
9
- import {PROPERTY_LENGTH, SYMBOL_EFFECT, SYMBOL_STATE} from '../constants';
10
- import type {InternalArray, InternalComputed, InternalStore, ReactiveProxyState} from '../models';
11
+ import {MESSAGE_UPDATE_CALLBACK, PROPERTY_LENGTH, SYMBOL_EFFECT, SYMBOL_STATE} from '../constants';
12
+ import type {
13
+ Computed,
14
+ InternalArray,
15
+ InternalComputed,
16
+ InternalStore,
17
+ ReactiveProxyState,
18
+ } from '../models';
11
19
  import {internalComputed} from '../value/computed';
12
20
  import {emitValue, getSignalValue, peekSignalValue} from './value';
13
21
 
@@ -21,7 +29,7 @@ export function getReactiveValueInProxy(
21
29
 
22
30
  state.mapped ??= new Map();
23
31
 
24
- const mapKey = String(key);
32
+ const mapKey = getString(key);
25
33
 
26
34
  let item = state.mapped.get(mapKey);
27
35
 
@@ -39,9 +47,15 @@ export function getReactiveValueInProxy(
39
47
  }
40
48
 
41
49
  export function getValueInProxy(this: InternalArray | InternalStore, first?: unknown): unknown {
50
+ const state = this[SYMBOL_STATE];
51
+
52
+ if (!state.active) {
53
+ return peekValueInProxy.call(this, first);
54
+ }
55
+
42
56
  let signal: InternalComputed | undefined;
43
57
 
44
- if (this[SYMBOL_STATE].isArray ? typeof first === 'number' : isKey(first)) {
58
+ if (state.isArray ? typeof first === 'number' : isKey(first)) {
45
59
  signal = getReactiveValueInProxy(this, first as Key);
46
60
  }
47
61
 
@@ -49,7 +63,7 @@ export function getValueInProxy(this: InternalArray | InternalStore, first?: unk
49
63
  }
50
64
 
51
65
  function isProxyKey(isArray: boolean, value: unknown): value is Key {
52
- return isArray ? typeof value === 'number' : isKey(value);
66
+ return (isArray && typeof value === 'number') || isKey(value);
53
67
  }
54
68
 
55
69
  function isProxyObject(isArray: boolean, value: unknown): value is ArrayOrPlainObject {
@@ -59,6 +73,10 @@ function isProxyObject(isArray: boolean, value: unknown): value is ArrayOrPlainO
59
73
  export function notifyProxyValue(this: InternalArray | InternalStore): void {
60
74
  const state = this[SYMBOL_STATE];
61
75
 
76
+ if (!state.active) {
77
+ return;
78
+ }
79
+
62
80
  state.mapped ??= new Map();
63
81
 
64
82
  const values = [...state.mapped.values()];
@@ -156,6 +174,10 @@ export function setProxyValue(
156
174
  ): void {
157
175
  const state = this[SYMBOL_STATE];
158
176
 
177
+ if (!state.active) {
178
+ return;
179
+ }
180
+
159
181
  if (state.isArray && first === PROPERTY_LENGTH) {
160
182
  (state.value as unknown[]).length = second as number;
161
183
 
@@ -231,8 +253,12 @@ export function setValueInProxy(
231
253
  ): boolean {
232
254
  const state = instance[SYMBOL_STATE];
233
255
 
256
+ if (!state.active) {
257
+ return true;
258
+ }
259
+
234
260
  if (state.isArray) {
235
- const isIndex = !Number.isNaN(Number(property));
261
+ const isIndex = !Number.isNaN(getNumber(property));
236
262
  const isLength = property === PROPERTY_LENGTH;
237
263
 
238
264
  if (!(isIndex || isLength)) {
@@ -255,12 +281,37 @@ export function setValueInProxy(
255
281
  return true;
256
282
  }
257
283
 
284
+ export function updateProxyDerivations(
285
+ instance: InternalArray | InternalStore,
286
+ value: Computed<unknown[]>,
287
+ ): Computed<unknown[]> {
288
+ const state = instance[SYMBOL_STATE];
289
+
290
+ if (state.derived == null) {
291
+ state.derived = new Set([value]);
292
+
293
+ return value;
294
+ }
295
+
296
+ for (const computed of state.derived) {
297
+ if (!computed.active) {
298
+ state.derived.delete(computed);
299
+ }
300
+ }
301
+
302
+ state.derived.add(value);
303
+
304
+ return value;
305
+ }
306
+
258
307
  export function updateProxyValue(this: InternalArray | InternalStore, callback: unknown): void {
259
308
  if (typeof callback !== 'function') {
260
- throw new TypeError('Callback must be a function');
309
+ throw new TypeError(MESSAGE_UPDATE_CALLBACK);
261
310
  }
262
311
 
263
- setProxyValue.call(this, callback(this[SYMBOL_STATE].value));
312
+ if (this[SYMBOL_STATE].active) {
313
+ setProxyValue.call(this, callback(this[SYMBOL_STATE].value));
314
+ }
264
315
  }
265
316
 
266
317
  // #endregion
@@ -2,6 +2,7 @@ import {isKey} from '@oscarpalmer/atoms/is';
2
2
  import type {Key} from '@oscarpalmer/atoms/models';
3
3
  import {subscriptions, type Subscription} from '@oscarpalmer/atoms/subscription';
4
4
  import {
5
+ MESSAGE_DEACTIVATED_SUBSCRIPTION,
5
6
  SUBSCRIPTION_PROPERTY,
6
7
  SUBSCRIPTION_TYPE_COPY,
7
8
  SUBSCRIPTION_TYPE_FROZEN,
@@ -9,6 +10,7 @@ import {
9
10
  SUBSCRIPTION_TYPE_READONLY,
10
11
  SUBSCRIPTION_TYPES,
11
12
  SUBSCRIPTION_TYPES_COPY,
13
+ SYMBOL_READONLY,
12
14
  SYMBOL_STATE,
13
15
  } from '../constants';
14
16
  import type {
@@ -30,6 +32,10 @@ export function subscribeToProxy(
30
32
  second?: Subscriber<unknown> | boolean,
31
33
  third?: boolean,
32
34
  ): Subscription {
35
+ if (!this[SYMBOL_STATE].active) {
36
+ throw new Error(MESSAGE_DEACTIVATED_SUBSCRIPTION);
37
+ }
38
+
33
39
  if (isKey(first)) {
34
40
  return getReactiveValueInProxy(this, first).subscribe(second as Subscriber<unknown>, third);
35
41
  }
@@ -42,12 +48,18 @@ function subscribeToReactive(
42
48
  type: SubscriptionType,
43
49
  subscriber: Subscriber<unknown>,
44
50
  ): Subscription {
45
- this[SYMBOL_STATE].subscriptions ??= subscriptions({
51
+ const state = this[SYMBOL_STATE];
52
+
53
+ if (!state.active) {
54
+ throw new Error(MESSAGE_DEACTIVATED_SUBSCRIPTION);
55
+ }
56
+
57
+ state.subscriptions ??= subscriptions({
46
58
  keys: SUBSCRIPTION_TYPES,
47
59
  property: SUBSCRIPTION_PROPERTY,
48
60
  });
49
61
 
50
- const [subscription, existing] = this[SYMBOL_STATE].subscriptions.create({
62
+ const [subscription, existing] = state.subscriptions.create({
51
63
  key: type,
52
64
  value: subscriber,
53
65
  });
@@ -55,7 +67,7 @@ function subscribeToReactive(
55
67
  if (!existing) {
56
68
  subscriber(
57
69
  type === SUBSCRIPTION_TYPE_FROZEN
58
- ? getFrozenValue(this[SYMBOL_STATE].value)
70
+ ? getFrozenValue(state.value)
59
71
  : peekSignalValue.call(this, SUBSCRIPTION_TYPES_COPY.has(type)),
60
72
  subscription,
61
73
  );
@@ -68,11 +80,29 @@ export function subscribeToReadonly(
68
80
  this: InternalReadonly,
69
81
  subscriber: Subscriber<unknown>,
70
82
  ): Subscription {
71
- return subscribeToReactive.call(
83
+ const state = this[SYMBOL_READONLY];
84
+
85
+ if (!state.active) {
86
+ throw new Error(MESSAGE_DEACTIVATED_SUBSCRIPTION);
87
+ }
88
+
89
+ const subscription = subscribeToReactive.call(
72
90
  this,
73
91
  this.frozen ? SUBSCRIPTION_TYPE_FROZEN : SUBSCRIPTION_TYPE_READONLY,
74
92
  subscriber,
75
93
  );
94
+
95
+ state.subscriptions ??= new Set();
96
+
97
+ for (const existing of state.subscriptions) {
98
+ if (!existing.active) {
99
+ state.subscriptions.delete(existing);
100
+ }
101
+ }
102
+
103
+ state.subscriptions.add(subscription);
104
+
105
+ return subscription;
76
106
  }
77
107
 
78
108
  export function subscribeToSignal(
@@ -1,4 +1,5 @@
1
1
  import {isPlainObject} from '@oscarpalmer/atoms/is';
2
+ import {min, round} from '@oscarpalmer/atoms/math';
2
3
  import {flushHandlers} from '../batch';
3
4
  import {
4
5
  ACTIVE,
@@ -6,13 +7,21 @@ import {
6
7
  ARRAY_PEEK,
7
8
  ARRAY_THRESHOLD,
8
9
  BATCH,
10
+ MESSAGE_UPDATE_CALLBACK,
9
11
  SUBSCRIPTION_TYPE_FROZEN,
10
12
  SUBSCRIPTION_TYPES,
11
13
  SUBSCRIPTION_TYPES_COPY,
12
14
  SYMBOL_EFFECT,
15
+ SYMBOL_READONLY,
13
16
  SYMBOL_STATE,
14
17
  } from '../constants';
15
- import type {InternalArray, InternalComputed, InternalStateful, InternalStore} from '../models';
18
+ import type {
19
+ InternalArray,
20
+ InternalComputed,
21
+ InternalReadonly,
22
+ InternalStateful,
23
+ InternalStore,
24
+ } from '../models';
16
25
 
17
26
  // #region Types
18
27
 
@@ -27,13 +36,21 @@ export function emitValue(instance: InternalStateful, notify?: boolean): void {
27
36
 
28
37
  if (state.computeds != null && state.computeds.size > 0) {
29
38
  for (const computed of state.computeds) {
30
- computed.dirty = true;
39
+ if (computed.instance.active) {
40
+ computed.dirty = true;
41
+ } else {
42
+ state.computeds.delete(computed);
43
+ }
31
44
  }
32
45
  }
33
46
 
34
47
  if (state.effects != null && state.effects.size > 0) {
35
48
  for (const effect of state.effects) {
36
- BATCH.handlers.set(effect, effect);
49
+ if (effect.active) {
50
+ BATCH.handlers.set(effect, effect);
51
+ } else {
52
+ state.effects.delete(effect);
53
+ }
37
54
  }
38
55
  }
39
56
 
@@ -43,9 +60,9 @@ export function emitValue(instance: InternalStateful, notify?: boolean): void {
43
60
  const mapped = state.mapped as Map<unknown, InternalComputed>;
44
61
 
45
62
  for (const [, item] of mapped) {
46
- const fx = item[SYMBOL_EFFECT];
63
+ const {instance} = item[SYMBOL_EFFECT];
47
64
 
48
- BATCH.handlers.set(fx.instance, fx.instance);
65
+ BATCH.handlers.set(instance, instance);
49
66
  }
50
67
  }
51
68
 
@@ -86,8 +103,8 @@ export function equalArrays(
86
103
  let offset = 0;
87
104
 
88
105
  if (length >= ARRAY_THRESHOLD) {
89
- offset = Math.round(length / ARRAY_PEEK);
90
- offset = offset > ARRAY_OFFSET ? ARRAY_OFFSET : offset;
106
+ offset = round(length / ARRAY_PEEK);
107
+ offset = min([offset, ARRAY_OFFSET]);
91
108
 
92
109
  for (let index = 0; index < offset; index += 1) {
93
110
  if (
@@ -124,13 +141,21 @@ export function getFrozenValue(value: unknown): unknown {
124
141
  return frozen;
125
142
  }
126
143
 
127
- export function getJsonValue(this: InternalStateful): unknown {
144
+ export function getJsonValue(this: InternalReadonly | InternalStateful): unknown {
145
+ if (SYMBOL_READONLY in this && !this[SYMBOL_READONLY].active) {
146
+ return this[SYMBOL_READONLY].value;
147
+ }
148
+
128
149
  return this[SYMBOL_STATE].value;
129
150
  }
130
151
 
131
152
  export function getSignalValue(this: InternalStateful): unknown {
132
153
  const state = this[SYMBOL_STATE];
133
154
 
155
+ if (!state.active) {
156
+ return state.value;
157
+ }
158
+
134
159
  if (ACTIVE.computed != null) {
135
160
  state.computeds ??= new Set();
136
161
 
@@ -146,10 +171,14 @@ export function getSignalValue(this: InternalStateful): unknown {
146
171
  return state.value;
147
172
  }
148
173
 
149
- export function getStringValue(this: InternalStateful, json?: boolean): string {
150
- return json === true
151
- ? JSON.stringify(this[SYMBOL_STATE].value)
152
- : String(this[SYMBOL_STATE].value);
174
+ export function getStringValue(this: InternalReadonly | InternalStateful, json?: boolean): string {
175
+ let {value} = this[SYMBOL_STATE];
176
+
177
+ if (SYMBOL_READONLY in this && !this[SYMBOL_READONLY].active) {
178
+ value = this[SYMBOL_READONLY].value;
179
+ }
180
+
181
+ return json === true ? JSON.stringify(value) : String(value);
153
182
  }
154
183
 
155
184
  export function handleSignal(
@@ -161,6 +190,10 @@ export function handleSignal(
161
190
  ): void {
162
191
  const state = instance[SYMBOL_STATE];
163
192
 
193
+ if (!state.active) {
194
+ return;
195
+ }
196
+
164
197
  try {
165
198
  let actual = typeof origin === 'function' ? (origin as () => unknown)() : origin;
166
199
 
@@ -215,10 +248,12 @@ export function updateSignal(
215
248
  setValue: (instance: InternalStateful, value: unknown) => void,
216
249
  ): void {
217
250
  if (typeof callback !== 'function') {
218
- throw new TypeError('Callback must be a function');
251
+ throw new TypeError(MESSAGE_UPDATE_CALLBACK);
219
252
  }
220
253
 
221
- handleSignal(instance, callback(instance[SYMBOL_STATE].value), setValue);
254
+ if (instance[SYMBOL_STATE].active) {
255
+ handleSignal(instance, callback(instance[SYMBOL_STATE].value), setValue);
256
+ }
222
257
  }
223
258
 
224
259
  // #endregion
package/src/models.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type {GenericCallback, Key, PlainObject} from '@oscarpalmer/atoms/models';
2
2
  import type {Subscription, Subscriptions} from '@oscarpalmer/atoms/subscription';
3
- import {SYMBOL_EFFECT, SYMBOL_STATE, type PROPERTY_LENGTH} from './constants';
3
+ import {SYMBOL_EFFECT, SYMBOL_READONLY, SYMBOL_STATE, type PROPERTY_LENGTH} from './constants';
4
4
 
5
5
  // #region Types
6
6
 
@@ -23,10 +23,21 @@ export type ComputedEffect = {
23
23
  notify: boolean;
24
24
  };
25
25
 
26
- export type Effect = {};
26
+ export type Effect = {
27
+ /**
28
+ * Is the effect active?
29
+ */
30
+ get active(): boolean;
31
+ /**
32
+ * Stop the effect
33
+ */
34
+ stop(): void;
35
+ };
27
36
 
28
37
  export type EffectState = {
38
+ active: boolean;
29
39
  callback: GenericCallback;
40
+ name: string;
30
41
  };
31
42
 
32
43
  export type InternalArray = {
@@ -35,11 +46,19 @@ export type InternalArray = {
35
46
 
36
47
  export type InternalComputed = {
37
48
  [SYMBOL_EFFECT]: ComputedEffect;
49
+ } & Computed<unknown> &
50
+ InternalStateful;
51
+
52
+ export type InternalEffect = {
53
+ [SYMBOL_STATE]: EffectState;
54
+ } & Effect;
55
+
56
+ export type InternalReactive = {
38
57
  [SYMBOL_STATE]: SignalState;
39
- } & Computed<unknown>;
58
+ } & Reactive<unknown>;
40
59
 
41
60
  export type InternalReadonly = {
42
- frozen: boolean;
61
+ [SYMBOL_READONLY]: ReadonlyState;
43
62
  } & InternalStateful &
44
63
  ReadonlySignal<unknown>;
45
64
 
@@ -54,6 +73,16 @@ export type InternalStore = {
54
73
  } & ReactiveStore<PlainObject>;
55
74
 
56
75
  export type Reactive<Value> = {
76
+ /**
77
+ * Is the signal active?
78
+ */
79
+ get active(): boolean;
80
+
81
+ /**
82
+ * Deactivate the signal, preventing further updates
83
+ */
84
+ deactivate(): void;
85
+
57
86
  /**
58
87
  * Get the value
59
88
  *
@@ -323,15 +352,18 @@ export type ReactiveOptions<Value> = {
323
352
  };
324
353
 
325
354
  export type ReactiveProxyState = {
355
+ derived?: Set<Computed<unknown>>;
326
356
  isArray: boolean;
327
357
  length?: Signal<number>;
328
358
  mapped?: Map<string, InternalComputed>;
329
359
  } & SignalState;
330
360
 
331
361
  export type ReactiveState<Value = unknown, Item = Value> = {
362
+ active: boolean;
332
363
  computeds?: Set<ComputedEffect>;
333
364
  effects?: Set<EffectState>;
334
365
  equal?: (first: Item, second: Item) => boolean;
366
+ name: string;
335
367
  promise?: Promise<unknown>;
336
368
  promises?: Map<Key, Promise<never>>;
337
369
  subscriptions?: Subscriptions<GenericCallback>;
@@ -506,6 +538,13 @@ export type ReadonlySignalValue<Value> = Value extends unknown[]
506
538
  ? Readonly<Value>
507
539
  : Value;
508
540
 
541
+ export type ReadonlyState = {
542
+ active: boolean;
543
+ name: string;
544
+ subscriptions?: Set<Subscription>;
545
+ value?: unknown;
546
+ };
547
+
509
548
  export type Signal<Value> = {
510
549
  /**
511
550
  * Get a readonly version of the signal