@oscarpalmer/mora 0.28.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/batch.mjs +15 -6
  2. package/dist/constants.d.mts +0 -1
  3. package/dist/constants.mjs +4 -3
  4. package/dist/effect.d.mts +5 -8
  5. package/dist/effect.mjs +23 -19
  6. package/dist/helpers/is.d.mts +9 -9
  7. package/dist/helpers/is.mjs +6 -0
  8. package/dist/helpers/proxy.d.mts +5 -9
  9. package/dist/helpers/proxy.mjs +4 -4
  10. package/dist/helpers/value.d.mts +3 -3
  11. package/dist/helpers/value.mjs +21 -3
  12. package/dist/index.d.mts +7 -8
  13. package/dist/index.mjs +1 -1
  14. package/dist/models.d.mts +356 -18
  15. package/dist/mora.full.mjs +458 -409
  16. package/dist/subscription.d.mts +1 -9
  17. package/dist/subscription.mjs +14 -15
  18. package/dist/value/array.d.mts +5 -133
  19. package/dist/value/array.mjs +91 -137
  20. package/dist/value/computed.d.mts +4 -12
  21. package/dist/value/computed.mjs +54 -50
  22. package/dist/value/reactive.d.mts +3 -38
  23. package/dist/value/reactive.mjs +10 -49
  24. package/dist/value/signal.d.mts +5 -21
  25. package/dist/value/signal.mjs +27 -49
  26. package/dist/value/store.d.mts +9 -92
  27. package/dist/value/store.mjs +42 -49
  28. package/package.json +8 -8
  29. package/src/batch.ts +22 -9
  30. package/src/constants.ts +3 -4
  31. package/src/effect.ts +31 -26
  32. package/src/helpers/is.ts +11 -10
  33. package/src/helpers/proxy.ts +23 -18
  34. package/src/helpers/value.ts +38 -3
  35. package/src/index.ts +6 -7
  36. package/src/models.ts +431 -16
  37. package/src/subscription.ts +20 -20
  38. package/src/value/array.ts +183 -265
  39. package/src/value/computed.ts +80 -74
  40. package/src/value/reactive.ts +16 -64
  41. package/src/value/signal.ts +34 -71
  42. package/src/value/store.ts +84 -177
@@ -1,68 +1,73 @@
1
1
  import type {ArrayOrPlainObject, Key, PlainObject} from '@oscarpalmer/atoms/models';
2
2
  import {PROPERTY_LENGTH} from '../constants';
3
- import type {InternalComputed, ReactiveState, SetValueInProxyParameters} from '../models';
4
- import type {ReactiveArray} from '../value/array';
5
- import {type Computed, computed} from '../value/computed';
6
- import type {Store} from '../value/store';
3
+ import type {
4
+ Computed,
5
+ ComputedEffect,
6
+ ReactiveArray,
7
+ ReactiveState,
8
+ ReactiveStore,
9
+ SetValueInProxyParameters,
10
+ } from '../models';
11
+ import {internalComputed} from '../value/computed';
7
12
  import {emitValue} from './value';
8
13
 
9
14
  export function emityProxyValues<Value>(
10
15
  state: ReactiveState<Value, Value>,
11
- mapped: Map<Key, Computed<unknown>>,
16
+ mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
12
17
  ): void;
13
18
 
14
19
  export function emityProxyValues<Value>(
15
20
  state: ReactiveState<Value[], Value>,
16
- mapped: Map<Key, Computed<unknown>>,
21
+ mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
17
22
  ): void;
18
23
 
19
24
  export function emityProxyValues(
20
25
  state: ReactiveState<unknown, unknown>,
21
- mapped: Map<Key, Computed<unknown>>,
26
+ mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
22
27
  ): void {
23
28
  const values = [...mapped.values()];
24
29
  const {length} = values;
25
30
 
26
31
  for (let index = 0; index < length; index += 1) {
27
- (values[index] as unknown as InternalComputed).effect.dirty = true;
32
+ values[index][1].dirty = true;
28
33
  }
29
34
 
30
35
  emitValue(state);
31
36
  }
32
37
 
33
- export function getReactiveValueInProxy<Value>(
38
+ export function getReactiveValueInProxy<Value, Result = Value>(
34
39
  array: ReactiveArray<Value>,
35
- mapped: Map<Key, Computed<unknown>>,
40
+ mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
36
41
  index: number,
37
42
  isArray: true,
38
- ): Computed<unknown>;
43
+ ): Computed<Result>;
39
44
 
