@oscarpalmer/mora 0.38.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 -4
  3. package/dist/constants.d.mts +16 -10
  4. package/dist/constants.mjs +12 -6
  5. package/dist/effect.d.mts +2 -3
  6. package/dist/effect.mjs +27 -8
  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 -11
  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 +18 -13
  17. package/dist/models.d.mts +38 -5
  18. package/dist/mora.full.mjs +555 -276
  19. package/dist/value/array.d.mts +1 -3
  20. package/dist/value/array.mjs +46 -22
  21. package/dist/value/computed.d.mts +1 -3
  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 -3
  26. package/dist/value/signal.mjs +9 -6
  27. package/dist/value/store.d.mts +1 -3
  28. package/dist/value/store.mjs +9 -6
  29. package/package.json +5 -12
  30. package/src/batch.ts +8 -4
  31. package/src/constants.ts +26 -16
  32. package/src/effect.ts +37 -7
  33. package/src/helpers/is.ts +18 -8
  34. package/src/helpers/misc.ts +121 -2
  35. package/src/helpers/proxy.ts +59 -9
  36. package/src/helpers/subscription.ts +34 -4
  37. package/src/helpers/value.ts +48 -15
  38. package/src/models.ts +42 -3
  39. package/src/value/array.ts +100 -21
  40. package/src/value/computed.ts +29 -10
  41. package/src/value/readonly.ts +38 -33
  42. package/src/value/signal.ts +11 -5
  43. package/src/value/store.ts +11 -5
  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,10 +5,17 @@ import type {
5
5
  Key,
6
6
  PlainObject,
7
7
  } from '@oscarpalmer/atoms/models';
8
- import {attempt} from '@oscarpalmer/atoms/result';
8
+ import {getNumber} from '@oscarpalmer/atoms/number';
9
+ import {getString} from '@oscarpalmer/atoms/string';
9
10
  import {startBatch, stopBatch} from '../batch';
10
- import {PROPERTY_LENGTH, SYMBOL_EFFECT, SYMBOL_STATE} from '../constants';
11
- 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';
12
19
  import {internalComputed} from '../value/computed';
13
20
  import {emitValue, getSignalValue, peekSignalValue} from './value';
14
21
 
