@oscarpalmer/mora 0.19.0 → 0.21.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.
@@ -12,7 +12,7 @@ function getReactiveValueInProxy(reactive, mapped, key, isArray) {
12
12
  });
13
13
  mapped.set(key, item);
14
14
  }
15
- return item.get();
15
+ return item;
16
16
  }
17
17
  function setProxyValue(proxy, value) {
18
18
  batch.startBatch();
@@ -10,7 +10,7 @@ function getReactiveValueInProxy(reactive, mapped, key, isArray) {
10
10
  });
11
11
  mapped.set(key, item);
12
12
  }
13
- return item.get();
13
+ return item;
14
14
  }
15
15
  function setProxyValue(proxy, value) {
16
16
  startBatch();
package/dist/mora.full.js CHANGED
@@ -289,7 +289,7 @@ function getReactiveValueInProxy(reactive, mapped, key, isArray) {
289
289
  });
290
290
  mapped.set(key, item);
291
291
  }
292
- return item.get();
292
+ return item;
293
293
  }
294
294
  function setProxyValue(proxy, value) {
295
295
  startBatch();
@@ -351,7 +351,7 @@ class Signal extends Reactive {
351
351
  }
352
352
  }
353
353
  /**
354
- * Update the value
354
+ * Update the value _(based on the current value)_
355
355
  */
