@oscarpalmer/atoms 0.29.0 → 0.31.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.
package/dist/js/index.js CHANGED
@@ -286,18 +286,25 @@ function isPlainObject(value) {
286
286
 
287
287
  // src/js/queue.ts
288
288
  function queue(callback) {
289
- queued.add(callback);
290
- if (queued.size > 0) {
289
+ _atomic_queued.add(callback);
290
+ if (_atomic_queued.size > 0) {
291
291
  queueMicrotask(() => {
292
- const callbacks = Array.from(queued);
293
- queued.clear();
292
+ const callbacks = Array.from(_atomic_queued);
293
+ _atomic_queued.clear();
294
294
  for (const callback2 of callbacks) {
295
295
  callback2();
296
296
  }
297
297
  });
298
298
  }
299
299
  }
300
- var queued = new Set;
300
+ if (globalThis._atomic_queued === undefined) {
301
+ const queued = new Set;
302
+ Object.defineProperty(globalThis, "_atomic_queued", {
303
+ get() {
304
+ return queued;
305
+ }
306
+ });
307
+ }
301
308
 
302
309
  // src/js/value.ts
303
310
  var _cloneNested = function(value) {
@@ -610,132 +617,6 @@ class Manager {
610
617
  }
611
618
  }
612
619
  var cloned = new Map;
613
- // src/js/signal.ts
614
- function computed(callback) {
615
- return new Computed(callback);
616
- }
617
- function effect(callback) {
618
- return new Effect(callback);
619
- }
620
- var getValue = function(reactive) {
621
- const effect2 = effects[effects.length - 1];
622
- if (effect2 !== undefined) {
623
- reactive._effects.add(effect2);
624
- effect2._reactives.add(reactive);
625
- }
626
- return reactive._value;
627
- };
628
- function isComputed(value2) {
629
- return value2 instanceof Computed;
630
- }
631
- function isEffect(value2) {
632
- return value2 instanceof Effect;
633
- }
634
- function isReactive(value2) {
635
- return value2 instanceof Computed || value2 instanceof Signal;
636
- }
637
- function isSignal(value2) {
638
- return value2 instanceof Signal;
639
- }
640
- var setValue = function(reactive, value2, run) {
641
- if (!run && Object.is(value2, reactive._value)) {
642
- return;
643
- }
644
- reactive._value = value2;
645
- if (reactive._active) {
646
- for (const effect2 of reactive._effects) {
647
- queue(effect2._callback);
648
- }
649
- }
650
- };
651
- function signal(value2) {
652
- return new Signal(value2);
653
- }
654
-
655
- class Reactive {
656
- _active = true;
657
- _effects = new Set;
658
- peek() {
659
- return this._value;
660
- }
661
- toJSON() {
662
- return this.value;
663
- }
664
- toString() {
665
- return String(this.value);
666
- }
667
- }
668
-
669
- class Computed extends Reactive {
670
- _effect;
671
- get value() {
672
- return getValue(this);
673
- }
674
- constructor(callback) {
675
- super();
676
- this._effect = effect(() => setValue(this, callback(), false));
677
- }
678
- run() {
679
- this._effect.run();
680
- }
681
- stop() {
682
- this._effect.stop();
683
- }
684
- }
685
-
686
- class Effect {
687
- _callback;
688
- _active = false;
689
- _reactives = new Set;
690
- constructor(_callback) {
691
- this._callback = _callback;
692
- this.run();
693
- }
694
- run() {
695
- if (this._active) {
696
- return;
697
- }
698
- this._active = true;
699
- const index = effects.push(this) - 1;
700
- this._callback();
701
- effects.splice(index, 1);
702
- }
703
- stop() {
704
- if (!this._active) {
705
- return;
706
- }
707
- this._active = false;
708
- for (const value2 of this._reactives) {
709
- value2._effects.delete(this);
710
- }
711
- this._reactives.clear();
712
- }
713
- }
714
-
715
- class Signal extends Reactive {
716
- _value;
717
- get value() {
718
- return getValue(this);
719
- }
720
- set value(value2) {
721
- setValue(this, value2, false);
722
- }
723
- constructor(_value) {
724
- super();
725
- this._value = _value;
726
- }
727
- run() {
728
- if (this._active) {
729
- return;
730
- }
731
- this._active = true;
732
- setValue(this, this._value, true);
733
- }
734
- stop() {
735
- this._active = false;
736
- }
737
- }
738
- var effects = [];
739
620
  // src/js/timer.ts
740
621
  function repeat(callback, options) {
741
622
  const count = typeof options?.count === "number" ? options.count : Number.POSITIVE_INFINITY;
@@ -763,8 +644,11 @@ var work = function(type, timer, state, options) {
763
644
  }
764
645
  state.active = true;
765
646
  const isRepeated = count > 0;
766
- const milliseconds = 16.666666666666668;
767
647
  let index = 0;
648
+ let total = count * interval;
649
+ if (total < milliseconds) {
650
+ total = milliseconds;
651
+ }
768
652
  let start;
769
653
  function step(timestamp) {
770
654
  if (!state.active) {
@@ -772,14 +656,13 @@ var work = function(type, timer, state, options) {
772
656
  }
773
657
  start ??= timestamp;
774
658
  const elapsed = timestamp - start;
775
- const maximum = elapsed + milliseconds;
776
- const minimum = elapsed - milliseconds;
777
- if (minimum < interval && interval < maximum) {
659
+ const finished = elapsed >= total;
660
+ if (finished || elapsed - 2 < interval && interval < elapsed + 2) {
778
661
  if (state.active) {
779
662
  callback(isRepeated ? index : undefined);
780
663
  }
781
664
  index += 1;
782
- if (index < count) {
665
+ if (!finished && index < count) {
783
666
  start = undefined;
784
667
  } else {
785
668
  state.active = false;
@@ -793,6 +676,7 @@ var work = function(type, timer, state, options) {
793
676
  state.frame = requestAnimationFrame(step);
794
677
  return timer;
795
678
  };
679
+ var milliseconds = 0;
796
680
 
797
681
  class Timer {
798
682
  get active() {
@@ -819,23 +703,30 @@ class Timer {
819
703
  return work("stop", this, this.state, this.options);
820
704
  }
821
705
  }
706
+ (() => {
707
+ let start;
708
+ function fn(time) {
709
+ if (start === undefined) {
710
+ start = time;
711
+ requestAnimationFrame(fn);
712
+ } else {
713
+ milliseconds = time - start;
714
+ }
715
+ }
716
+ requestAnimationFrame(fn);
717
+ })();
822
718
  export {
823
719
  wait,
824
720
  unsubscribe,
825
721
  unique,
826
722
  subscribe,
827
723
  splice,
828
- signal,
829
724
  set,
830
725
  repeat,
831
726
  queue,
832
727
  push,
833
728
  proxy,
834
729
  merge,
835
- isSignal,
836
- isReactive,
837
- isEffect,
838
- isComputed,
839
730
  insert,
840
731
  indexOf,
841
732
  groupBy,
@@ -851,10 +742,8 @@ export {
851
742
  find,
852
743
  filter,
853
744
  exists,
854
- effect,
855
745
  diff,
856
746
  createUuid,
857
- computed,
858
747
  cloneProxy,
859
748
  clone,
860
749
  clamp,
package/dist/js/index.mjs CHANGED
@@ -5,7 +5,6 @@ export * from "./event";
5
5
  export * from "./number";
6
6
  export * from "./proxy";
7
7
  export * from "./queue";
8
- export * from "./signal";
9
8
  export * from "./string";
10
9
  export * from "./timer";
11
10
  export * from "./value";
package/dist/js/proxy.js CHANGED
@@ -21,18 +21,25 @@ function isPlainObject(value) {
21
21
 
22
22
  // src/js/queue.ts
23
23
  function queue(callback) {
24
- queued.add(callback);
25
- if (queued.size > 0) {
24
+ _atomic_queued.add(callback);
25
+ if (_atomic_queued.size > 0) {
26
26
  queueMicrotask(() => {
27
- const callbacks = Array.from(queued);
28
- queued.clear();
27
+ const callbacks = Array.from(_atomic_queued);
28
+ _atomic_queued.clear();
29
29
  for (const callback2 of callbacks) {
30
30
  callback2();
31
31
  }
32
32
  });
33
33
  }
34
34
  }
35
- var queued = new Set;
35
+ if (globalThis._atomic_queued === undefined) {
36
+ const queued = new Set;
37
+ Object.defineProperty(globalThis, "_atomic_queued", {
38
+ get() {
39
+ return queued;
40
+ }
41
+ });
42
+ }
36
43
 
37
44
  // src/js/value.ts
38
45
  var _cloneNested = function(value) {
package/dist/js/queue.js CHANGED
@@ -1,17 +1,24 @@
1
1
  // src/js/queue.ts
2
2
  function queue(callback) {
3
- queued.add(callback);
4
- if (queued.size > 0) {
3
+ _atomic_queued.add(callback);
4
+ if (_atomic_queued.size > 0) {
5
5
  queueMicrotask(() => {
6
- const callbacks = Array.from(queued);
7
- queued.clear();
6
+ const callbacks = Array.from(_atomic_queued);
7
+ _atomic_queued.clear();
8
8
  for (const callback2 of callbacks) {
9
9
  callback2();
10
10
  }
11
11
  });
12
12
  }
13
13
  }
14
- var queued = new Set;
14
+ if (globalThis._atomic_queued === undefined) {
15
+ const queued = new Set;
16
+ Object.defineProperty(globalThis, "_atomic_queued", {
17
+ get() {
18
+ return queued;
19
+ }
20
+ });
21
+ }
15
22
  export {
16
23
  queue
17
24
  };
package/dist/js/queue.mjs CHANGED
@@ -1,17 +1,24 @@
1
1
  // src/js/queue.ts
2
2
  function queue(callback) {
3
- queued.add(callback);
4
- if (queued.size > 0) {
3
+ _atomic_queued.add(callback);
4
+ if (_atomic_queued.size > 0) {
5
5
  queueMicrotask(() => {
6
- const callbacks = Array.from(queued);
7
- queued.clear();
6
+ const callbacks = Array.from(_atomic_queued);
7
+ _atomic_queued.clear();
8
8
  for (const callback2 of callbacks) {
9
9
  callback2();
10
10
  }
11
11
  });
12
12
  }
13
13
  }
14
- var queued = new Set;
14
+ if (globalThis._atomic_queued === undefined) {
15
+ const queued = new Set;
16
+ Object.defineProperty(globalThis, "_atomic_queued", {
17
+ get() {
18
+ return queued;
19
+ }
20
+ });
21
+ }
15
22
  export {
16
23
  queue
17
24
  };
package/dist/js/signal.js CHANGED
@@ -1,17 +1,24 @@
1
1
  // src/js/queue.ts
2
2
  function queue(callback) {
3
- queued.add(callback);
4
- if (queued.size > 0) {
3
+ _atomic_queued.add(callback);
4
+ if (_atomic_queued.size > 0) {
5
5
  queueMicrotask(() => {
6
- const callbacks = Array.from(queued);
7
- queued.clear();
6
+ const callbacks = Array.from(_atomic_queued);
7
+ _atomic_queued.clear();
8
8
  for (const callback2 of callbacks) {
9
9
  callback2();
10
10
  }
11
11
  });
12
12
  }
13
13
  }
14
- var queued = new Set;
14
+ if (globalThis._atomic_effects === undefined) {
15
+ const queued = new Set;
16
+ Object.defineProperty(globalThis, "_atomic_queued", {
17
+ get() {
18
+ return queued;
19
+ }
20
+ });
21
+ }
15
22
 
16
23
  // src/js/signal.ts
17
24
  function computed(callback) {
@@ -21,7 +28,7 @@ function effect(callback) {
21
28
  return new Effect(callback);
22
29
  }
23
30
  var getValue = function(reactive) {
24
- const effect2 = effects[effects.length - 1];
31
+ const effect2 = _atomic_effects[_atomic_effects.length - 1];
25
32
  if (effect2 !== undefined) {
26
33
  reactive._effects.add(effect2);
27
34
  effect2._reactives.add(reactive);
@@ -29,16 +36,19 @@ var getValue = function(reactive) {
29
36
  return reactive._value;
30
37
  };
31
38
  function isComputed(value) {
32
- return value instanceof Computed;
39
+ return isInstance(/^computed$/i, value);
33
40
  }
34
41
  function isEffect(value) {
35
- return value instanceof Effect;
42
+ return isInstance(/^effect$/i, value);
36
43
  }
44
+ var isInstance = function(expression, value) {
45
+ return expression.test(value?.constructor?.name ?? "") && value.atomic === true;
46
+ };
37
47
  function isReactive(value) {
38
- return value instanceof Computed || value instanceof Signal;
48
+ return isComputed(value) || isSignal(value);
39
49
  }
40
50
  function isSignal(value) {
41
- return value instanceof Signal;
51
+ return isInstance(/^signal$/i, value);
42
52
  }
43
53
  var setValue = function(reactive, value, run) {
44
54
  if (!run && Object.is(value, reactive._value)) {
@@ -54,8 +64,27 @@ var setValue = function(reactive, value, run) {
54
64
  function signal(value) {
55
65
  return new Signal(value);
56
66
  }
67
+ if (globalThis._atomic_effects === undefined) {
68
+ const effects = [];
69
+ Object.defineProperty(globalThis, "_atomic_effects", {
70
+ get() {
71
+ return effects;
72
+ }
73
+ });
74
+ }
57
75
 
58
- class Reactive {
76
+ class Atomic {
77
+ constructor() {
78
+ Object.defineProperty(this, "atomic", {
79
+ value: true
80
+ });
81
+ }
82
+ }
83
+
84
+ class Reactive extends Atomic {
85
+ constructor() {
86
+ super(...arguments);
87
+ }
59
88
  _active = true;
60
89
  _effects = new Set;
61
90
  peek() {
@@ -86,11 +115,12 @@ class Computed extends Reactive {
86
115
  }
87
116
  }
88
117
 
89
- class Effect {
118
+ class Effect extends Atomic {
90
119
  _callback;
91
120
  _active = false;
92
121
  _reactives = new Set;
93
122
  constructor(_callback) {
123
+ super();
94
124
  this._callback = _callback;
95
125
  this.run();
96
126
  }
@@ -99,9 +129,9 @@ class Effect {
99
129
  return;
100
130
  }
101
131
  this._active = true;
102
- const index = effects.push(this) - 1;
132
+ const index = _atomic_effects.push(this) - 1;
103
133
  this._callback();
104
- effects.splice(index, 1);
134
+ _atomic_effects.splice(index, 1);
105
135
  }
106
136
  stop() {
107
137
  if (!this._active) {
@@ -138,7 +168,6 @@ class Signal extends Reactive {
138
168
  this._active = false;
139
169
  }
140
170
  }
141
- var effects = [];
142
171
  export {
143
172
  signal,
144
173
  isSignal,
package/dist/js/timer.js CHANGED
@@ -25,8 +25,11 @@ var work = function(type, timer, state, options) {
25
25
  }
26
26
  state.active = true;
27
27
  const isRepeated = count > 0;
28
- const milliseconds = 16.666666666666668;
29
28
  let index = 0;
29
+ let total = count * interval;
30
+ if (total < milliseconds) {
31
+ total = milliseconds;
32
+ }
30
33
  let start;
31
34
  function step(timestamp) {
32
35
  if (!state.active) {
@@ -34,14 +37,13 @@ var work = function(type, timer, state, options) {
34
37
  }
35
38
  start ??= timestamp;
36
39
  const elapsed = timestamp - start;
37
- const maximum = elapsed + milliseconds;
38
- const minimum = elapsed - milliseconds;
39
- if (minimum < interval && interval < maximum) {
40
+ const finished = elapsed >= total;
41
+ if (finished || elapsed - 2 < interval && interval < elapsed + 2) {
40
42
  if (state.active) {
41
43
  callback(isRepeated ? index : undefined);
42
44
  }
43
45
  index += 1;
44
- if (index < count) {
46
+ if (!finished && index < count) {
45
47
  start = undefined;
46
48
  } else {
47
49
  state.active = false;
@@ -55,6 +57,7 @@ var work = function(type, timer, state, options) {
55
57
  state.frame = requestAnimationFrame(step);
56
58
  return timer;
57
59
  };
60
+ var milliseconds = 0;
58
61
 
59
62
  class Timer {
60
63
  get active() {
@@ -81,6 +84,18 @@ class Timer {
81
84
  return work("stop", this, this.state, this.options);
82
85
  }
83
86
  }
87
+ (() => {
88
+ let start;
89
+ function fn(time) {
90
+ if (start === undefined) {
91
+ start = time;
92
+ requestAnimationFrame(fn);
93
+ } else {
94
+ milliseconds = time - start;
95
+ }
96
+ }
97
+ requestAnimationFrame(fn);
98
+ })();
84
99
  export {
85
100
  wait,
86
101
  repeat,
package/dist/js/timer.mjs CHANGED
@@ -25,8 +25,11 @@ var work = function(type, timer, state, options) {
25
25
  }
26
26
  state.active = true;
27
27
  const isRepeated = count > 0;
28
- const milliseconds = 16.666666666666668;
29
28
  let index = 0;
29
+ let total = count * interval;
30
+ if (total < milliseconds) {
31
+ total = milliseconds;
32
+ }
30
33
  let start;
31
34
  function step(timestamp) {
32
35
  if (!state.active) {
@@ -34,14 +37,13 @@ var work = function(type, timer, state, options) {
34
37
  }
35
38
  start ??= timestamp;
36
39
  const elapsed = timestamp - start;
37
- const maximum = elapsed + milliseconds;
38
- const minimum = elapsed - milliseconds;
39
- if (minimum < interval && interval < maximum) {
40
+ const finished = elapsed >= total;
41
+ if (finished || elapsed - 2 < interval && interval < elapsed + 2) {
40
42
  if (state.active) {
41
43
  callback(isRepeated ? index : undefined);
42
44
  }
43
45
  index += 1;
44
- if (index < count) {
46
+ if (!finished && index < count) {
45
47
  start = undefined;
46
48
  } else {
47
49
  state.active = false;
@@ -55,6 +57,7 @@ var work = function(type, timer, state, options) {
55
57
  state.frame = requestAnimationFrame(step);
56
58
  return timer;
57
59
  };
60
+ var milliseconds = 0;
58
61
 
59
62
  class Timer {
60
63
  get active() {
@@ -81,6 +84,18 @@ class Timer {
81
84
  return work("stop", this, this.state, this.options);
82
85
  }
83
86
  }
87
+ (() => {
88
+ let start;
89
+ function fn(time) {
90
+ if (start === undefined) {
91
+ start = time;
92
+ requestAnimationFrame(fn);
93
+ } else {
94
+ milliseconds = time - start;
95
+ }
96
+ }
97
+ requestAnimationFrame(fn);
98
+ })();
84
99
  export {
85
100
  wait,
86
101
  repeat,
package/package.json CHANGED
@@ -12,6 +12,9 @@
12
12
  "typescript": "^5.4"
13
13
  },
14
14
  "exports": {
15
+ ".": {
16
+ "types": "./types/index.d.ts"
17
+ },
15
18
  "./array": {
16
19
  "bun": "./src/js/array.ts",
17
20
  "import": "./dist/js/array.mjs",
@@ -60,12 +63,6 @@
60
63
  "require": "./dist/js/queue.js",
61
64
  "types": "./types/queue.d.ts"
62
65
  },
63
- "./signal": {
64
- "bun": "./src/js/signal.ts",
65
- "import": "./dist/js/signal.mjs",
66
- "require": "./dist/js/signal.js",
67
- "types": "./types/signal.d.ts"
68
- },
69
66
  "./string": {
70
67
  "bun": "./src/js/string.ts",
71
68
  "import": "./dist/js/string.mjs",
@@ -117,5 +114,5 @@
117
114
  },
118
115
  "type": "module",
119
116
  "types": "./types/index.d.ts",
120
- "version": "0.29.0"
117
+ "version": "0.31.0"
121
118
  }
package/src/js/index.ts CHANGED
@@ -4,7 +4,6 @@ export * from './event';
4
4
  export * from './number';
5
5
  export * from './proxy';
6
6
  export * from './queue';
7
- export * from './signal';
8
7
  export * from './string';
9
8
  export * from './timer';
10
9
  export * from './value';
package/src/js/queue.ts CHANGED
@@ -1,16 +1,28 @@
1
- const queued = new Set<() => void>();
1
+ declare global {
2
+ var _atomic_queued: Set<() => void>;
3
+ }
4
+
5
+ if (globalThis._atomic_queued === undefined) {
6
+ const queued = new Set<() => void>();
7
+
8
+ Object.defineProperty(globalThis, '_atomic_queued', {
9
+ get() {
10
+ return queued;
11
+ },
12
+ });
13
+ }
2
14
 
3
15
  /**
4
16
  * Queues a callback to be executed at the next best time
5
17
  */
6
18
  export function queue(callback: () => void): void {
7
- queued.add(callback);
19
+ _atomic_queued.add(callback);
8
20
 
9
- if (queued.size > 0) {
21
+ if (_atomic_queued.size > 0) {
10
22
  queueMicrotask(() => {
11
- const callbacks = Array.from(queued);
23
+ const callbacks = Array.from(_atomic_queued);
12
24
 
13
- queued.clear();
25
+ _atomic_queued.clear();
14
26
 
15
27
  for (const callback of callbacks) {
16
28
  callback();
package/src/js/timer.ts CHANGED
@@ -39,6 +39,8 @@ type TimerState = {
39
39
 
40
40
  type WorkType = 'restart' | 'start' | 'stop';
41
41
 
42
+ let milliseconds = 0;
43
+
42
44
  /**
43
45
  * A timer that can be started, stopped, and restarted as neeeded
44
46
  */
@@ -154,9 +156,13 @@ function work(
154
156
  state.active = true;
155
157
 
156
158
  const isRepeated = count > 0;
157
- const milliseconds = 1000 / 60;
158
159
 
159
160
  let index = 0;
161
+ let total = count * interval;
162
+
163
+ if (total < milliseconds) {
164
+ total = milliseconds;
165
+ }
160
166
 
161
167
  let start: DOMHighResTimeStamp | undefined;
162
168
 
@@ -168,17 +174,16 @@ function work(
168
174
  start ??= timestamp;
169
175
 
170
176
  const elapsed = timestamp - start;
171
- const maximum = elapsed + milliseconds;
172
- const minimum = elapsed - milliseconds;
177
+ const finished = elapsed >= total;
173
178
 
174
- if (minimum < interval && interval < maximum) {
179
+ if (finished || (elapsed - 2 < interval && interval < elapsed + 2)) {
175
180
  if (state.active) {
176
181
  callback((isRepeated ? index : undefined) as never);
177
182
  }
178
183
 
179
184
  index += 1;
180
185
 
181
- if (index < count) {
186
+ if (!finished && index < count) {
182
187
  start = undefined;
183
188
  } else {
184
189
  state.active = false;
@@ -197,3 +202,22 @@ function work(
197
202
 
198
203
  return timer;
199
204
  }
205
+
206
+ /**
207
+ * Called immediately to calculate an approximate refresh rate in milliseconds
208
+ */
209
+ (() => {
210
+ let start: number;
211
+
212
+ function fn(time: number) {
213
+ if (start === undefined) {
214
+ start = time;
215
+
216
+ requestAnimationFrame(fn);
217
+ } else {
218
+ milliseconds = time - start;
219
+ }
220
+ }
221
+
222
+ requestAnimationFrame(fn);
223
+ })();
package/types/index.d.ts CHANGED
@@ -4,7 +4,6 @@ export * from './event';
4
4
  export * from './number';
5
5
  export * from './proxy';
6
6
  export * from './queue';
7
- export * from './signal';
8
7
  export * from './string';
9
8
  export * from './timer';
10
9
  export * from './value';
package/types/queue.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ declare global {
2
+ var _atomic_queued: Set<() => void>;
3
+ }
1
4
  /**
2
5
  * Queues a callback to be executed at the next best time
3
6
  */
package/src/js/signal.ts DELETED
@@ -1,259 +0,0 @@
1
- import {queue} from './queue';
2
-
3
- type InternalEffect = {
4
- _active: boolean;
5
- _callback: () => void;
6
- _reactives: Set<InternalReactive>;
7
- };
8
-
9
- type InternalReactive = {
10
- _active: boolean;
11
- _effects: Set<InternalEffect>;
12
- _value: unknown;
13
- };
14
-
15
- /**
16
- * The base class for reactive values
17
- */
18
- abstract class Reactive<T = unknown> {
19
- protected _active = true;
20
- protected _effects = new Set<InternalEffect>();
21
- protected declare _value: T;
22
-
23
- /**
24
- * The current value
25
- */
26
- abstract get value(): T;
27
-
28
- /**
29
- * The current value, returned without triggering computations or effects
30
- */
31
- peek(): T {
32
- return this._value;
33
- }
34
-
35
- /**
36
- * Allows reactivity for value, if it was stopped
37
- */
38
- abstract run(): void;
39
-
40
- /**
41
- * Stops reactivity for value, if it's running
42
- */
43
- abstract stop(): void;
44
-
45
- /**
46
- * Returns the JSON representation of the value
47
- */
48
- toJSON(): T {
49
- return this.value;
50
- }
51
-
52
- /**
53
- * Returns the string representation of the value
54
- */
55
- toString(): string {
56
- return String(this.value);
57
- }
58
- }
59
-
60
- /**
61
- * A computed, reactive value
62
- */
63
- class Computed<T> extends Reactive<T> {
64
- private readonly _effect: Effect;
65
-
66
- /**
67
- * @inheritdoc
68
- */
69
- get value(): T {
70
- return getValue(this as never) as T;
71
- }
72
-
73
- constructor(callback: () => T) {
74
- super();
75
-
76
- this._effect = effect(() => setValue(this as never, callback(), false));
77
- }
78
-
79
- /**
80
- * @inheritdoc
81
- */
82
- run(): void {
83
- this._effect.run();
84
- }
85
-
86
- /**
87
- * @inheritdoc
88
- */
89
- stop(): void {
90
- this._effect.stop();
91
- }
92
- }
93
-
94
- /**
95
- * A reactive effect
96
- */
97
- class Effect {
98
- private _active = false;
99
- private readonly _reactives = new Set<InternalReactive>();
100
-
101
- constructor(private readonly _callback: () => void) {
102
- this.run();
103
- }
104
-
105
- /**
106
- * Starts and runs the effect, if it was stopped
107
- */
108
- run(): void {
109
- if (this._active) {
110
- return;
111
- }
112
-
113
- this._active = true;
114
-
115
- const index = effects.push(this as never) - 1;
116
-
117
- this._callback();
118
-
119
- effects.splice(index, 1);
120
- }
121
-
122
- /**
123
- * Stops the effect, if it's running
124
- */
125
- stop(): void {
126
- if (!this._active) {
127
- return;
128
- }
129
-
130
- this._active = false;
131
-
132
- for (const value of this._reactives) {
133
- value._effects.delete(this as never);
134
- }
135
-
136
- this._reactives.clear();
137
- }
138
- }
139
-
140
- /**
141
- * A reactive value
142
- */
143
- class Signal<T> extends Reactive<T> {
144
- /**
145
- * @inheritdoc
146
- */
147
- get value(): T {
148
- return getValue(this as never) as T;
149
- }
150
-
151
- /**
152
- * Sets the value
153
- */
154
- set value(value: T) {
155
- setValue(this as never, value, false);
156
- }
157
-
158
- constructor(protected readonly _value: T) {
159
- super();
160
- }
161
-
162
- /**
163
- * @inheritdoc
164
- */
165
- run(): void {
166
- if (this._active) {
167
- return;
168
- }
169
-
170
- this._active = true;
171
-
172
- setValue(this as never, this._value, true);
173
- }
174
-
175
- /**
176
- * @inheritdoc
177
- */
178
- stop(): void {
179
- this._active = false;
180
- }
181
- }
182
-
183
- const effects: InternalEffect[] = [];
184
-
185
- /**
186
- * Creates a computed, reactive value
187
- */
188
- export function computed<T>(callback: () => T): Computed<T> {
189
- return new Computed(callback);
190
- }
191
-
192
- /**
193
- * Creates a reactive effect
194
- */
195
- export function effect(callback: () => void): Effect {
196
- return new Effect(callback);
197
- }
198
-
199
- function getValue(reactive: InternalReactive): unknown {
200
- const effect = effects[effects.length - 1];
201
-
202
- if (effect !== undefined) {
203
- reactive._effects.add(effect);
204
- effect._reactives.add(reactive);
205
- }
206
-
207
- return reactive._value;
208
- }
209
-
210
- /**
211
- * Is the value a computed, reactive value?
212
- */
213
- export function isComputed(value: unknown): value is Computed<unknown> {
214
- return value instanceof Computed;
215
- }
216
-
217
- /**
218
- * Is the value a reactive effect?
219
- */
220
- export function isEffect(value: unknown): value is Effect {
221
- return value instanceof Effect;
222
- }
223
-
224
- /**
225
- * Is the value a reactive value?
226
- */
227
- export function isReactive(value: unknown): value is Reactive<unknown> {
228
- return value instanceof Computed || value instanceof Signal;
229
- }
230
-
231
- /**
232
- * Is the value a reactive value?
233
- */
234
- export function isSignal(value: unknown): value is Signal<unknown> {
235
- return value instanceof Signal;
236
- }
237
-
238
- function setValue<T>(reactive: InternalReactive, value: T, run: boolean): void {
239
- if (!run && Object.is(value, reactive._value)) {
240
- return;
241
- }
242
-
243
- reactive._value = value;
244
-
245
- if (reactive._active) {
246
- for (const effect of reactive._effects) {
247
- queue(effect._callback);
248
- }
249
- }
250
- }
251
-
252
- /**
253
- * Creates a reactive value
254
- */
255
- export function signal<T>(value: T): Signal<T> {
256
- return new Signal(value);
257
- }
258
-
259
- export type {Computed, Effect, Reactive, Signal};
package/types/signal.d.ts DELETED
@@ -1,130 +0,0 @@
1
- type InternalEffect = {
2
- _active: boolean;
3
- _callback: () => void;
4
- _reactives: Set<InternalReactive>;
5
- };
6
- type InternalReactive = {
7
- _active: boolean;
8
- _effects: Set<InternalEffect>;
9
- _value: unknown;
10
- };
11
- /**
12
- * The base class for reactive values
13
- */
14
- declare abstract class Reactive<T = unknown> {
15
- protected _active: boolean;
16
- protected _effects: Set<InternalEffect>;
17
- protected _value: T;
18
- /**
19
- * The current value
20
- */
21
- abstract get value(): T;
22
- /**
23
- * The current value, returned without triggering computations or effects
24
- */
25
- peek(): T;
26
- /**
27
- * Allows reactivity for value, if it was stopped
28
- */
29
- abstract run(): void;
30
- /**
31
- * Stops reactivity for value, if it's running
32
- */
33
- abstract stop(): void;
34
- /**
35
- * Returns the JSON representation of the value
36
- */
37
- toJSON(): T;
38
- /**
39
- * Returns the string representation of the value
40
- */
41
- toString(): string;
42
- }
43
- /**
44
- * A computed, reactive value
45
- */
46
- declare class Computed<T> extends Reactive<T> {
47
- private readonly _effect;
48
- /**
49
- * @inheritdoc
50
- */
51
- get value(): T;
52
- constructor(callback: () => T);
53
- /**
54
- * @inheritdoc
55
- */
56
- run(): void;
57
- /**
58
- * @inheritdoc
59
- */
60
- stop(): void;
61
- }
62
- /**
63
- * A reactive effect
64
- */
65
- declare class Effect {
66
- private readonly _callback;
67
- private _active;
68
- private readonly _reactives;
69
- constructor(_callback: () => void);
70
- /**
71
- * Starts and runs the effect, if it was stopped
72
- */
73
- run(): void;
74
- /**
75
- * Stops the effect, if it's running
76
- */
77
- stop(): void;
78
- }
79
- /**
80
- * A reactive value
81
- */
82
- declare class Signal<T> extends Reactive<T> {
83
- protected readonly _value: T;
84
- /**
85
- * @inheritdoc
86
- */
87
- get value(): T;
88
- /**
89
- * Sets the value
90
- */
91
- set value(value: T);
92
- constructor(_value: T);
93
- /**
94
- * @inheritdoc
95
- */
96
- run(): void;
97
- /**
98
- * @inheritdoc
99
- */
100
- stop(): void;
101
- }
102
- /**
103
- * Creates a computed, reactive value
104
- */
105
- export declare function computed<T>(callback: () => T): Computed<T>;
106
- /**
107
- * Creates a reactive effect
108
- */
109
- export declare function effect(callback: () => void): Effect;
110
- /**
111
- * Is the value a computed, reactive value?
112
- */
113
- export declare function isComputed(value: unknown): value is Computed<unknown>;
114
- /**
115
- * Is the value a reactive effect?
116
- */
117
- export declare function isEffect(value: unknown): value is Effect;
118
- /**
119
- * Is the value a reactive value?
120
- */
121
- export declare function isReactive(value: unknown): value is Reactive<unknown>;
122
- /**
123
- * Is the value a reactive value?
124
- */
125
- export declare function isSignal(value: unknown): value is Signal<unknown>;
126
- /**
127
- * Creates a reactive value
128
- */
129
- export declare function signal<T>(value: T): Signal<T>;
130
- export type { Computed, Effect, Reactive, Signal };