40
45
  export function getReactiveValueInProxy<Value extends PlainObject>(
41
- store: Store<Value>,
42
- mapped: Map<Key, Computed<unknown>>,
46
+ store: ReactiveStore<Value>,
47
+ mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
43
48
  key: Key,
44
49
  isArray: false,
45
50
  ): Computed<unknown>;
46
51
 
47
52
  export function getReactiveValueInProxy(
48
- reactive: ReactiveArray<unknown> | Store<PlainObject>,
49
- mapped: Map<Key, Computed<unknown>>,
53
+ reactive: ReactiveArray<unknown> | ReactiveStore<PlainObject>,
54
+ mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
50
55
  key: Key,
51
56
  isArray: boolean,
52
57
  ): Computed<unknown> {
53
58
  let item = mapped.get(key);
54
59
 
55
60
  if (item == null) {
56
- item = computed(() =>
61
+ item = internalComputed(() =>
57
62
  isArray
58
63
  ? (reactive.get() as unknown[]).at(key as number)
59
64
  : (reactive.get() as PlainObject)[key],
60
- ) as Computed<unknown>;
65
+ );
61
66
 
62
67
  mapped.set(key, item);
63
68
  }
64
69
 
65
- return item;
70
+ return item[0];
66
71
  }
67
72
 