356
356
  update(callback) {
357
357
  this.set(callback(this.state.value));
@@ -400,7 +400,7 @@ class ReactiveArray extends Reactive {
400
400
  }
401
401
  get(first) {
402
402
  if (typeof first === 'number') {
403
- return getReactiveValueInProxy(this, this.#indiced, first, true);
403
+ return getReactiveValueInProxy(this, this.#indiced, first, true).get();
404
404
  }
405
405
  if (first === 'length') {
406
406
  return this.length;
@@ -419,8 +419,14 @@ class ReactiveArray extends Reactive {
419
419
  map(callback) {
420
420
  return computed(() => this.get().map(callback));
421
421
  }
422
- peek(length) {
423
- return length === true ? this.#size.peek() : [...this.state.value];
422
+ peek(value) {
423
+ if (value === true) {
424
+ return this.#size.peek();
425
+ }
426
+ if (typeof value === 'number') {
427
+ return this.state.value.at(value);
428
+ }
429
+ return [...this.state.value];
424
430
  }
425
431
  /**
426
432
  * Remove and return the last item of the array
@@ -435,8 +441,8 @@ class ReactiveArray extends Reactive {
435
441
  return this.state.value.push(...items);
436
442
  }
437
443
  set(first, second) {
438
- if (Array.isArray(first)) {
439
- this.state.value.splice(0, this.state.value.length, ...first);
444
+ if (first == null || Array.isArray(first)) {
445
+ this.state.value.splice(0, this.state.value.length, ...(first ?? []));
440
446
  }
441
447
  else if (first === 'length') {
442
448
  this.length = second;
@@ -457,12 +463,27 @@ class ReactiveArray extends Reactive {
457
463
  splice(from, to, ...items) {
458
464
  return this.state.value.splice(from, to ?? this.state.value.length, ...items);
459
465
  }
466
+ subscribe(first, second) {
467
+ if (typeof first === 'number' && typeof second === 'function') {
468
+ return getReactiveValueInProxy(this, this.#indiced, first, true).subscribe(second);
469
+ }
470
+ return typeof first === 'function' ? subscribe(this.state, first) : noop;
471
+ }
460
472
  /**
461
473
  * Add items to the beginning of the array
462
474
  */
463
475
  unshift(...items) {
464
476
  return this.state.value.unshift(...items);
465
477
  }
478
+ /**
479
+ * Update the value _(based on the current value)_
480
+ */
481
+ update(callback) {
482
+ const updated = callback(this.state.value);
483
+ if (updated == null || Array.isArray(updated)) {
484
+ this.set(updated);
485
+ }
486
+ }
466
487
  }
467
488
  /**
468
489
  * Create a reactive array
@@ -523,7 +544,7 @@ class Store extends Reactive {
523
544
  }
524
545
  get(key) {
525
546
  return isKey(key)
526
- ? getReactiveValueInProxy(this, this.#keyed, key, false)
547
+ ? getReactiveValueInProxy(this, this.#keyed, key, false).get()
527
548
  : getValue(this.state);
528
549
  }
529
550
  peek(key) {
@@ -537,6 +558,21 @@ class Store extends Reactive {
537
558
  setProxyValue(this.state.value, first ?? {});
538
559
  }
539
560
  }
561
+ subscribe(first, second) {
562
+ if (isKey(first) && typeof second === 'function') {
563
+ return getReactiveValueInProxy(this, this.#keyed, first, false).subscribe(second);
564
+ }
565
+ return typeof first === 'function' ? subscribe(this.state, first) : noop;
566
+ }
567
+ /**
568
+ * Update the value _(based on the current value)_
569
+ */
570
+ update(callback) {
571
+ const updated = callback({ ...this.state.value });
572
+ if (updated == null || isPlainObject(updated)) {
573
+ setProxyValue(this.state.value, updated ?? {});
574
+ }
575
+ }
540
576
  }
541
577
  /**
542
578
  * Create a reactive store
@@ -10,6 +10,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
10
10
  const helpers_is = require("../helpers/is.cjs");
11
11
  const helpers_proxy = require("../helpers/proxy.cjs");
12
12
  const helpers_value = require("../helpers/value.cjs");
13
+ const subscription = require("../subscription.cjs");
13
14
  const value_computed = require("./computed.cjs");
14
15
  const value_reactive = require("./reactive.cjs");
15
16
  const value_signal = require("./signal.cjs");
@@ -56,7 +57,7 @@ class ReactiveArray extends value_reactive.Reactive {
56
57
  }
57
58
  get(first) {
58
59
  if (typeof first === "number") {
59
- return helpers_proxy.getReactiveValueInProxy(this, __privateGet(this, _indiced), first, true);
60
+ return helpers_proxy.getReactiveValueInProxy(this, __privateGet(this, _indiced), first, true).get();
60
61
  }
61
62
  if (first === "length") {
62
63
  return this.length;
@@ -75,8 +76,14 @@ class ReactiveArray extends value_reactive.Reactive {
75
76
  map(callback) {
76
77
  return value_computed.computed(() => this.get().map(callback));
77
78
  }
78
- peek(length) {
79
- return length === true ? __privateGet(this, _size).peek() : [...this.state.value];
79
+ peek(value) {
80
+ if (value === true) {
81
+ return __privateGet(this, _size).peek();
82
+ }
83
+ if (typeof value === "number") {
84
+ return this.state.value.at(value);
85
+ }
86
+ return [...this.state.value];
80
87
  }
81
88
  /**
82
89
  * Remove and return the last item of the array
@@ -91,8 +98,8 @@ class ReactiveArray extends value_reactive.Reactive {
91
98
  return this.state.value.push(...items);
92
99
  }
93
100
  set(first, second) {
94
- if (Array.isArray(first)) {
95
- this.state.value.splice(0, this.state.value.length, ...first);
101
+ if (first == null || Array.isArray(first)) {
102
+ this.state.value.splice(0, this.state.value.length, ...first ?? []);
96
103
  } else if (first === "length") {
97
104
  this.length = second;
98
105
  } else if (typeof first === "number") {
@@ -115,12 +122,32 @@ class ReactiveArray extends value_reactive.Reactive {
115
122
  ...items
116
123
  );
117
124
  }
125
+ subscribe(first, second) {
126
+ if (typeof first === "number" && typeof second === "function") {
127
+ return helpers_proxy.getReactiveValueInProxy(
128
+ this,
129
+ __privateGet(this, _indiced),
130
+ first,
131
+ true
132
+ ).subscribe(second);
133
+ }
134
+ return typeof first === "function" ? subscription.subscribe(this.state, first) : subscription.noop;
135
+ }
118
136
  /**
119
137
  * Add items to the beginning of the array
120
138
  */
121
139
  unshift(...items) {
122
140
  return this.state.value.unshift(...items);
123
141
  }
142
+ /**
143
+ * Update the value _(based on the current value)_
144
+ */
145
+ update(callback) {
146
+ const updated = callback(this.state.value);
147
+ if (updated == null || Array.isArray(updated)) {
148
+ this.set(updated);
149
+ }
150
+ }
124
151
  }
125
152
  _indiced = new WeakMap();
126
153
  _size = new WeakMap();
@@ -8,6 +8,7 @@ var _indiced, _size;
8
8
  import { arrayName } from "../helpers/is.js";
9
9
  import { setValueInProxy, getReactiveValueInProxy } from "../helpers/proxy.js";
10
10
  import { getValue, equalArrays, emitValue } from "../helpers/value.js";
11
+ import { subscribe, noop } from "../subscription.js";
11
12
  import { computed } from "./computed.js";
12
13
  import { Reactive } from "./reactive.js";
13
14
  import { signal } from "./signal.js";
@@ -54,7 +55,7 @@ class ReactiveArray extends Reactive {
54
55
  }
55
56
  get(first) {
56
57
  if (typeof first === "number") {
57
- return getReactiveValueInProxy(this, __privateGet(this, _indiced), first, true);
58
+ return getReactiveValueInProxy(this, __privateGet(this, _indiced), first, true).get();
58
59
  }
59
60
  if (first === "length") {
60
61
  return this.length;
@@ -73,8 +74,14 @@ class ReactiveArray extends Reactive {
73
74
  map(callback) {
74
75
  return computed(() => this.get().map(callback));
75
76
  }
76
- peek(length) {
77
- return length === true ? __privateGet(this, _size).peek() : [...this.state.value];
77
+ peek(value) {
78
+ if (value === true) {
79
+ return __privateGet(this, _size).peek();
80
+ }
81
+ if (typeof value === "number") {
82
+ return this.state.value.at(value);
83
+ }
84
+ return [...this.state.value];
78
85
  }
79
86
  /**
80
87
  * Remove and return the last item of the array
@@ -89,8 +96,8 @@ class ReactiveArray extends Reactive {
89
96
  return this.state.value.push(...items);
90
97
  }
91
98
  set(first, second) {
92
- if (Array.isArray(first)) {
93
- this.state.value.splice(0, this.state.value.length, ...first);
99
+ if (first == null || Array.isArray(first)) {
100
+ this.state.value.splice(0, this.state.value.length, ...first ?? []);
94
101
  } else if (first === "length") {
95
102
  this.length = second;
96
103
  } else if (typeof first === "number") {
@@ -113,12 +120,32 @@ class ReactiveArray extends Reactive {
113
120
  ...items
114
121
  );
115
122
  }
123
+ subscribe(first, second) {
124
+ if (typeof first === "number" && typeof second === "function") {
125
+ return getReactiveValueInProxy(
126
+ this,
127
+ __privateGet(this, _indiced),
128
+ first,
129
+ true
130
+ ).subscribe(second);
131
+ }
132
+ return typeof first === "function" ? subscribe(this.state, first) : noop;
133
+ }
116
134
  /**
117
135
  * Add items to the beginning of the array
118
136
  */
119
137
  unshift(...items) {
120
138
  return this.state.value.unshift(...items);
121
139
  }
140
+ /**
141
+ * Update the value _(based on the current value)_
142
+ */
143
+ update(callback) {
144
+ const updated = callback(this.state.value);
145
+ if (updated == null || Array.isArray(updated)) {
146
+ this.set(updated);
147
+ }
148
+ }
122
149
  }
123
150
  _indiced = new WeakMap();
124
151
  _size = new WeakMap();
@@ -23,7 +23,7 @@ class Signal extends value_reactive.Reactive {
23
23
  }
24
24
  }
25
25
  /**
26
- * Update the value
26
+ * Update the value _(based on the current value)_
27
27
  */
28
28
  update(callback) {
29
29
  this.set(callback(this.state.value));
@@ -21,7 +21,7 @@ class Signal extends Reactive {
21
21
  }
22
22
  }
23
23
  /**
24
- * Update the value
24
+ * Update the value _(based on the current value)_
25
25
  */
26
26
  update(callback) {
27
27
  this.set(callback(this.state.value));
@@ -11,6 +11,7 @@ const is = require("../node_modules/@oscarpalmer/atoms/dist/internal/is.cjs");
11
11
  const helpers_is = require("../helpers/is.cjs");
12
12
  const helpers_proxy = require("../helpers/proxy.cjs");
13
13
  const helpers_value = require("../helpers/value.cjs");
14
+ const subscription = require("../subscription.cjs");
14
15
  const value_reactive = require("./reactive.cjs");
15
16
  class Store extends value_reactive.Reactive {
16
17
  constructor(value, options) {
@@ -24,7 +25,7 @@ class Store extends value_reactive.Reactive {
24
25
  __privateAdd(this, _keyed, /* @__PURE__ */ new Map());
25
26
  }
26
27
  get(key) {
27
- return is.isKey(key) ? helpers_proxy.getReactiveValueInProxy(this, __privateGet(this, _keyed), key, false) : helpers_value.getValue(this.state);
28
+ return is.isKey(key) ? helpers_proxy.getReactiveValueInProxy(this, __privateGet(this, _keyed), key, false).get() : helpers_value.getValue(this.state);
28
29
  }
29
30
  peek(key) {
30
31
  return is.isKey(key) ? this.state.value[key] : { ...this.state.value };
@@ -36,6 +37,23 @@ class Store extends value_reactive.Reactive {
36
37
  helpers_proxy.setProxyValue(this.state.value, first ?? {});
37
38
  }
38
39
  }
40
+ subscribe(first, second) {
41
+ if (is.isKey(first) && typeof second === "function") {
42
+ return helpers_proxy.getReactiveValueInProxy(this, __privateGet(this, _keyed), first, false).subscribe(
43
+ second
44
+ );
45
+ }
46
+ return typeof first === "function" ? subscription.subscribe(this.state, first) : subscription.noop;
47
+ }
48
+ /**
49
+ * Update the value _(based on the current value)_
50
+ */
51
+ update(callback) {
52
+ const updated = callback({ ...this.state.value });
53
+ if (updated == null || is.isPlainObject(updated)) {
54
+ helpers_proxy.setProxyValue(this.state.value, updated ?? {});
55
+ }
56
+ }
39
57
  }
40
58
  _keyed = new WeakMap();
41
59
  function store(value, options) {
@@ -9,6 +9,7 @@ import { isPlainObject, isKey } from "../node_modules/@oscarpalmer/atoms/dist/in
9
9
  import { storeName } from "../helpers/is.js";
10
10
  import { setValueInProxy, getReactiveValueInProxy, setProxyValue } from "../helpers/proxy.js";
11
11
  import { getValue } from "../helpers/value.js";
12
+ import { subscribe, noop } from "../subscription.js";
12
13
  import { Reactive } from "./reactive.js";
13
14
  class Store extends Reactive {
14
15
  constructor(value, options) {
@@ -22,7 +23,7 @@ class Store extends Reactive {
22
23
  __privateAdd(this, _keyed, /* @__PURE__ */ new Map());
23
24
  }
24
25
  get(key) {
25
- return isKey(key) ? getReactiveValueInProxy(this, __privateGet(this, _keyed), key, false) : getValue(this.state);
26
+ return isKey(key) ? getReactiveValueInProxy(this, __privateGet(this, _keyed), key, false).get() : getValue(this.state);
26
27
  }
27
28
  peek(key) {
28
29
  return isKey(key) ? this.state.value[key] : { ...this.state.value };
@@ -34,6 +35,23 @@ class Store extends Reactive {
34
35
  setProxyValue(this.state.value, first ?? {});
35
36
  }
36
37
  }
38
+ subscribe(first, second) {
39
+ if (isKey(first) && typeof second === "function") {
40
+ return getReactiveValueInProxy(this, __privateGet(this, _keyed), first, false).subscribe(
41
+ second
42
+ );
43
+ }
44
+ return typeof first === "function" ? subscribe(this.state, first) : noop;
45
+ }
46
+ /**
47
+ * Update the value _(based on the current value)_
48
+ */
49
+ update(callback) {
50
+ const updated = callback({ ...this.state.value });
51
+ if (updated == null || isPlainObject(updated)) {
52
+ setProxyValue(this.state.value, updated ?? {});
53
+ }
54
+ }
37
55
  }
38
56
  _keyed = new WeakMap();
39
57
  function store(value, options) {
package/package.json CHANGED
@@ -4,14 +4,14 @@
4
4
  "url": "https://oscarpalmer.se"
5
5
  },
6
6
  "dependencies": {
7
- "@oscarpalmer/atoms": "^0.100"
7
+ "@oscarpalmer/atoms": "^0.102"
8
8
  },
9
9
  "description": "Signals and stuff…",
10
10
  "devDependencies": {
11
11
  "@biomejs/biome": "^1.9",
12
12
  "@rollup/plugin-node-resolve": "^16",
13
13
  "@rollup/plugin-typescript": "^12.1",
14
- "@types/node": "^22.15",
14
+ "@types/node": "^24",
15
15
  "@vitest/coverage-istanbul": "^3.2",
16
16
  "dts-bundle-generator": "^9.5",
17
17
  "glob": "^11",
@@ -54,5 +54,5 @@
54
54
  },
55
55
  "type": "module",
56
56
  "types": "./types/index.d.ts",
57
- "version": "0.19.0"
57
+ "version": "0.21.0"
58
58
  }
package/src/batch.ts CHANGED
@@ -36,6 +36,6 @@ export function stopBatch(): void {
36
36
  flushHandlers();
37
37
  }
38
38
 
39
- export const batchedHandlers = new Set<Effect | Subscription<unknown>>();
39
+ export const batchedHandlers = new Set<Effect | Subscription>();
40
40
 
41
41
  export let batchDepth = 0;
@@ -12,42 +12,42 @@ import type {Store} from '../value/store';
12
12
  import {emitValue} from './value';
13
13
 
14
14
  export function getReactiveValueInProxy<Value>(
15
- array: ReactiveArray<Value>,
16
- mapped: Map<Key, Computed<unknown>>,
17
- index: number,
18
- isArray: true,
19
- ): unknown;
15
+ array: ReactiveArray<Value>,
16
+ mapped: Map<Key, Computed<unknown>>,
17
+ index: number,
18
+ isArray: true,
19
+ ): Computed<unknown>;
20
20
 
21
21
  export function getReactiveValueInProxy<Value extends PlainObject>(
22
- store: Store<Value>,
23
- mapped: Map<Key, Computed<unknown>>,
24
- key: Key,
25
- isArray: false,
26
- ): unknown;
22
+ store: Store<Value>,
23
+ mapped: Map<Key, Computed<unknown>>,
24
+ key: Key,
25
+ isArray: false,
26
+ ): Computed<unknown>;
27
27
 
28
28
  export function getReactiveValueInProxy(
29
- reactive: ReactiveArray<unknown> | Store<PlainObject>,
30
- mapped: Map<Key, Computed<unknown>>,
31
- key: Key,
32
- isArray: boolean,
33
- ): unknown {
34
- let item = mapped.get(key);
35
-
36
- if (item == null) {
37
- item = computed(() => {
38
- const value = reactive.get();
39
-
40
- return isArray
41
- ? (value as unknown[]).at(key as number)
42
- : (value as PlainObject)[key];
43
- }) as Computed<unknown>;
29
+ reactive: ReactiveArray<unknown> | Store<PlainObject>,
30
+ mapped: Map<Key, Computed<unknown>>,
31
+ key: Key,
32
+ isArray: boolean,
33
+ ): Computed<unknown> {
34
+ let item = mapped.get(key);
35
+
36
+ if (item == null) {
37
+ item = computed(() => {
38
+ const value = reactive.get();
39
+
40
+ return isArray
41
+ ? (value as unknown[]).at(key as number)
42
+ : (value as PlainObject)[key];
43
+ }) as Computed<unknown>;
44
+
45
+ mapped.set(key, item);
46
+ }
44
47
 
45
- mapped.set(key, item);
48
+ return item;
46
49
  }
47
50
 
48
- return item.get();
49
- }
50
-
51
51
  export function setProxyValue(
52
52
  proxy: ArrayOrPlainObject,
53
53
  value: ArrayOrPlainObject,
@@ -1,9 +1,9 @@
1
1
  import type {GenericCallback} from '@oscarpalmer/atoms/models';
2
2
  import type {ReactiveState} from './value/reactive';
3
3
 
4
- export class Subscription<Value> {
4
+ export class Subscription {
5
5
  constructor(
6
- public state: ReactiveState<Value, never>,
6
+ public state: ReactiveState<unknown, never>,
7
7
  public callback: GenericCallback,
8
8
  ) {
9
9
  callback(state.value);
@@ -1,6 +1,8 @@
1
+ import type {GenericCallback} from '@oscarpalmer/atoms';
1
2
  import {arrayName} from '../helpers/is';
2
3
  import {getReactiveValueInProxy, setValueInProxy} from '../helpers/proxy';
3
4
  import {emitValue, equalArrays, getValue} from '../helpers/value';
5
+ import {type Unsubscribe, noop, subscribe} from '../subscription';
4
6
  import {type Computed, computed} from './computed';
5
7
  import {Reactive, type ReactiveOptions, type ReactiveState} from './reactive';
6
8
  import {type Signal, signal} from './signal';
@@ -65,13 +67,19 @@ export class ReactiveArray<Item> extends Reactive<Item[], Item> {
65
67
  */
66
68
  get(): Item[];
67
69
 
70
+ /**
71
+ * Get the value at an index
72
+ */
68
73
  get(index: number): Item | undefined;
69
74
 
75
+ /**
76
+ * Get the length of the array
77
+ */
70
78
  get(property: 'length'): number;
71
79
 
72
80
  get(first?: unknown): unknown {
73
81
  if (typeof first === 'number') {
74
- return getReactiveValueInProxy(this, this.#indiced, first, true);
82
+ return getReactiveValueInProxy(this, this.#indiced, first, true).get();
75
83
  }
76
84
 
77
85
  if (first === 'length') {
@@ -104,13 +112,23 @@ export class ReactiveArray<Item> extends Reactive<Item[], Item> {
104
112
  */
105
113
  peek(): Item[];
106
114
 
115
+ peek(index: number): Item | undefined;
116
+
107
117
  /**
108
118
  * Get the length of the array _(without reactivity)_
109
119
  */
110
120
  peek(length: true): number;
111
121
 
112
- peek(length?: unknown): Item[] | number {
113
- return length === true ? this.#size.peek() : [...this.state.value];
122
+ peek(value?: unknown): unknown {
123
+ if (value === true) {
124
+ return this.#size.peek();
125
+ }
126
+
127
+ if (typeof value === 'number') {
128
+ return this.state.value.at(value);
129
+ }
130
+
131
+ return [...this.state.value];
114
132
  }
115
133
 
116
134
  /**
@@ -130,7 +148,7 @@ export class ReactiveArray<Item> extends Reactive<Item[], Item> {
130
148
  /**
131
149
  * Set the value
132
150
  */
133
- set(value: Item[]): void;
151
+ set(value?: Item[]): void;
134
152
 
135
153
  /**
136
154
  * Set the value at an index
@@ -142,9 +160,9 @@ export class ReactiveArray<Item> extends Reactive<Item[], Item> {
142
160
  */
143
161
  set(property: 'length', value: number): void;
144
162
 
145
- set(first: number | 'length' | Item[], second?: number | Item): void {
146
- if (Array.isArray(first)) {
147
- this.state.value.splice(0, this.state.value.length, ...first);
163
+ set(first?: number | 'length' | Item[], second?: number | Item): void {
164
+ if (first == null || Array.isArray(first)) {
165
+ this.state.value.splice(0, this.state.value.length, ...(first ?? []));
148
166
  } else if (first === 'length') {
149
167
  this.length = second as number;
150
168
  } else if (typeof first === 'number') {
@@ -170,12 +188,52 @@ export class ReactiveArray<Item> extends Reactive<Item[], Item> {
170
188
  );
171
189
  }
172
190
 
191
+ /**
192
+ * @inheritdoc
193
+ */
194
+ subscribe(callback: (value: Item[]) => void): Unsubscribe;
195
+
196
+ /**
197
+ * Subscribe to changes at a specific index
198
+ */
199
+ subscribe(
200
+ index: number,
201
+ callback: (value: Item | undefined) => void,
202
+ ): Unsubscribe;
203
+
204
+ subscribe(
205
+ first: number | GenericCallback,
206
+ second?: GenericCallback,
207
+ ): Unsubscribe {
208
+ if (typeof first === 'number' && typeof second === 'function') {
209
+ return getReactiveValueInProxy(
210
+ this,
211
+ this.#indiced,
212
+ first,
213
+ true,
214
+ ).subscribe(second);
215
+ }
216
+
217
+ return typeof first === 'function' ? subscribe(this.state, first) : noop;
218
+ }
219
+
173
220
  /**
174
221
  * Add items to the beginning of the array
175
222
  */
176
223
  unshift(...items: Item[]): number {
177
224
  return this.state.value.unshift(...items);
178
225
  }
226
+
227
+ /**
228
+ * Update the value _(based on the current value)_
229
+ */
230
+ update(callback: (value: Item[]) => Item[]): void {
231
+ const updated = callback(this.state.value);
232
+
233
+ if (updated == null || Array.isArray(updated)) {
234
+ this.set(updated);
235
+ }
236
+ }
179
237
  }
180
238
 
181
239
  /**
@@ -1,3 +1,4 @@
1
+ import type {GenericCallback} from '@oscarpalmer/atoms/models';
1
2
  import type {Effect} from '../effect';
2
3
  import {
3
4
  type Subscription,
@@ -80,6 +81,6 @@ export type ReactiveState<Value, Equal> = {
80
81
  computeds: Set<Computed<unknown>>;
81
82
  effects: Set<Effect>;
82
83
  equal: (first: Equal, second: Equal) => boolean;
83
- subscriptions: Map<(value: Value) => void, Subscription<Value>>;
84
+ subscriptions: Map<GenericCallback, Subscription>;
84
85
  value: Value;
85
86
  };
@@ -26,7 +26,7 @@ export class Signal<Value> extends Reactive<Value> {
26
26
  }
27
27
 
28
28
  /**
29
- * Update the value
29
+ * Update the value _(based on the current value)_
30
30
  */
31
31
  update(callback: (value: Value) => Value): void {
32
32
  this.set(callback(this.state.value));