@@ -22,7 +29,7 @@ export function getReactiveValueInProxy(
22
29
 
23
30
  state.mapped ??= new Map();
24
31
 
25
- const mapKey = String(key);
32
+ const mapKey = getString(key);
26
33
 
27
34
  let item = state.mapped.get(mapKey);
28
35
 
@@ -40,9 +47,15 @@ export function getReactiveValueInProxy(
40
47
  }
41
48
 
42
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
+
43
56
  let signal: InternalComputed | undefined;
44
57
 
45
- if (this[SYMBOL_STATE].isArray ? typeof first === 'number' : isKey(first)) {
58
+ if (state.isArray ? typeof first === 'number' : isKey(first)) {
46
59
  signal = getReactiveValueInProxy(this, first as Key);
47
60
  }
48
61
 
@@ -50,7 +63,7 @@ export function getValueInProxy(this: InternalArray | InternalStore, first?: unk
50
63
  }
51
64
 
52
65
  function isProxyKey(isArray: boolean, value: unknown): value is Key {
53
- return isArray ? typeof value === 'number' : isKey(value);
66
+ return (isArray && typeof value === 'number') || isKey(value);
54
67
  }
55
68
 
56
69
  function isProxyObject(isArray: boolean, value: unknown): value is ArrayOrPlainObject {
@@ -60,6 +73,10 @@ function isProxyObject(isArray: boolean, value: unknown): value is ArrayOrPlainO
60
73
  export function notifyProxyValue(this: InternalArray | InternalStore): void {
61
74
  const state = this[SYMBOL_STATE];
62
75
 
76
+ if (!state.active) {
77
+ return;
78
+ }
79
+
63
80
  state.mapped ??= new Map();
64
81
 
65
82
  const values = [...state.mapped.values()];
@@ -157,6 +174,10 @@ export function setProxyValue(
157
174
  ): void {
158
175
  const state = this[SYMBOL_STATE];
159
176
 
177
+ if (!state.active) {
178
+ return;
179
+ }
180
+
160
181
  if (state.isArray && first === PROPERTY_LENGTH) {
161
182
  (state.value as unknown[]).length = second as number;
162
183
 
@@ -232,8 +253,12 @@ export function setValueInProxy(
232
253
  ): boolean {
233
254
  const state = instance[SYMBOL_STATE];
234
255
 
256
+ if (!state.active) {
257
+ return true;
258
+ }
259
+
235
260
  if (state.isArray) {
236
- const isIndex = !Number.isNaN(Number(property));
261
+ const isIndex = !Number.isNaN(getNumber(property));
237
262
  const isLength = property === PROPERTY_LENGTH;
238
263
 
239
264
  if (!(isIndex || isLength)) {
@@ -256,12 +281,37 @@ export function setValueInProxy(
256
281
  return true;
257
282
  }
258
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
+
259
307
  export function updateProxyValue(this: InternalArray | InternalStore, callback: unknown): void {
260
308
  if (typeof callback !== 'function') {
261
- throw new TypeError('Callback must be a function');
309
+ throw new TypeError(MESSAGE_UPDATE_CALLBACK);
262
310
  }
263
311
 
264
- setProxyValue.call(this, callback(this[SYMBOL_STATE].value));
312
+ if (this[SYMBOL_STATE].active) {
313
+ setProxyValue.call(this, callback(this[SYMBOL_STATE].value));
314
+ }
265
315
  }
266
316
 
267
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,6 +1,5 @@
1
1
  import {isPlainObject} from '@oscarpalmer/atoms/is';
2
- import {round} from '@oscarpalmer/atoms/math';
3
- import {attempt} from '@oscarpalmer/atoms/result';
2
+ import {min, round} from '@oscarpalmer/atoms/math';
4
3
  import {flushHandlers} from '../batch';
5
4
  import {
6
5
  ACTIVE,
@@ -8,13 +7,21 @@ import {
8
7
  ARRAY_PEEK,
9
8
  ARRAY_THRESHOLD,
10
9
  BATCH,
10
+ MESSAGE_UPDATE_CALLBACK,
11
11
  SUBSCRIPTION_TYPE_FROZEN,
12
12
  SUBSCRIPTION_TYPES,
13
13
  SUBSCRIPTION_TYPES_COPY,
14
14
  SYMBOL_EFFECT,
15
+ SYMBOL_READONLY,
15
16
  SYMBOL_STATE,
16
17
  } from '../constants';
17
- import type {InternalArray, InternalComputed, InternalStateful, InternalStore} from '../models';
18
+ import type {
19
+ InternalArray,
20
+ InternalComputed,
21
+ InternalReadonly,
22
+ InternalStateful,
23
+ InternalStore,
24
+ } from '../models';
18
25
 
19
26
  // #region Types
20
27
 
@@ -29,13 +36,21 @@ export function emitValue(instance: InternalStateful, notify?: boolean): void {
29
36
 
30
37
  if (state.computeds != null && state.computeds.size > 0) {
31
38
  for (const computed of state.computeds) {
32
- computed.dirty = true;
39
+ if (computed.instance.active) {
40
+ computed.dirty = true;
41
+ } else {
42
+ state.computeds.delete(computed);
43
+ }
33
44
  }
34
45
  }
35
46
 
36
47
  if (state.effects != null && state.effects.size > 0) {
37
48
  for (const effect of state.effects) {
38
- BATCH.handlers.set(effect, effect);
49
+ if (effect.active) {
50
+ BATCH.handlers.set(effect, effect);
51
+ } else {
52
+ state.effects.delete(effect);
53
+ }
39
54
  }
40
55
  }
41
56
 
@@ -45,9 +60,9 @@ export function emitValue(instance: InternalStateful, notify?: boolean): void {
45
60
  const mapped = state.mapped as Map<unknown, InternalComputed>;
46
61
 
47
62
  for (const [, item] of mapped) {
48
- const fx = item[SYMBOL_EFFECT];
63
+ const {instance} = item[SYMBOL_EFFECT];
49
64
 
50
- BATCH.handlers.set(fx.instance, fx.instance);
65
+ BATCH.handlers.set(instance, instance);
51
66
  }
52
67
  }
53
68
 
@@ -89,7 +104,7 @@ export function equalArrays(
89
104
 
90
105
  if (length >= ARRAY_THRESHOLD) {
91
106
  offset = round(length / ARRAY_PEEK);
92
- offset = offset > ARRAY_OFFSET ? ARRAY_OFFSET : offset;
107
+ offset = min([offset, ARRAY_OFFSET]);
93
108
 
94
109
  for (let index = 0; index < offset; index += 1) {
95
110
  if (
@@ -126,13 +141,21 @@ export function getFrozenValue(value: unknown): unknown {
126
141
  return frozen;
127
142
  }
128
143
 
129
- 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
+
130
149
  return this[SYMBOL_STATE].value;
131
150
  }
132
151
 
133
152
  export function getSignalValue(this: InternalStateful): unknown {
134
153
  const state = this[SYMBOL_STATE];
135
154
 
155
+ if (!state.active) {
156
+ return state.value;
157
+ }
158
+
136
159
  if (ACTIVE.computed != null) {
137
160
  state.computeds ??= new Set();
138
161
 
@@ -148,10 +171,14 @@ export function getSignalValue(this: InternalStateful): unknown {
148
171
  return state.value;
149
172
  }
150
173
 
151
- export function getStringValue(this: InternalStateful, json?: boolean): string {
152
- return json === true
153
- ? JSON.stringify(this[SYMBOL_STATE].value)
154
- : 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);
155
182
  }
156
183
 
157
184
  export function handleSignal(
@@ -163,6 +190,10 @@ export function handleSignal(
163
190
  ): void {
164
191
  const state = instance[SYMBOL_STATE];
165
192
 
193
+ if (!state.active) {
194
+ return;
195
+ }
196
+
166
197
  try {
167
198
  let actual = typeof origin === 'function' ? (origin as () => unknown)() : origin;
168
199
 
@@ -217,10 +248,12 @@ export function updateSignal(
217
248
  setValue: (instance: InternalStateful, value: unknown) => void,
218
249
  ): void {
219
250
  if (typeof callback !== 'function') {
220
- throw new TypeError('Callback must be a function');
251
+ throw new TypeError(MESSAGE_UPDATE_CALLBACK);
221
252
  }
222
253
 
223
- handleSignal(instance, callback(instance[SYMBOL_STATE].value), setValue);
254
+ if (instance[SYMBOL_STATE].active) {
255
+ handleSignal(instance, callback(instance[SYMBOL_STATE].value), setValue);
256
+ }
224
257
  }
225
258
 
226
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 = {
@@ -38,8 +49,16 @@ export type InternalComputed = {
38
49
  } & Computed<unknown> &
39
50
  InternalStateful;
40
51
 
52
+ export type InternalEffect = {
53
+ [SYMBOL_STATE]: EffectState;
54
+ } & Effect;
55
+
56
+ export type InternalReactive = {
57
+ [SYMBOL_STATE]: SignalState;
58
+ } & Reactive<unknown>;
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