68
73
  export function setProxyValue<Value, Item = Value>(
@@ -1,10 +1,10 @@
1
1
  import {flushHandlers} from '../batch';
2
2
  import {ACTIVE, ARRAY_OFFSET, ARRAY_PEEK, ARRAY_THRESHOLD, BATCH} from '../constants';
3
- import type {InternalComputed, ReactiveState} from '../models';
3
+ import type {ReactiveState} from '../models';
4
4
 
5
5
  export function emitValue<Value>(state: ReactiveState<Value, never>): void {
6
6
  for (const computed of state.computeds) {
7
- (computed as unknown as InternalComputed).effect.dirty = true;
7
+ computed.dirty = true;
8
8
  }
9
9
 
10
10
  for (const effect of state.effects) {
@@ -55,7 +55,7 @@ export function equalArrays<Value>(
55
55
  return true;
56
56
  }
57
57
 
58
- export function getValue<Value>(state: ReactiveState<Value, never>): Value {
58
+ export function getSimpleValue<Value>(state: ReactiveState<Value, never>): Value {
59
59
  if (ACTIVE.computed != null) {
60
60
  state.computeds.add(ACTIVE.computed);
61
61
  }
@@ -66,3 +66,38 @@ export function getValue<Value>(state: ReactiveState<Value, never>): Value {
66
66
 
67
67
  return state.value;
68
68
  }
69
+
70
+ export function handleSimpleValue<Value>(
71
+ state: ReactiveState<Value, Value>,
72
+ origin: Value | (() => Value | Promise<Value>) | Promise<Value>,
73
+ setValue: (state: ReactiveState<Value, Value>, value: Value) => void,
74
+ onAfter?: () => void,
75
+ ): void {
76
+ try {
77
+ let actual = typeof origin === 'function' ? (origin as () => unknown)() : origin;
78
+
79
+ if (actual instanceof Promise) {
80
+ state.promise = actual;
81
+
82
+ void actual
83
+ .then(value => {
84
+ if (actual === state.promise) {
85
+ state.promise = undefined;
86
+
87
+ setValue(state, value);
88
+ }
89
+ })
90
+ .catch(() => {
91
+ if (actual === state.promise) {
92
+ state.promise = undefined;
93
+ }
94
+ });
95
+ } else {
96
+ setValue(state, actual as Value);
97
+ }
98
+ } catch {
99
+ // ?
100
+ } finally {
101
+ onAfter?.();
102
+ }
103
+ }
package/src/index.ts CHANGED
@@ -1,9 +1,8 @@
1
1
  export {startBatch, stopBatch} from './batch';
2
- export {effect, type Effect} from './effect';
2
+ export {effect} from './effect';
3
3
  export {isArray, isComputed, isEffect, isReactive, isSignal} from './helpers/is';
4
- export type {Unsubscribe} from './models';
5
- export {array, type ReactiveArray} from './value/array';
6
- export {computed, type Computed} from './value/computed';
7
- export type {Reactive} from './value/reactive';
8
- export {signal, type Signal} from './value/signal';
9
- export {store, type Store} from './value/store';
4
+ export type {Computed, Effect, ReactiveArray, ReactiveStore, Signal, Unsubscribe} from './models';
5
+ export {array} from './value/array';
6
+ export {computed} from './value/computed';
7
+ export {signal} from './value/signal';
8
+ export {store} from './value/store';
package/src/models.ts CHANGED
@@ -1,37 +1,256 @@
1
1
  import type {GenericCallback, Key} from '@oscarpalmer/atoms/models';
2
- import type {Effect} from './effect';
3
- import type {Subscription} from './subscription';
4
- import type {Computed} from './value/computed';
5
- import type {Signal} from './value/signal';
2
+ import type {PROPERTY_LENGTH} from './constants';
6
3
 
7
4
  export type Active = {
8
- computed?: Computed<unknown>;
9
- effect?: Effect;
5
+ computed?: ComputedEffect;
6
+ effect?: EffectState;
10
7
  };
11
8
 
12
9
  export type Batch = {
13
10
  depth: number;
14
- handlers: Set<Effect | Subscription>;
11
+ flushing: boolean;
12
+ handlers: Set<EffectState | Subscription>;
15
13
  };
16
14
 
15
+ export type Computed<Value> = Reactive<Value> & SimpleReactive<Value>;
16
+
17
17
  export type ComputedEffect = {
18
18
  dirty: boolean;
19
- instance: Effect;
19
+ instance: EffectState;
20
20
  };
21
21
 
22
+ export type Effect = {};
23
+
22
24
  export type EffectState = {
23
25
  callback: GenericCallback;
24
26
  };
25
27
 
26
- export type InternalComputed = {
27
- readonly effect: ComputedEffect;
28
- readonly state: ReactiveState<unknown, unknown>;
29
- };
28
+ export type Reactive<Value> = {
29
+ /**
30
+ * JSON representation of the value
31
+ *
32
+ * @returns JSON value
33
+ */
34
+ toJSON(): Value;
30
35
 
31
- export type InternalEffect = {
32
- state: EffectState;
36
+ /**
37
+ * String representation of the value
38
+ *
39
+ * @returns Value as string
40
+ */
41
+ toString(): string;
33
42
  };
34
43
 
44
+ export type ReactiveArray<Item> = {
45
+ /**
46
+ * The length of the array
47
+ */
48
+ get length(): number;
49
+
50
+ /**
51
+ * Set the length of the array
52
+ */
53
+ set length(value: number);
54
+
55
+ /**
56
+ * Get the value at an index
57
+ *
58
+ * @param index Index of item to get _(if negative, starts from the end)_
59
+ * @returns Item at index, or `undefined` if it doesn't exist
60
+ */
61
+ at(index: number): Item | undefined;
62
+
63
+ /**
64
+ * Clear the array
65
+ */
66
+ clear(): void;
67
+
68
+ /**
69
+ * Create a computed, filtered array
70
+ *
71
+ * @param callback Callback to evaluate each item
72
+ * @returns Computed array of filtered items
73
+ */
74
+ filter(callback: (item: Item, index: number, array: Item[]) => boolean): Computed<Item[]>;
75
+
76
+ /**
77
+ * Get the array
78
+ *
79
+ * @returns Array of items
80
+ */
81
+ get(): Item[];
82
+
83
+ /**
84
+ * Get the value at an index
85
+ *
86
+ * @param index Index of item to get _(if negative, starts from the end)_
87
+ * @returns Item at index, or `undefined` if it doesn't exist
88
+ */
89
+ get(index: number): Item | undefined;
90
+
91
+ /**
92
+ * Get the length of the array
93
+ *
94
+ * @returns Length of the array
95
+ */
96
+ get(property: typeof PROPERTY_LENGTH): number;
97
+
98
+ /**
99
+ * Create a computed, mapped array
100
+ *
101
+ * @param callback Callback to transform each item
102
+ * @returns Computed array of mapped items
103
+ */
104
+ map<Mapped>(callback: (item: Item, index: number, array: Item[]) => Mapped): Computed<Mapped[]>;
105
+
106
+ /**
107
+ * Notify dependents of changes
108
+ *
109
+ * _This bypasses equality checks and will immediately notify dependents.
110
+ * Use this only if you're modifying nested data that would be ignored by equality checks._
111
+ */
112
+ notify(): void;
113
+
114
+ /**
115
+ * Get the array _(without reactivity)_
116
+ *
117
+ * @returns Array of items
118
+ */
119
+ peek(): Item[];
120
+
121
+ /**
122
+ * Get the value at an index _(without reactivity)_
123
+ *
124
+ * @param index Index of item to get _(if negative, starts from the end)_
125
+ * @returns Item at index, or `undefined` if it doesn't exist
126
+ */
127
+ peek(index: number): Item | undefined;
128
+
129
+ /**
130
+ * Get the length of the array _(without reactivity)_
131
+ *
132
+ * @returns Length of the array
133
+ */
134
+ peek(property: typeof PROPERTY_LENGTH): number;
135
+
136
+ /**
137
+ * Remove and return the last item of the array
138
+ *
139
+ * @returns Removed item, or `undefined` if the array is empty
140
+ */
141
+ pop(): Item | undefined;
142
+
143
+ /**
144
+ * Add items to the end of the array
145
+ *
146
+ * @param items Items to add
147
+ * @returns New array length
148
+ */
149
+ push(...items: Item[]): number;
150
+
151
+ /**
152
+ * Create a computed, filtered, and mapped array
153
+ *
154
+ * @param filter Callback to evaluate each item
155
+ * @param map Callback to transform each item
156
+ * @returns Computed array of mapped items
157
+ */
158
+ select<Mapped>(
159
+ filter: (item: Item, index: number, array: Item[]) => boolean,
160
+ map: (item: Item, index: number, array: Item[]) => Mapped,
161
+ ): Computed<Mapped[]>;
162
+
163
+ /**
164
+ * Set the value
165
+ *
166
+ * @param value New array of items _(defaults to an empty array)_
167
+ */
168
+ set(
169
+ value?:
170
+ | Item[]
171
+ | (() => null | undefined | Item[] | Promise<null | undefined | Item[]>)
172
+ | Promise<null | undefined | Item[]>,
173
+ ): void;
174
+
175
+ /**
176
+ * Set the value at an index
177
+ *
178
+ * @param index Index of item to set _(if negative, starts from the end)_
179
+ * @param value New item
180
+ */
181
+ set(index: number, value: Item | (() => Item | Promise<Item>) | Promise<Item>): void;
182
+
183
+ /**
184
+ * Set the length of the array
185
+ *
186
+ * @param value New array length
187
+ */
188
+ set(property: typeof PROPERTY_LENGTH, value: number): void;
189
+
190
+ /**
191
+ * Remove and return the first item of the array
192
+ *
193
+ * @returns Removed item, or `undefined` if the array is empty
194
+ */
195
+ shift(): Item | undefined;
196
+
197
+ /**
198
+ * Remove and return items from the array _(and optionally add new items)_
199
+ *
200
+ * @param from Index to start removing items from
201
+ * @param to Index to stop removing items at _(defaults to the end of the array)_
202
+ * @param items Optional items to add
203
+ * @returns Removed items
204
+ */
205
+ splice(from: number, to?: number, ...items: Item[]): Item[];
206
+
207
+ /**
208
+ * Subscribe to changes
209
+ *
210
+ * @param callback Callback for changes
211
+ * @returns Unsubscribe callback
212
+ */
213
+ subscribe(callback: (value: Item[]) => void): Unsubscribe;
214
+
215
+ /**
216
+ * Subscribe to changes at a specific index
217
+ *
218
+ * @param index Index of item to subscribe to
219
+ * @param callback Callback for changes
220
+ * @returns Unsubscribe callback
221
+ */
222
+ subscribe(index: number, callback: (value: Item | undefined) => void): Unsubscribe;
223
+
224
+ /**
225
+ * Add items to the beginning of the array
226
+ * @param items Items to add
227
+ * @returns New array length
228
+ */
229
+ unshift(...items: Item[]): number;
230
+
231
+ /**
232
+ * Unsubscribe from changes for a specific index
233
+ *
234
+ * @param index Index of the value to unsubscribe from
235
+ * @param callback Callback to unsubscribe
236
+ */
237
+ unsubscribe(index: number, callback: (item: Item | undefined) => void): void;
238
+
239
+ /**
240
+ * Unsubscribe from changes
241
+ *
242
+ * @param callback Callback to unsubscribe
243
+ */
244
+ unsubscribe(callback: (array: Item[]) => void): void;
245
+
246
+ /**
247
+ * Update the value _(based on the current value)_
248
+ *
249
+ * @param callback Callback to update the value
250
+ */
251
+ update(callback: (value: Item[]) => Item[]): void;
252
+ } & Reactive<Item[]>;
253
+
35
254
  export type ReactiveOptions<Value> = {
36
255
  /**
37
256
  * Method for comparing values for equality
@@ -44,8 +263,8 @@ export type ReactiveOptions<Value> = {
44
263
  };
45
264
 
46
265
  export type ReactiveState<Value, Equal> = {
47
- computeds: Set<Computed<unknown>>;
48
- effects: Set<Effect>;
266
+ computeds: Set<ComputedEffect>;
267
+ effects: Set<EffectState>;
49
268
  equal: (first: Equal, second: Equal) => boolean;
50
269
  promise?: Promise<Value>;
51
270
  promises?: Map<Key, Promise<never>>;
@@ -53,6 +272,147 @@ export type ReactiveState<Value, Equal> = {
53
272
  value: Value;
54
273
  };
55
274
 
275
+ export type ReactiveStore<Value> = {
276
+ /**
277
+ * Get the value
278
+ *
279
+ * @returns Current value
280
+ */
281
+ get(): Value;
282
+
283
+ /**
284
+ * Get a value by key
285
+ *
286
+ * @param key Key of the value to get
287
+ * @returns Value for the specified key, or `undefined` if it doesn't exist
288
+ */
289
+ get<Key extends keyof Value>(key: Key): Value[Key];
290
+
291
+ /**
292
+ * Get a value by key
293
+ *
294
+ * @param key Key of the value to get
295
+ * @returns Value for the specified key, or `undefined` if it doesn't exist
296
+ */
297
+ get(key: Key): unknown;
298
+
299
+ /**
300
+ * Notify dependents of changes
301
+ *
302
+ * _This bypasses equality checks and will immediately notify dependents.
303
+ * Use this only if you're modifying nested data that would be ignored by equality checks._
304
+ */
305
+ notify(): void;
306
+
307
+ /**
308
+ * Get the value _(without reactivity)_
309
+ *
310
+ * @returns Current value
311
+ */
312
+ peek(): Value;
313
+
314
+ /**
315
+ * Get a value by key _(without reactivity)_
316
+ *
317
+ * @param key Key of the value to get
318
+ * @returns Value for the specified key, or `undefined` if it doesn't exist
319
+ */
320
+ peek<Key extends keyof Value>(key: Key): Value[Key];
321
+
322
+ /**
323
+ * Get a value by key _(without reactivity)_
324
+ *
325
+ * @param key Key of the value to get
326
+ * @returns Value for the specified key, or `undefined` if it doesn't exist
327
+ */
328
+ peek(key: Key): unknown;
329
+
330
+ /**
331
+ * Set the value
332
+ *
333
+ * @param value New value _(defaults to an empty object)_
334
+ */
335
+ set(
336
+ value?:
337
+ | Value
338
+ | (() => null | undefined | Value | Promise<null | undefined | Value>)
339
+ | Promise<null | undefined | Value>,
340
+ ): void;
341
+
342
+ /**
343
+ * Set a value by key
344
+ *
345
+ * @param key Key of the value to set
346
+ * @param value New value
347
+ */
348
+ set<Key extends keyof Value>(
349
+ key: Key,
350
+ value: Value[Key] | (() => Value[Key] | Promise<Value[Key]>) | Promise<Value[Key]>,
351
+ ): void;
352
+
353
+ /**
354
+ * Set a value by key
355
+ *
356
+ * @param key Key of the value to set
357
+ * @param value New value
358
+ */
359
+ set(key: Key, value: unknown): void;
360
+
361
+ /**
362
+ * Subscribe to changes
363
+ *
364
+ * @param callback Callback for changes
365
+ * @returns Unsubscribe callback
366
+ */
367
+ subscribe(callback: (value: Value) => void): Unsubscribe;
368
+
369
+ /**
370
+ * Subscribe to changes for a specific key
371
+ *
372
+ * @param key Key of the value to subscribe to
373
+ * @param callback Callback for changes
374
+ * @returns Unsubscribe callback
375
+ */
376
+ subscribe<Key extends keyof Value>(
377
+ key: Key,
378
+ callback: (value: Value[Key] | undefined) => void,
379
+ ): Unsubscribe;
380
+
381
+ /**
382
+ * Subscribe to changes for a specific key
383
+ *
384
+ * @param key Key of the value to subscribe to
385
+ * @param callback Callback for changes
386
+ * @returns Unsubscribe callback
387
+ */
388
+ subscribe(key: Key, callback: (value: unknown) => void): Unsubscribe;
389
+
390
+ /**
391
+ * Unsubscribe from changes for a specific key
392
+ *
393
+ * @param key Key of the value to unsubscribe from
394
+ * @param callback Callback to unsubscribe
395
+ */
396
+ unsubscribe<Key extends keyof Value>(
397
+ key: Key,
398
+ callback: (value: Value[Key] | undefined) => void,
399
+ ): void;
400
+
401
+ /**
402
+ * Unsubscribe from changes
403
+ *
404
+ * @param callback Callback to unsubscribe
405
+ */
406
+ unsubscribe(callback: (value: Value) => void): void;
407
+
408
+ /**
409
+ * Update the value _(based on the current value)_
410
+ *
411
+ * @param callback Callback to update the value
412
+ */
413
+ update(callback: (value: Value) => Value): void;
414
+ } & Reactive<Value>;
415
+
56
416
  export type SetValueInProxyParameters<Value, Equal> = {
57
417
  target: Value;
58
418
  property: PropertyKey;
@@ -62,6 +422,61 @@ export type SetValueInProxyParameters<Value, Equal> = {
62
422
  length?: Signal<number>;
63
423
  };
64
424
 
425
+ export type Signal<Value> = {
426
+ /**
427
+ * Set the value
428
+ *
429
+ * @param value New value
430
+ */
431
+ set(value: Value | (() => Value | Promise<Value>) | Promise<Value>): void;
432
+
433
+ /**
434
+ * Update the value _(based on the current value)_
435
+ *
436
+ * @param callback Callback to update the value
437
+ */
438
+ update(callback: (value: Value) => Value): void;
439
+ } & Reactive<Value> &
440
+ SimpleReactive<Value>;
441
+
442
+ type SimpleReactive<Value> = {
443
+ /**
444
+ * Get the value
445
+ *
446
+ * @returns Current value
447
+ */
448
+ get(): Value;
449
+
450
+ /**
451
+ * Get the value _(without reactivity)_
452
+ *
453
+ * @returns Current value
454
+ */
455
+ peek(): Value;
456
+
457
+ /**
458
+ * Subscribe to changes
459
+ *
460
+ * @param callback Callback for changes
461
+ * @returns Unsubscribe callback
462
+ */
463
+ subscribe(callback: (value: Value) => void): Unsubscribe;
464
+
465
+ /**
466
+ * Unsubscribe from changes
467
+ *
468
+ * @param callback Callback to unsubscribe
469
+ */
470
+ unsubscribe(callback: (value: Value) => void): void;
471
+ };
472
+
473
+ export type Subscription = {
474
+ callback: GenericCallback;
475
+ state: ReactiveState<unknown, never>;
476
+
477
+ destroy(): void;
478
+ };
479
+
65
480
  /**
66
481
  * Unsubscribe from changes
67
482
  */
@@ -1,22 +1,4 @@
1
- import type {GenericCallback} from '@oscarpalmer/atoms/models';
2
- import type {ReactiveState, Unsubscribe} from './models';
3
-
4
- export class Subscription {
5
- callback: GenericCallback;
6
- state: ReactiveState<unknown, never>;
7
-
8
- constructor(state: ReactiveState<unknown, never>, callback: GenericCallback) {
9
- this.state = state;
10
- this.callback = callback;
11
-
12
- callback(state.value);
13
- }
14
-
15
- destroy(): void {
16
- this.callback = noop;
17
- this.state = undefined as never;
18
- }
19
- }
1
+ import type {ReactiveState, Subscription, Unsubscribe} from './models';
20
2
 
21
3
  export function noop(): void {}
22
4
 
@@ -28,13 +10,31 @@ export function subscribe<Value>(
28
10
  return noop;
29
11
  }
30
12
 
31
- state.subscriptions.set(callback, new Subscription(state, callback));
13
+ state.subscriptions.set(callback, subscription(state, callback));
32
14
 
33
15
  return () => {
34
16
  unsubscribe(state, callback);
35
17
  };
36
18
  }
37
19
 
20
+ function subscription<Value>(
21
+ state: ReactiveState<Value, never>,
22
+ callback: (value: Value) => void,
23
+ ): Subscription {
24
+ const instance: Subscription = {
25
+ callback,
26
+ state,
27
+ destroy: () => {
28
+ instance.callback = noop;
29
+ instance.state = undefined as never;
30
+ },
31
+ };
32
+
33
+ callback(state.value);
34
+
35
+ return instance;
36
+ }
37
+
38
38
  export function unsubscribe<Value>(
39
39
  state: ReactiveState<Value, never>,
40
40
  callback: (value: Value) => void,