@esportsplus/reactivity 0.0.23 → 0.0.24
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/build/api/effect.d.ts +2 -0
- package/build/api/effect.js +3 -0
- package/build/api/index.d.ts +4 -0
- package/build/api/index.js +4 -0
- package/build/api/macro.d.ts +4 -0
- package/build/api/macro.js +8 -0
- package/build/api/promise.d.ts +3 -0
- package/build/api/promise.js +38 -0
- package/build/api/reactive.d.ts +16 -0
- package/build/api/reactive.js +27 -0
- package/build/context/index.d.ts +5 -0
- package/build/context/index.js +3 -0
- package/build/context/node.d.ts +7 -0
- package/build/context/node.js +21 -0
- package/build/context/nodes.d.ts +7 -0
- package/build/context/nodes.js +33 -0
- package/build/index.d.ts +2 -2
- package/build/index.js +2 -2
- package/build/signal.d.ts +25 -10
- package/build/signal.js +236 -2
- package/build/symbols.d.ts +2 -2
- package/build/symbols.js +2 -2
- package/build/types.d.ts +22 -16
- package/build/types.js +2 -1
- package/package.json +2 -2
- package/src/api/effect.ts +5 -0
- package/src/api/index.ts +4 -0
- package/src/api/macro.ts +15 -0
- package/src/api/promise.ts +45 -0
- package/src/api/reactive.ts +42 -0
- package/src/context/index.ts +5 -0
- package/src/context/node.ts +36 -0
- package/src/context/nodes.ts +52 -0
- package/src/index.ts +2 -2
- package/src/signal.ts +325 -11
- package/src/symbols.ts +5 -5
- package/src/types.ts +24 -18
- package/tsconfig.json +1 -1
- package/build/core.d.ts +0 -30
- package/build/core.js +0 -218
- package/build/methods/effect.d.ts +0 -2
- package/build/methods/effect.js +0 -4
- package/build/methods/index.d.ts +0 -3
- package/build/methods/index.js +0 -3
- package/build/methods/reactive.d.ts +0 -3
- package/build/methods/reactive.js +0 -52
- package/build/primitives/closure.d.ts +0 -3
- package/build/primitives/closure.js +0 -10
- package/build/primitives/computed.d.ts +0 -3
- package/build/primitives/computed.js +0 -11
- package/build/primitives/dispatch.d.ts +0 -3
- package/build/primitives/dispatch.js +0 -13
- package/build/primitives/dispose.d.ts +0 -3
- package/build/primitives/dispose.js +0 -13
- package/build/primitives/effect.d.ts +0 -7
- package/build/primitives/effect.js +0 -9
- package/build/primitives/index.d.ts +0 -8
- package/build/primitives/index.js +0 -8
- package/build/primitives/reactive.d.ts +0 -3
- package/build/primitives/reactive.js +0 -35
- package/build/primitives/reset.d.ts +0 -3
- package/build/primitives/reset.js +0 -13
- package/build/primitives/signal.d.ts +0 -8
- package/build/primitives/signal.js +0 -14
- package/build/reactive.d.ts +0 -22
- package/build/reactive.js +0 -190
- package/src/core.ts +0 -295
- package/src/primitives/closure.ts +0 -15
- package/src/primitives/computed.ts +0 -16
- package/src/primitives/dispatch.ts +0 -17
- package/src/primitives/dispose.ts +0 -17
- package/src/primitives/effect.ts +0 -13
- package/src/primitives/index.ts +0 -8
- package/src/primitives/reactive.ts +0 -43
- package/src/primitives/reset.ts +0 -17
- package/src/primitives/signal.ts +0 -18
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { computed, read, root, signal, write } from '~/signal';
|
|
2
|
+
import context from '~/context';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export default (fn: <A, R extends Promise<any>>(...args: A[]) => R, options: Parameters<typeof computed>[1] = {}) => {
|
|
6
|
+
let input: unknown,
|
|
7
|
+
nodes = {
|
|
8
|
+
data: signal(options?.value, options),
|
|
9
|
+
status: signal(undefined, options)
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
function host(this: typeof host, ...args: Parameters<typeof fn>) {
|
|
13
|
+
input = args;
|
|
14
|
+
|
|
15
|
+
root(() => {
|
|
16
|
+
fn(...args)
|
|
17
|
+
.then(<T>(value: T) => {
|
|
18
|
+
write(nodes.data, value);
|
|
19
|
+
})
|
|
20
|
+
.catch(() => {
|
|
21
|
+
write(nodes.data, undefined);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
Object.defineProperties(host, {
|
|
27
|
+
data: {
|
|
28
|
+
get() {
|
|
29
|
+
return read(nodes.data);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
input: {
|
|
33
|
+
get() {
|
|
34
|
+
return input;
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
status: {
|
|
38
|
+
get() {
|
|
39
|
+
return read(nodes.status);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return context.nodes(host, nodes);
|
|
45
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { computed, read, signal, write } from '~/signal';
|
|
2
|
+
import { Computed, Context, Infer, Signal } from '~/types';
|
|
3
|
+
import context from '~/context';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
type Data = {
|
|
7
|
+
[key in keyof Context]: never
|
|
8
|
+
} & Record<PropertyKey, Parameters<typeof computed>[0] | Parameters<typeof signal>[0]>;
|
|
9
|
+
|
|
10
|
+
type Options = Parameters<typeof computed>[1] | Parameters<typeof signal>[1];
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export default <T>(data: Data, options: Options = {}) => {
|
|
14
|
+
let host = {},
|
|
15
|
+
nodes: Record<PropertyKey, Signal<any>> = {};
|
|
16
|
+
|
|
17
|
+
for (let key in data) {
|
|
18
|
+
if (typeof data[key] === 'function') {
|
|
19
|
+
nodes[key] = computed(data[key] as Computed<T>['fn'], options);
|
|
20
|
+
|
|
21
|
+
Object.defineProperty(host, key, {
|
|
22
|
+
get() {
|
|
23
|
+
return read(nodes[key]);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
nodes[key] = signal(data[key], options);
|
|
29
|
+
|
|
30
|
+
Object.defineProperty(host, key, {
|
|
31
|
+
get() {
|
|
32
|
+
return read(nodes[key]);
|
|
33
|
+
},
|
|
34
|
+
set(data) {
|
|
35
|
+
write(nodes[key], data);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return context.nodes(host as Infer<typeof data>, nodes);
|
|
42
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { NODE } from '~/symbols';
|
|
2
|
+
import { Context, Event, Listener, Signal } from '~/types';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
type Internals = {
|
|
6
|
+
[NODE]: Signal<any>;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
function dispose(this: Internals) {
|
|
11
|
+
this[NODE].dispose();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function on(this: Internals, event: Event, listener: Listener) {
|
|
15
|
+
this[NODE].on(event,listener);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function once(this: Internals, event: Event, listener: Listener) {
|
|
19
|
+
this[NODE].once(event, listener);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function reset(this: Internals) {
|
|
23
|
+
this[NODE].reset();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
export default <T>(host: T & Partial<Context>, node: Internals[typeof NODE]) => {
|
|
28
|
+
(host as unknown as Internals)[NODE] = node;
|
|
29
|
+
|
|
30
|
+
host.dispose = dispose;
|
|
31
|
+
host.on = on;
|
|
32
|
+
host.once = once;
|
|
33
|
+
host.reset = reset;
|
|
34
|
+
|
|
35
|
+
return host as Required<typeof host>;
|
|
36
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { NODES } from '~/symbols';
|
|
2
|
+
import { Context, Event, Listener, Signal } from '~/types';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
type Internals = {
|
|
6
|
+
[NODES]: Record<PropertyKey, Signal<any>> ;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
function dispose(this: Internals) {
|
|
11
|
+
let nodes = this[NODES];
|
|
12
|
+
|
|
13
|
+
for (let key in nodes) {
|
|
14
|
+
nodes[key].dispose();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function on(this: Internals, event: Event, listener: Listener) {
|
|
19
|
+
let nodes = this[NODES];
|
|
20
|
+
|
|
21
|
+
for (let key in nodes) {
|
|
22
|
+
nodes[key].on(event, listener);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function once(this: Internals, event: Event, listener: Listener) {
|
|
27
|
+
let nodes = this[NODES];
|
|
28
|
+
|
|
29
|
+
for (let key in nodes) {
|
|
30
|
+
nodes[key].once(event, listener);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function reset(this: Internals) {
|
|
35
|
+
let nodes = this[NODES];
|
|
36
|
+
|
|
37
|
+
for (let key in nodes) {
|
|
38
|
+
nodes[key].reset();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
export default <T>(host: T & Partial<Context>, nodes: Internals[typeof NODES]) => {
|
|
44
|
+
(host as unknown as Internals)[NODES] = nodes;
|
|
45
|
+
|
|
46
|
+
host.dispose = dispose;
|
|
47
|
+
host.on = on;
|
|
48
|
+
host.once = once;
|
|
49
|
+
host.reset = reset;
|
|
50
|
+
|
|
51
|
+
return host as Required<typeof host>;
|
|
52
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from './
|
|
2
|
-
export
|
|
1
|
+
export * from './api';
|
|
2
|
+
export * as core from './signal';
|
|
3
3
|
export { DISPOSE, RESET, UPDATE } from './symbols';
|
package/src/signal.ts
CHANGED
|
@@ -1,21 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CHECK, CLEAN, COMPUTED, DIRTY, DISPOSED, DISPOSE, EFFECT, RESET, SIGNAL, UPDATE } from '~/symbols';
|
|
2
|
+
import { Changed, Computed, Context, Effect, Event, Listener, Options, Root, Scheduler, State, Type } from '~/types';
|
|
2
3
|
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
let index = 0,
|
|
6
|
+
observer: Signal<any> | null = null,
|
|
7
|
+
observers: Signal<any>[] | null = null,
|
|
8
|
+
scope: Root | null = null;
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Signal<T> {
|
|
5
12
|
changed: Changed | null = null;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
observers: Signal[] | null = null;
|
|
13
|
+
fn: Computed<T>['fn'] | null = null;
|
|
14
|
+
listeners: Record<symbol, (Listener | null)[]> | null = null;
|
|
15
|
+
observers: Signal<T>[] | null = null;
|
|
10
16
|
root: Root | null = null;
|
|
11
|
-
sources: Signal[] | null = null;
|
|
17
|
+
sources: Signal<T>[] | null = null;
|
|
18
|
+
state: State;
|
|
12
19
|
task: Parameters<Scheduler>[0] | null = null;
|
|
13
20
|
type: Type;
|
|
14
|
-
|
|
15
|
-
value: T;
|
|
21
|
+
updating: boolean | null = null;
|
|
22
|
+
value: Computed<T>['value'] | T;
|
|
16
23
|
|
|
17
24
|
|
|
18
|
-
constructor(data: T, state: Signal['state'], type: Signal['type'], options: Options = {}) {
|
|
25
|
+
constructor(data: T, state: Signal<T>['state'], type: Signal<T>['type'], options: Options = {}) {
|
|
19
26
|
if (options?.changed) {
|
|
20
27
|
this.changed = options.changed;
|
|
21
28
|
}
|
|
@@ -24,7 +31,314 @@ class Signal<T = unknown> {
|
|
|
24
31
|
this.type = type;
|
|
25
32
|
this.value = data;
|
|
26
33
|
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
dispose() {
|
|
37
|
+
if (this.state === DISPOSED) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this.state = DISPOSED;
|
|
42
|
+
|
|
43
|
+
dispatch(DISPOSE, this);
|
|
44
|
+
flush(this);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
on(event: Event, listener: Listener) {
|
|
48
|
+
if (this.updating) {
|
|
49
|
+
listener.once = true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!this.listeners?.[event]) {
|
|
53
|
+
this.listeners ??= {};
|
|
54
|
+
this.listeners[event] = [listener];
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
let listeners = this.listeners[event];
|
|
58
|
+
|
|
59
|
+
if (listeners.indexOf(listener) === -1) {
|
|
60
|
+
let i = listeners.indexOf(null);
|
|
61
|
+
|
|
62
|
+
if (i === -1) {
|
|
63
|
+
listeners.push(listener);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
listeners[i] = listener;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
once(event: Event, listener: Listener) {
|
|
73
|
+
listener.once = true;
|
|
74
|
+
this.on(event, listener);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
reset() {
|
|
78
|
+
dispatch(RESET, this);
|
|
79
|
+
flush(this);
|
|
80
|
+
|
|
81
|
+
if (this.type === COMPUTED) {
|
|
82
|
+
this.state = DIRTY;
|
|
83
|
+
this.value = undefined as T;
|
|
84
|
+
}
|
|
85
|
+
else if (this.type === EFFECT) {
|
|
86
|
+
this.state = DIRTY;
|
|
87
|
+
update(this);
|
|
88
|
+
}
|
|
89
|
+
else if (this.type === SIGNAL) {
|
|
90
|
+
this.state = CLEAN;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
function changed(a: unknown, b: unknown) {
|
|
97
|
+
return a !== b;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function dispatch<T>(event: Event, node: Signal<T>) {
|
|
101
|
+
if (!node.listeners?.[event]) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let listeners = node.listeners[event],
|
|
106
|
+
value = node.value;
|
|
107
|
+
|
|
108
|
+
for (let i = 0, n = listeners.length; i < n; i++) {
|
|
109
|
+
let listener = listeners[i];
|
|
110
|
+
|
|
111
|
+
if (!listener) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
listener(value);
|
|
116
|
+
|
|
117
|
+
if (listener?.once) {
|
|
118
|
+
listeners[i] = null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function flush<T>(node: Signal<T>) {
|
|
124
|
+
if (node.sources) {
|
|
125
|
+
removeSourceObservers(node, 0);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
node.listeners = null;
|
|
129
|
+
node.observers = null;
|
|
130
|
+
node.sources = null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function notify<T>(nodes: Signal<T>[] | null, state: typeof CHECK | typeof DIRTY) {
|
|
134
|
+
if (!nodes) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
for (let i = 0, n = nodes.length; i < n; i++) {
|
|
139
|
+
let node = nodes[i];
|
|
140
|
+
|
|
141
|
+
if (node.state < state) {
|
|
142
|
+
if (node.type === EFFECT && node.state === CLEAN) {
|
|
143
|
+
node.root!.scheduler(node.task!);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
node.state = state;
|
|
147
|
+
notify(node.observers, CHECK);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function removeSourceObservers<T>(node: Signal<T>, start: number) {
|
|
153
|
+
if (!node.sources) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
for (let i = start, n = node.sources.length; i < n; i++) {
|
|
158
|
+
let source = node.sources[i];
|
|
159
|
+
|
|
160
|
+
if (!source?.observers) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
source.observers[source.observers.indexOf(node)] = source.observers[source.observers.length - 1];
|
|
165
|
+
source.observers.pop();
|
|
166
|
+
}
|
|
27
167
|
}
|
|
28
168
|
|
|
169
|
+
function sync<T>(node: Signal<T>) {
|
|
170
|
+
if (node.state === CHECK && node.sources) {
|
|
171
|
+
for (let i = 0, n = node.sources.length; i < n; i++) {
|
|
172
|
+
sync(node.sources[i]);
|
|
173
|
+
|
|
174
|
+
// Stop the loop here so we won't trigger updates on other parents unnecessarily
|
|
175
|
+
// If our computation changes to no longer use some sources, we don't
|
|
176
|
+
// want to update() a source we used last time, but now don't use.
|
|
177
|
+
if ((node.state as State) === DIRTY) {
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (node.state === DIRTY) {
|
|
184
|
+
update(node);
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
node.state = CLEAN;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function update<T>(node: Signal<T>) {
|
|
192
|
+
let i = index,
|
|
193
|
+
o = observer,
|
|
194
|
+
os = observers;
|
|
195
|
+
|
|
196
|
+
index = 0;
|
|
197
|
+
observer = node;
|
|
198
|
+
observers = null as typeof observers;
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
dispatch(UPDATE, node);
|
|
202
|
+
|
|
203
|
+
node.updating = true;
|
|
204
|
+
|
|
205
|
+
let value = node.fn!.call(node as Context, node?.value);
|
|
206
|
+
|
|
207
|
+
node.updating = null;
|
|
208
|
+
|
|
209
|
+
if (observers) {
|
|
210
|
+
removeSourceObservers(node, index);
|
|
211
|
+
|
|
212
|
+
if (node.sources && index > 0) {
|
|
213
|
+
node.sources.length = index + observers.length;
|
|
214
|
+
|
|
215
|
+
for (let i = 0, n = observers.length; i < n; i++) {
|
|
216
|
+
node.sources[index + i] = observers[i];
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
node.sources = observers;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
for (let i = index, n = node.sources.length; i < n; i++) {
|
|
224
|
+
let source = node.sources[i];
|
|
225
|
+
|
|
226
|
+
if (!source.observers) {
|
|
227
|
+
source.observers = [node];
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
source.observers.push(node);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
else if (node.sources && index < node.sources.length) {
|
|
235
|
+
removeSourceObservers(node, index);
|
|
236
|
+
node.sources.length = index;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (node.type === COMPUTED) {
|
|
240
|
+
write(node, value);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
if (node.state === DIRTY) {
|
|
245
|
+
removeSourceObservers(node, 0);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
finally {
|
|
249
|
+
index = i;
|
|
250
|
+
observer = o;
|
|
251
|
+
observers = os;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
node.state = CLEAN;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
const computed = <T>(fn: Computed<T>['fn'], options: Options & { value?: unknown } = {}) => {
|
|
259
|
+
let node = new Signal(options?.value as any, DIRTY, COMPUTED, options);
|
|
260
|
+
|
|
261
|
+
node.fn = fn;
|
|
262
|
+
|
|
263
|
+
return node as Computed<T>;
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const effect = <T>(fn: Effect<T>['fn'], options: Options = {}) => {
|
|
267
|
+
if (!scope) {
|
|
268
|
+
throw new Error('Reactivity: `effects` cannot be created without a reactive root');
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
let node = new Signal(undefined as any, DIRTY, EFFECT, options);
|
|
272
|
+
|
|
273
|
+
node.fn = fn;
|
|
274
|
+
node.root = scope;
|
|
275
|
+
node.task = () => read(node);
|
|
276
|
+
|
|
277
|
+
update(node);
|
|
278
|
+
|
|
279
|
+
return node as Effect<void>;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const read = <T>(node: Signal<T>): typeof node['value'] => {
|
|
283
|
+
if (node.state === DISPOSED) {
|
|
284
|
+
return node.value;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (observer) {
|
|
288
|
+
if (!observers) {
|
|
289
|
+
if (observer?.sources?.[index] == node) {
|
|
290
|
+
index++;
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
observers = [node];
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
observers.push(node);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (node.fn) {
|
|
302
|
+
sync(node);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return node.value;
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const root = <T>(fn: () => T, properties: { scheduler?: Scheduler } = {}) => {
|
|
309
|
+
let o = observer,
|
|
310
|
+
s = scope;
|
|
311
|
+
|
|
312
|
+
properties.scheduler = properties?.scheduler || scope?.scheduler;
|
|
313
|
+
|
|
314
|
+
if (!properties.scheduler) {
|
|
315
|
+
throw new Error('Reactivity: `root` cannot be created without a task scheduler');
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
observer = null;
|
|
319
|
+
scope = properties as Root;
|
|
320
|
+
|
|
321
|
+
let result = fn();
|
|
322
|
+
|
|
323
|
+
observer = o;
|
|
324
|
+
scope = s;
|
|
325
|
+
|
|
326
|
+
return result;
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
const signal = <T>(data: T, options: Options = {}) => {
|
|
330
|
+
return new Signal(data, CLEAN, SIGNAL, options);
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
const write = <T>(node: Signal<T>, value: unknown) => {
|
|
334
|
+
if ((node?.changed || changed)(node.value, value)) {
|
|
335
|
+
node.value = value as T;
|
|
336
|
+
notify(node.observers, DIRTY);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return node.value;
|
|
340
|
+
};
|
|
341
|
+
|
|
29
342
|
|
|
30
|
-
export default Signal;
|
|
343
|
+
export default Signal;
|
|
344
|
+
export { computed, effect, read, root, signal, write };
|
package/src/symbols.ts
CHANGED
|
@@ -14,11 +14,6 @@ const EFFECT = 1;
|
|
|
14
14
|
const SIGNAL = 2;
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
const NODE = Symbol();
|
|
18
|
-
|
|
19
|
-
const NODES = Symbol();
|
|
20
|
-
|
|
21
|
-
|
|
22
17
|
const DISPOSE = Symbol();
|
|
23
18
|
|
|
24
19
|
const RESET = Symbol();
|
|
@@ -26,4 +21,9 @@ const RESET = Symbol();
|
|
|
26
21
|
const UPDATE = Symbol();
|
|
27
22
|
|
|
28
23
|
|
|
24
|
+
const NODE = Symbol();
|
|
25
|
+
|
|
26
|
+
const NODES = Symbol();
|
|
27
|
+
|
|
28
|
+
|
|
29
29
|
export { CHECK, CLEAN, COMPUTED, DIRTY, DISPOSED, DISPOSE, EFFECT, NODE, NODES, RESET, SIGNAL, UPDATE };
|
package/src/types.ts
CHANGED
|
@@ -1,28 +1,41 @@
|
|
|
1
|
-
import { CHECK, CLEAN, COMPUTED, DIRTY, DISPOSED, EFFECT,
|
|
2
|
-
import
|
|
1
|
+
import { CHECK, CLEAN, COMPUTED, DIRTY, DISPOSED, EFFECT, SIGNAL } from './symbols';
|
|
2
|
+
import Signal from './signal';
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
type Changed = (a: unknown, b: unknown) => boolean;
|
|
6
6
|
|
|
7
|
-
type Computed<T
|
|
8
|
-
fn:
|
|
9
|
-
|
|
7
|
+
type Computed<T> = {
|
|
8
|
+
fn: T extends Promise<unknown> ? never : ((this: Context, previous: T) => T);
|
|
9
|
+
value: ReturnType<Computed<T>['fn']>;
|
|
10
|
+
} & Omit<Signal<T>, 'fn' | 'value'>;
|
|
10
11
|
|
|
11
|
-
type
|
|
12
|
+
type Context = {
|
|
13
|
+
dispose(): void;
|
|
14
|
+
on(event: Event, listener: Listener): void;
|
|
15
|
+
once(event: Event, listener: Listener): void;
|
|
16
|
+
reset(): void;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type Effect<T> = {
|
|
20
|
+
fn: (this: Context, previous: T) => T;
|
|
12
21
|
root: NonNullable<Signal<T>['root']>;
|
|
13
22
|
task: NonNullable<Signal<T>['task']>
|
|
14
|
-
} & Computed<T>;
|
|
23
|
+
} & Omit<Computed<T>, 'fn' | 'root' | 'task'>;
|
|
15
24
|
|
|
16
|
-
type
|
|
25
|
+
type Event = symbol;
|
|
17
26
|
|
|
18
27
|
type Infer<T> =
|
|
19
28
|
T extends (...args: any[]) => any
|
|
20
29
|
? ReturnType<T>
|
|
21
|
-
: T extends Record<
|
|
30
|
+
: T extends Record<PropertyKey, unknown>
|
|
22
31
|
? { [K in keyof T]: Infer<T[K]> }
|
|
23
32
|
: T;
|
|
24
33
|
|
|
25
|
-
type Listener =
|
|
34
|
+
type Listener = {
|
|
35
|
+
once?: boolean;
|
|
36
|
+
|
|
37
|
+
<T>(value: T): void;
|
|
38
|
+
};
|
|
26
39
|
|
|
27
40
|
type Options = {
|
|
28
41
|
changed?: Changed;
|
|
@@ -34,16 +47,9 @@ type Root = {
|
|
|
34
47
|
|
|
35
48
|
type Scheduler = (fn: (...args: unknown[]) => Promise<unknown> | unknown) => unknown;
|
|
36
49
|
|
|
37
|
-
type Signal<T = unknown> = S<T>;
|
|
38
|
-
|
|
39
50
|
type State = typeof CHECK | typeof CLEAN | typeof DIRTY | typeof DISPOSED;
|
|
40
51
|
|
|
41
52
|
type Type = typeof COMPUTED | typeof EFFECT | typeof SIGNAL;
|
|
42
53
|
|
|
43
|
-
type Wrapper = {
|
|
44
|
-
[NODE]?: Signal,
|
|
45
|
-
[NODES]?: Signal[]
|
|
46
|
-
};
|
|
47
|
-
|
|
48
54
|
|
|
49
|
-
export { Changed, Computed, Effect,
|
|
55
|
+
export { Changed, Computed, Context, Effect, Event, Infer, Listener, Options, Root, Scheduler, Signal, State, Type };
|
package/tsconfig.json
CHANGED
package/build/core.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Computed, Effect, Fn, Listener, Options, Scheduler } from './types';
|
|
2
|
-
import Signal from './signal';
|
|
3
|
-
declare const computed: <T>(fn: Fn<T>, options?: Options) => Computed<unknown>;
|
|
4
|
-
declare const dispose: (node: Signal) => void;
|
|
5
|
-
declare const effect: <T>(fn: Fn<T>, options?: Options) => Effect<unknown>;
|
|
6
|
-
declare const dispatch: (event: symbol, node: Signal) => void;
|
|
7
|
-
declare const on: (event: symbol, listener: Listener, node: Signal) => void;
|
|
8
|
-
declare const read: (node: Signal) => unknown;
|
|
9
|
-
declare const reset: (node: Signal) => void;
|
|
10
|
-
declare const root: <T>(fn: () => T, properties?: {
|
|
11
|
-
scheduler?: Scheduler;
|
|
12
|
-
}) => T;
|
|
13
|
-
declare const signal: <T>(data: T, options?: Options) => Signal<T>;
|
|
14
|
-
declare const write: (node: Signal, value: unknown) => unknown;
|
|
15
|
-
declare const _default: {
|
|
16
|
-
computed: <T>(fn: Fn<T>, options?: Options) => Computed<unknown>;
|
|
17
|
-
dispatch: (event: symbol, node: Signal<unknown>) => void;
|
|
18
|
-
dispose: (node: Signal<unknown>) => void;
|
|
19
|
-
effect: <T_1>(fn: Fn<T_1>, options?: Options) => Effect<unknown>;
|
|
20
|
-
on: (event: symbol, listener: Listener, node: Signal<unknown>) => void;
|
|
21
|
-
read: (node: Signal<unknown>) => unknown;
|
|
22
|
-
reset: (node: Signal<unknown>) => void;
|
|
23
|
-
root: <T_2>(fn: () => T_2, properties?: {
|
|
24
|
-
scheduler?: Scheduler | undefined;
|
|
25
|
-
}) => T_2;
|
|
26
|
-
signal: <T_3>(data: T_3, options?: Options) => Signal<T_3>;
|
|
27
|
-
write: (node: Signal<unknown>, value: unknown) => unknown;
|
|
28
|
-
};
|
|
29
|
-
export default _default;
|
|
30
|
-
export { computed, dispatch, dispose, effect, on, read, reset, root, signal, write };
|