@esportsplus/reactivity 0.0.23 → 0.0.25
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 +7 -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 +9 -0
- package/build/api/macro.js +8 -0
- package/build/api/promise.d.ts +8 -0
- package/build/api/promise.js +38 -0
- package/build/api/reactive.d.ts +11 -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 +24 -18
- 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 +48 -0
- package/src/api/reactive.ts +47 -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 +26 -23
- 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,48 @@
|
|
|
1
|
+
import { computed, read, root, signal, write } from '~/signal';
|
|
2
|
+
import context from '~/context';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
// TODO:
|
|
6
|
+
// - Add status value
|
|
7
|
+
// - Add reject/stop method
|
|
8
|
+
export default (fn: <A, R extends Promise<any>>(...args: A[]) => R, options: Parameters<typeof computed>[1] = {}) => {
|
|
9
|
+
let input: unknown,
|
|
10
|
+
nodes = {
|
|
11
|
+
data: signal(options?.value, options),
|
|
12
|
+
status: signal(undefined, options)
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function host(this: typeof host, ...args: Parameters<typeof fn>) {
|
|
16
|
+
input = args;
|
|
17
|
+
|
|
18
|
+
root(() => {
|
|
19
|
+
fn(...args)
|
|
20
|
+
.then(<T>(value: T) => {
|
|
21
|
+
write(nodes.data, value);
|
|
22
|
+
})
|
|
23
|
+
.catch(() => {
|
|
24
|
+
write(nodes.data, undefined);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
Object.defineProperties(host, {
|
|
30
|
+
data: {
|
|
31
|
+
get() {
|
|
32
|
+
return read(nodes.data);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
input: {
|
|
36
|
+
get() {
|
|
37
|
+
return input;
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
status: {
|
|
41
|
+
get() {
|
|
42
|
+
return read(nodes.status);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return context.nodes(host, nodes);
|
|
48
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { computed, read, signal, write } from '~/signal';
|
|
2
|
+
import { Context, Signal } from '~/types';
|
|
3
|
+
import context from '~/context';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
type Infer<T> =
|
|
7
|
+
T extends (...args: unknown[]) => unknown
|
|
8
|
+
? ReturnType<T>
|
|
9
|
+
: T extends Record<PropertyKey, unknown>
|
|
10
|
+
? { [K in keyof T]: Infer<T[K]> }
|
|
11
|
+
: T;
|
|
12
|
+
|
|
13
|
+
type Never = { [K in keyof Context]?: never };
|
|
14
|
+
|
|
15
|
+
type Options = Parameters<typeof computed>[1] | Parameters<typeof signal>[1];
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
export default <T extends Record<PropertyKey, unknown>>(data: T & Never, options: Options = {}) => {
|
|
19
|
+
let host = {},
|
|
20
|
+
nodes: Record<PropertyKey, Signal<unknown>> = {};
|
|
21
|
+
|
|
22
|
+
for (let key in (data as T)) {
|
|
23
|
+
if (typeof data[key] === 'function') {
|
|
24
|
+
nodes[key] = computed(data[key] as Parameters<typeof computed>[0], options);
|
|
25
|
+
|
|
26
|
+
Object.defineProperty(host, key, {
|
|
27
|
+
get() {
|
|
28
|
+
return read(nodes[key]);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
nodes[key] = signal(data[key], options);
|
|
34
|
+
|
|
35
|
+
Object.defineProperty(host, key, {
|
|
36
|
+
get() {
|
|
37
|
+
return read(nodes[key]);
|
|
38
|
+
},
|
|
39
|
+
set(data) {
|
|
40
|
+
write(nodes[key], data);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return context.nodes(host as Infer<T> & Context, nodes);
|
|
47
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { NODE } from '~/symbols';
|
|
2
|
+
import { Context, Event, Listener, Prettify, 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 Prettify< Required<typeof host> >;
|
|
36
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { NODES } from '~/symbols';
|
|
2
|
+
import { Context, Event, Listener, Prettify, 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 Prettify< 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,34 @@
|
|
|
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
|
-
type
|
|
19
|
-
|
|
20
|
-
? ReturnType<T>
|
|
21
|
-
: T extends Record<string, unknown>
|
|
22
|
-
? { [K in keyof T]: Infer<T[K]> }
|
|
23
|
-
: T;
|
|
27
|
+
type Listener = {
|
|
28
|
+
once?: boolean;
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
<T>(value: T): void;
|
|
31
|
+
};
|
|
26
32
|
|
|
27
33
|
type Options = {
|
|
28
34
|
changed?: Changed;
|
|
@@ -32,18 +38,15 @@ type Root = {
|
|
|
32
38
|
scheduler: Scheduler
|
|
33
39
|
};
|
|
34
40
|
|
|
35
|
-
type
|
|
41
|
+
type Prettify<T> = {
|
|
42
|
+
[K in keyof T]: T[K];
|
|
43
|
+
} & {};
|
|
36
44
|
|
|
37
|
-
type
|
|
45
|
+
type Scheduler = (fn: (...args: unknown[]) => Promise<unknown> | unknown) => unknown;
|
|
38
46
|
|
|
39
47
|
type State = typeof CHECK | typeof CLEAN | typeof DIRTY | typeof DISPOSED;
|
|
40
48
|
|
|
41
49
|
type Type = typeof COMPUTED | typeof EFFECT | typeof SIGNAL;
|
|
42
50
|
|
|
43
|
-
type Wrapper = {
|
|
44
|
-
[NODE]?: Signal,
|
|
45
|
-
[NODES]?: Signal[]
|
|
46
|
-
};
|
|
47
|
-
|
|
48
51
|
|
|
49
|
-
export { Changed, Computed,
|
|
52
|
+
export { Changed, Computed, Context, Effect, Event, Listener, Options, Prettify, 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 };
|