@fluixi/reactive 1.0.0-alpha.82 → 1.0.0-alpha.84
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/README.md +4 -0
- package/dist/cdn/reactive.cjs +2673 -1
- package/dist/cdn/reactive.global.js +2 -1
- package/dist/cdn/reactive.mjs +2657 -1
- package/dist/cdn/signal.cjs +299 -1
- package/dist/cdn/signal.d.ts +1 -1
- package/dist/cdn/signal.global.js +2 -1
- package/dist/cdn/signal.js +1 -1
- package/dist/cdn/signal.mjs +276 -1
- package/dist/index.cjs +2673 -1
- package/dist/index.mjs +2657 -1
- package/dist/lib/index.cjs +2674 -1
- package/dist/lib/index.js +1 -1
- package/dist/lib/index.mjs +2659 -1
- package/dist/lib/observable/index.cjs +386 -1
- package/dist/lib/observable/index.mjs +364 -1
- package/dist/lib/observable/observable.cjs +384 -1
- package/dist/lib/observable/observable.d.ts +0 -137
- package/dist/lib/observable/observable.d.ts.map +1 -1
- package/dist/lib/observable/observable.js +0 -71
- package/dist/lib/observable/observable.mjs +361 -1
- package/dist/lib/observable/subscription.cjs +180 -1
- package/dist/lib/observable/subscription.d.ts +0 -12
- package/dist/lib/observable/subscription.d.ts.map +1 -1
- package/dist/lib/observable/subscription.js +0 -12
- package/dist/lib/observable/subscription.mjs +157 -1
- package/dist/lib/observable/types.cjs +18 -1
- package/dist/lib/observable/types.d.ts.map +1 -1
- package/dist/lib/predicates.cjs +44 -1
- package/dist/lib/predicates.d.ts +2 -2
- package/dist/lib/predicates.js +2 -2
- package/dist/lib/predicates.mjs +23 -1
- package/dist/lib/signal/api.cjs +571 -1
- package/dist/lib/signal/api.d.ts +211 -1
- package/dist/lib/signal/api.d.ts.map +1 -1
- package/dist/lib/signal/api.js +207 -12
- package/dist/lib/signal/api.mjs +548 -1
- package/dist/lib/signal/cached-resource.cjs +672 -1
- package/dist/lib/signal/cached-resource.d.ts +28 -16
- package/dist/lib/signal/cached-resource.d.ts.map +1 -1
- package/dist/lib/signal/cached-resource.js +35 -29
- package/dist/lib/signal/cached-resource.mjs +650 -1
- package/dist/lib/signal/graph/children.cjs +325 -1
- package/dist/lib/signal/graph/children.js +1 -1
- package/dist/lib/signal/graph/children.mjs +302 -1
- package/dist/lib/signal/graph/compat.cjs +578 -1
- package/dist/lib/signal/graph/compat.d.ts +13 -13
- package/dist/lib/signal/graph/compat.d.ts.map +1 -1
- package/dist/lib/signal/graph/compat.js +51 -32
- package/dist/lib/signal/graph/compat.mjs +556 -1
- package/dist/lib/signal/graph/core.cjs +295 -1
- package/dist/lib/signal/graph/core.d.ts +28 -24
- package/dist/lib/signal/graph/core.d.ts.map +1 -1
- package/dist/lib/signal/graph/core.js +45 -31
- package/dist/lib/signal/graph/core.mjs +273 -1
- package/dist/lib/signal/graph/debounced.cjs +668 -1
- package/dist/lib/signal/graph/debounced.d.ts +5 -5
- package/dist/lib/signal/graph/debounced.d.ts.map +1 -1
- package/dist/lib/signal/graph/debounced.js +5 -5
- package/dist/lib/signal/graph/debounced.mjs +645 -1
- package/dist/lib/signal/graph/derived.cjs +496 -1
- package/dist/lib/signal/graph/derived.d.ts +1 -1
- package/dist/lib/signal/graph/derived.js +1 -1
- package/dist/lib/signal/graph/derived.mjs +473 -1
- package/dist/lib/signal/graph/detect.cjs +66 -1
- package/dist/lib/signal/graph/detect.mjs +45 -1
- package/dist/lib/signal/graph/error-boundary.cjs +301 -1
- package/dist/lib/signal/graph/error-boundary.js +3 -3
- package/dist/lib/signal/graph/error-boundary.mjs +278 -1
- package/dist/lib/signal/graph/index.cjs +305 -1
- package/dist/lib/signal/graph/index.d.ts +7 -6
- package/dist/lib/signal/graph/index.d.ts.map +1 -1
- package/dist/lib/signal/graph/index.js +7 -6
- package/dist/lib/signal/graph/index.mjs +283 -1
- package/dist/lib/signal/graph/observe.cjs +163 -0
- package/dist/lib/signal/graph/observe.d.ts +141 -0
- package/dist/lib/signal/graph/observe.d.ts.map +1 -0
- package/dist/lib/signal/graph/observe.js +149 -0
- package/dist/lib/signal/graph/observe.mjs +140 -0
- package/dist/lib/signal/graph/resource.cjs +620 -1
- package/dist/lib/signal/graph/resource.d.ts +1 -1
- package/dist/lib/signal/graph/resource.js +7 -8
- package/dist/lib/signal/graph/resource.mjs +597 -1
- package/dist/lib/signal/graph/runtime.cjs +501 -1
- package/dist/lib/signal/graph/runtime.d.ts +9 -9
- package/dist/lib/signal/graph/runtime.d.ts.map +1 -1
- package/dist/lib/signal/graph/runtime.js +56 -37
- package/dist/lib/signal/graph/runtime.mjs +478 -1
- package/dist/lib/signal/graph/signal-next.cjs +1208 -1
- package/dist/lib/signal/graph/signal-next.d.ts +5 -5
- package/dist/lib/signal/graph/signal-next.d.ts.map +1 -1
- package/dist/lib/signal/graph/signal-next.js +14 -12
- package/dist/lib/signal/graph/signal-next.mjs +1186 -1
- package/dist/lib/signal/graph/ssr-hooks.cjs +60 -1
- package/dist/lib/signal/graph/ssr-hooks.d.ts +6 -7
- package/dist/lib/signal/graph/ssr-hooks.d.ts.map +1 -1
- package/dist/lib/signal/graph/ssr-hooks.js +6 -7
- package/dist/lib/signal/graph/ssr-hooks.mjs +39 -1
- package/dist/lib/signal/graph/state.cjs +72 -1
- package/dist/lib/signal/graph/state.d.ts +43 -10
- package/dist/lib/signal/graph/state.d.ts.map +1 -1
- package/dist/lib/signal/graph/state.js +83 -21
- package/dist/lib/signal/graph/state.mjs +49 -1
- package/dist/lib/signal/graph/suspense.cjs +301 -1
- package/dist/lib/signal/graph/suspense.js +4 -4
- package/dist/lib/signal/graph/suspense.mjs +278 -1
- package/dist/lib/signal/index-legacy.cjs +2540 -1
- package/dist/lib/signal/index-legacy.d.ts +1 -1
- package/dist/lib/signal/index-legacy.js +1 -1
- package/dist/lib/signal/index-legacy.mjs +2518 -1
- package/dist/lib/signal/index.cjs +1275 -1
- package/dist/lib/signal/index.d.ts +5 -2
- package/dist/lib/signal/index.d.ts.map +1 -1
- package/dist/lib/signal/index.js +8 -3
- package/dist/lib/signal/index.mjs +1253 -1
- package/dist/lib/signal/list.cjs +549 -1
- package/dist/lib/signal/list.d.ts +5 -5
- package/dist/lib/signal/list.js +10 -10
- package/dist/lib/signal/list.mjs +526 -1
- package/dist/lib/signal/resource-api.cjs +626 -1
- package/dist/lib/signal/resource-api.d.ts +5 -5
- package/dist/lib/signal/resource-api.js +5 -5
- package/dist/lib/signal/resource-api.mjs +603 -1
- package/dist/lib/signal/signal.cjs +2023 -1
- package/dist/lib/signal/signal.d.ts +4 -4
- package/dist/lib/signal/signal.d.ts.map +1 -1
- package/dist/lib/signal/signal.js +22 -23
- package/dist/lib/signal/signal.mjs +2000 -1
- package/dist/lib/signal/types.cjs +38 -1
- package/dist/lib/signal/types.d.ts.map +1 -1
- package/dist/lib/signal/types.js +2 -2
- package/dist/lib/signal/types.mjs +17 -1
- package/dist/lib/signal/utilities.cjs +1012 -1
- package/dist/lib/signal/utilities.d.ts +0 -108
- package/dist/lib/signal/utilities.d.ts.map +1 -1
- package/dist/lib/signal/utilities.js +0 -158
- package/dist/lib/signal/utilities.mjs +990 -1
- package/dist/lib/store/api.cjs +612 -1
- package/dist/lib/store/api.d.ts +33 -0
- package/dist/lib/store/api.d.ts.map +1 -1
- package/dist/lib/store/api.js +41 -8
- package/dist/lib/store/api.mjs +596 -1
- package/dist/lib/store/index.cjs +691 -1
- package/dist/lib/store/index.js +1 -1
- package/dist/lib/store/index.mjs +676 -1
- package/dist/lib/store/setter.types.cjs +18 -1
- package/dist/lib/store/setter.types.d.ts +43 -3
- package/dist/lib/store/setter.types.d.ts.map +1 -1
- package/dist/lib/store/store.cjs +658 -1
- package/dist/lib/store/store.d.ts +72 -0
- package/dist/lib/store/store.d.ts.map +1 -1
- package/dist/lib/store/store.js +294 -11
- package/dist/lib/store/store.mjs +644 -1
- package/dist/lib/store/types.cjs +18 -1
- package/dist/lib/store/types.d.ts +1 -1
- package/dist/lib/store/types.d.ts.map +1 -1
- package/dist/lib/store/utils.cjs +43 -1
- package/dist/lib/store/utils.d.ts +1 -1
- package/dist/lib/store/utils.js +1 -1
- package/dist/lib/store/utils.mjs +22 -1
- package/dist/lib/subject.cjs +450 -1
- package/dist/lib/subject.js +3 -91
- package/dist/lib/subject.mjs +427 -1
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/version.generated.cjs +27 -1
- package/dist/version.generated.d.ts +1 -1
- package/dist/version.generated.js +2 -2
- package/dist/version.generated.mjs +7 -1
- package/package.json +5 -4
package/dist/lib/signal/api.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Context, type Owner } from './graph/runtime.js';
|
|
1
2
|
import type { Accessor, Setter, SignalOptions } from './signal.js';
|
|
2
3
|
/** A writable reactive value: call it to read, `.set()` to write. */
|
|
3
4
|
export type SignalHandle<T> = Accessor<T> & {
|
|
@@ -5,9 +6,218 @@ export type SignalHandle<T> = Accessor<T> & {
|
|
|
5
6
|
};
|
|
6
7
|
/** A derived value. Read-only, so it is just the accessor. */
|
|
7
8
|
export type MemoHandle<T> = Accessor<T>;
|
|
9
|
+
/**
|
|
10
|
+
* A writable reactive value.
|
|
11
|
+
*
|
|
12
|
+
* The returned function *is* the accessor, with `set` hung off it, so it passes
|
|
13
|
+
* anywhere an accessor is expected and a read is an ordinary call. Reading inside a
|
|
14
|
+
* tracked scope subscribes that scope; reading outside one does not.
|
|
15
|
+
*
|
|
16
|
+
* `options.equals` decides what counts as a change and defaults to `===`. A write that
|
|
17
|
+
* compares equal notifies nobody, which is how a reflect loop or a feedback cycle
|
|
18
|
+
* terminates.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* const count = signal(0);
|
|
23
|
+
* count(); // 0
|
|
24
|
+
* count.set(1); // write a value
|
|
25
|
+
* count.set((n) => n + 1); // or derive from the previous one
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @example A function value has to be wrapped, because a bare function is read as an
|
|
29
|
+
* updater and called:
|
|
30
|
+
* ```ts
|
|
31
|
+
* const handler = signal<() => void>(() => {});
|
|
32
|
+
* handler.set(() => myCallback); // stores myCallback
|
|
33
|
+
* handler.set(myCallback); // calls myCallback and stores what it returned
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @example Deep values compare by identity unless told otherwise:
|
|
37
|
+
* ```ts
|
|
38
|
+
* const point = signal({ x: 0 }, { equals: (a, b) => a.x === b.x });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
8
41
|
export declare function signal<T>(value: T, options?: SignalOptions<T>): SignalHandle<T>;
|
|
9
42
|
export declare function signal<T = undefined>(): SignalHandle<T | undefined>;
|
|
43
|
+
/**
|
|
44
|
+
* A derived value, computed once per change and cached.
|
|
45
|
+
*
|
|
46
|
+
* Lazy and pull-based: the function does not run until something reads the memo, and
|
|
47
|
+
* then not again until one of its own dependencies changes. That is the difference from
|
|
48
|
+
* {@link computed}, which exists to do work rather than to hold a value.
|
|
49
|
+
*
|
|
50
|
+
* `prev` is the previous result, which makes an accumulator cheap without a second
|
|
51
|
+
* signal to hold it.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* const first = signal('Ada');
|
|
56
|
+
* const last = signal('Lovelace');
|
|
57
|
+
* const full = memo(() => `${first()} ${last()}`);
|
|
58
|
+
* full(); // 'Ada Lovelace', computed now
|
|
59
|
+
* full(); // cached, the function did not run again
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @example Reading the previous value:
|
|
63
|
+
* ```ts
|
|
64
|
+
* const high = memo((prev = 0) => Math.max(prev, reading()), 0);
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
10
67
|
export declare function memo<T>(fn: (prev?: T) => T, value?: T, options?: SignalOptions<T>): MemoHandle<T>;
|
|
11
|
-
/**
|
|
68
|
+
/**
|
|
69
|
+
* Run `fn` now, and again whenever anything it read changes.
|
|
70
|
+
*
|
|
71
|
+
* Dependencies are collected by reading, not declared, so they are whatever the last
|
|
72
|
+
* run actually touched. A branch not taken subscribes to nothing, and a read behind a
|
|
73
|
+
* condition comes and goes with it.
|
|
74
|
+
*
|
|
75
|
+
* Eager. It runs once on creation and again as soon as a dependency is written, in the
|
|
76
|
+
* same task as the write. `batch` is what coalesces a group of writes into one run.
|
|
77
|
+
*
|
|
78
|
+
* Teardown goes through `onCleanup`, which runs before the next execution and once more
|
|
79
|
+
* on disposal. A returned function is **not** teardown: the return value is carried
|
|
80
|
+
* forward as the next call's `prev`, so returning a disposer silently leaks it. The
|
|
81
|
+
* effect is owned by the enclosing {@link root}, so disposing that disposes this.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```ts
|
|
85
|
+
* const query = signal('');
|
|
86
|
+
* effect(() => console.log('searching', query()));
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* @example Teardown between runs, via onCleanup rather than a return:
|
|
90
|
+
* ```ts
|
|
91
|
+
* effect(() => {
|
|
92
|
+
* const id = setInterval(tick, delay());
|
|
93
|
+
* onCleanup(() => clearInterval(id));
|
|
94
|
+
* });
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* @example Writing a signal an effect reads re-triggers it. Break the cycle with
|
|
98
|
+
* `untrack`, or make the write compare equal:
|
|
99
|
+
* ```ts
|
|
100
|
+
* effect(() => save(untrack(() => draft())));
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
103
|
+
* @returns Its disposer, for an effect created outside a root.
|
|
104
|
+
*/
|
|
12
105
|
export declare function effect<T>(fn: (prev?: T) => T | (() => void), value?: T): () => void;
|
|
106
|
+
/**
|
|
107
|
+
* The rest of the `create` prefix, dropped.
|
|
108
|
+
*
|
|
109
|
+
* Each one calls through to the long name with the same arguments. Both spellings stay
|
|
110
|
+
* and mix freely; the graph does not know which was written.
|
|
111
|
+
*
|
|
112
|
+
* `onCleanup`, `getOwner` and `runWithOwner` keep their names. The rule here is losing
|
|
113
|
+
* a `create` that adds nothing, and none of those three has one; `cleanup` would also
|
|
114
|
+
* lose the sense that it registers a callback rather than performing one now.
|
|
115
|
+
*/
|
|
116
|
+
/**
|
|
117
|
+
* An owner scope with an explicit disposer.
|
|
118
|
+
*
|
|
119
|
+
* Every signal, memo, effect and nested scope created while `fn` runs belongs to this
|
|
120
|
+
* one, and `dispose()` takes all of them down together. Without an owner an effect has
|
|
121
|
+
* nothing to tear it down, which is the usual source of a leak.
|
|
122
|
+
*
|
|
123
|
+
* A root created inside another root is attached to it, so disposal is recursive. To
|
|
124
|
+
* detach deliberately, create the root where no owner is current.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```ts
|
|
128
|
+
* const stop = root((dispose) => {
|
|
129
|
+
* effect(() => render(state()));
|
|
130
|
+
* onCleanup(() => detachListeners());
|
|
131
|
+
* return dispose;
|
|
132
|
+
* });
|
|
133
|
+
* stop(); // effect and cleanup both run
|
|
134
|
+
* ```
|
|
135
|
+
*
|
|
136
|
+
* @returns Whatever `fn` returns. Return the disposer when the caller needs it.
|
|
137
|
+
*/
|
|
138
|
+
export declare function root<T>(fn: (dispose: () => void) => T): T;
|
|
139
|
+
/**
|
|
140
|
+
* The effect form `@fluixi/dom` wires its bindings with.
|
|
141
|
+
*
|
|
142
|
+
* Timing is identical to {@link effect} in this runtime: both are eager, and both
|
|
143
|
+
* re-run in the task that wrote their dependency. The render-versus-commit distinction
|
|
144
|
+
* the name suggests is a DOM-layer concern, not a graph one, so do not reach for this
|
|
145
|
+
* expecting different scheduling.
|
|
146
|
+
*
|
|
147
|
+
* What differs is that it is not reported to devtools. Every DOM binding goes through
|
|
148
|
+
* here, and a graph carrying one node per text node is not a graph anyone reads.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* renderEffect(() => el.setAttribute('aria-expanded', String(open())));
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
export declare function renderEffect<T>(fn: (prev?: T) => T | (() => void), value?: T): () => void;
|
|
156
|
+
/**
|
|
157
|
+
* A tracked computation whose result nobody reads.
|
|
158
|
+
*
|
|
159
|
+
* Eager where {@link memo} is lazy. A memo that nothing reads never runs at all, so a
|
|
160
|
+
* memo written for its side effect silently does nothing; this is the form for work
|
|
161
|
+
* that has to happen on every change.
|
|
162
|
+
*
|
|
163
|
+
* Timing matches {@link effect}, and so does ordering: they run in creation order, not
|
|
164
|
+
* in two phases. A `computed` that writes a signal an effect reads has to be created
|
|
165
|
+
* first for the effect to see the settled value.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```ts
|
|
169
|
+
* computed(() => {
|
|
170
|
+
* valid.set(email().includes('@')); // derive into another signal
|
|
171
|
+
* });
|
|
172
|
+
* ```
|
|
173
|
+
*
|
|
174
|
+
* @example `prev` threads the last result through, with no signal to hold it:
|
|
175
|
+
* ```ts
|
|
176
|
+
* computed((runs = 0) => {
|
|
177
|
+
* void query();
|
|
178
|
+
* return runs + 1;
|
|
179
|
+
* }, 0);
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
export declare function computed<T>(fn: (prev?: T) => T, value?: T): void;
|
|
183
|
+
/**
|
|
184
|
+
* A context key: a value passed down an owner tree instead of through props.
|
|
185
|
+
*
|
|
186
|
+
* Lookup walks owners, not the DOM, so a consumer sees whatever provider encloses it
|
|
187
|
+
* reactively. A consumer with no provider above it gets `defaultValue`, which is why
|
|
188
|
+
* supplying one is usually better than handling undefined everywhere.
|
|
189
|
+
*
|
|
190
|
+
* Pass `name`. Unnamed, the key is a bare symbol and a devtools panel has nothing to
|
|
191
|
+
* label the node with.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* const Theme = context<'light' | 'dark'>('light', 'theme');
|
|
196
|
+
*
|
|
197
|
+
* // provider side, as a component
|
|
198
|
+
* Theme.Provider({ value: 'dark', children: () => renderPage() });
|
|
199
|
+
*
|
|
200
|
+
* // consumer side, anywhere below it
|
|
201
|
+
* const theme = useContext(Theme); // 'dark' here, 'light' with no provider
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
export declare function context<T>(defaultValue?: T, name?: string): Context<T>;
|
|
205
|
+
/**
|
|
206
|
+
* A child scope of `parent`, created without entering it.
|
|
207
|
+
*
|
|
208
|
+
* Low level, and rarely the right tool. {@link root} both creates a scope and makes it
|
|
209
|
+
* current, which is what almost all code wants. This hands back an owner to hold and
|
|
210
|
+
* enter later with `runWithOwner`, for a scope whose lifetime does not match the call
|
|
211
|
+
* that created it: a cached subtree, or one list row among many.
|
|
212
|
+
*
|
|
213
|
+
* Disposing `parent` disposes this, since it is attached on creation.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```ts
|
|
217
|
+
* const scope = childOwner(getOwner());
|
|
218
|
+
* // later, and possibly from another task
|
|
219
|
+
* runWithOwner(scope, () => effect(() => paint(row())));
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
export declare function childOwner(parent: Owner | null): Owner;
|
|
13
223
|
//# sourceMappingURL=api.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/lib/signal/api.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/lib/signal/api.ts"],"names":[],"mappings":"AAiCA,OAAO,EAIL,KAAK,OAAO,EACZ,KAAK,KAAK,EACX,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEnE,qEAAqE;AACrE,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;CAAE,CAAC;AAE/D,8DAA8D;AAC9D,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;AACjF,wBAAgB,MAAM,CAAC,CAAC,GAAG,SAAS,KAAK,YAAY,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;AAMrE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAEjG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI,CAEnF;AAED;;;;;;;;;GASG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAEzD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI,CAEzF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,CAEhE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAEtE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,KAAK,GAAG,IAAI,GAAG,KAAK,CAEtD"}
|
package/dist/lib/signal/api.js
CHANGED
|
@@ -1,31 +1,226 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The short reactive API:
|
|
2
|
+
* The short reactive API: the `create` prefix dropped, where dropping it loses nothing.
|
|
3
|
+
*
|
|
4
|
+
* signal memo effect root renderEffect computed context childOwner
|
|
3
5
|
*
|
|
4
6
|
* const count = signal(0);
|
|
5
7
|
* count(); // read
|
|
6
8
|
* count.set(1); // write
|
|
7
9
|
*
|
|
8
|
-
* `signal` is `createSignal` with the setter attached to the accessor
|
|
9
|
-
* back beside it. The function
|
|
10
|
-
* was
|
|
11
|
-
* spelling. `memo` is `createMemo`
|
|
12
|
-
* set, so there is nothing to attach.
|
|
10
|
+
* `signal` is `createSignal` with the setter attached to the accessor rather than handed
|
|
11
|
+
* back beside it. The returned function is the accessor itself, so a read is the call it
|
|
12
|
+
* always was and `count` still passes anywhere an accessor is expected. Only the write
|
|
13
|
+
* changes spelling. `memo` is `createMemo` renamed and no more than that: a derived value
|
|
14
|
+
* has nothing to set, so there is nothing to attach.
|
|
15
|
+
*
|
|
16
|
+
* The rule across the API is to read a thing the way its shape implies. A call for a
|
|
17
|
+
* value, a property for an object (see `store`), and `.set()` to write.
|
|
13
18
|
*
|
|
14
|
-
* The
|
|
15
|
-
*
|
|
19
|
+
* The long names are unchanged and the two spellings are one primitive, so they mix
|
|
20
|
+
* freely. `onCleanup`, `getOwner` and `runWithOwner` are not here: they have no `create`
|
|
21
|
+
* to drop, and `cleanup` would read as performing one rather than registering one.
|
|
16
22
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
23
|
+
* Two of these names promise scheduling they do not deliver, which the per-function
|
|
24
|
+
* docs say outright: `renderEffect` has the same timing as `effect`, and `computed` runs
|
|
25
|
+
* in creation order alongside it rather than in an earlier phase.
|
|
19
26
|
*/
|
|
20
|
-
import { createEffect, createMemo, createSignal } from './graph/compat.js';
|
|
27
|
+
import { createComputed, createEffect, createMemo, createRenderEffect, createSignal, } from './graph/compat.js';
|
|
28
|
+
import { createChildOwner, createContext, createRoot, } from './graph/runtime.js';
|
|
21
29
|
export function signal(value, options) {
|
|
22
30
|
const [read, write] = createSignal(value, options);
|
|
23
31
|
return Object.assign(read, { set: write });
|
|
24
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* A derived value, computed once per change and cached.
|
|
35
|
+
*
|
|
36
|
+
* Lazy and pull-based: the function does not run until something reads the memo, and
|
|
37
|
+
* then not again until one of its own dependencies changes. That is the difference from
|
|
38
|
+
* {@link computed}, which exists to do work rather than to hold a value.
|
|
39
|
+
*
|
|
40
|
+
* `prev` is the previous result, which makes an accumulator cheap without a second
|
|
41
|
+
* signal to hold it.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* const first = signal('Ada');
|
|
46
|
+
* const last = signal('Lovelace');
|
|
47
|
+
* const full = memo(() => `${first()} ${last()}`);
|
|
48
|
+
* full(); // 'Ada Lovelace', computed now
|
|
49
|
+
* full(); // cached, the function did not run again
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* @example Reading the previous value:
|
|
53
|
+
* ```ts
|
|
54
|
+
* const high = memo((prev = 0) => Math.max(prev, reading()), 0);
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
25
57
|
export function memo(fn, value, options) {
|
|
26
58
|
return createMemo(fn, value, options);
|
|
27
59
|
}
|
|
28
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* Run `fn` now, and again whenever anything it read changes.
|
|
62
|
+
*
|
|
63
|
+
* Dependencies are collected by reading, not declared, so they are whatever the last
|
|
64
|
+
* run actually touched. A branch not taken subscribes to nothing, and a read behind a
|
|
65
|
+
* condition comes and goes with it.
|
|
66
|
+
*
|
|
67
|
+
* Eager. It runs once on creation and again as soon as a dependency is written, in the
|
|
68
|
+
* same task as the write. `batch` is what coalesces a group of writes into one run.
|
|
69
|
+
*
|
|
70
|
+
* Teardown goes through `onCleanup`, which runs before the next execution and once more
|
|
71
|
+
* on disposal. A returned function is **not** teardown: the return value is carried
|
|
72
|
+
* forward as the next call's `prev`, so returning a disposer silently leaks it. The
|
|
73
|
+
* effect is owned by the enclosing {@link root}, so disposing that disposes this.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* const query = signal('');
|
|
78
|
+
* effect(() => console.log('searching', query()));
|
|
79
|
+
* ```
|
|
80
|
+
*
|
|
81
|
+
* @example Teardown between runs, via onCleanup rather than a return:
|
|
82
|
+
* ```ts
|
|
83
|
+
* effect(() => {
|
|
84
|
+
* const id = setInterval(tick, delay());
|
|
85
|
+
* onCleanup(() => clearInterval(id));
|
|
86
|
+
* });
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* @example Writing a signal an effect reads re-triggers it. Break the cycle with
|
|
90
|
+
* `untrack`, or make the write compare equal:
|
|
91
|
+
* ```ts
|
|
92
|
+
* effect(() => save(untrack(() => draft())));
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* @returns Its disposer, for an effect created outside a root.
|
|
96
|
+
*/
|
|
29
97
|
export function effect(fn, value) {
|
|
30
98
|
return createEffect(fn, value);
|
|
31
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* The rest of the `create` prefix, dropped.
|
|
102
|
+
*
|
|
103
|
+
* Each one calls through to the long name with the same arguments. Both spellings stay
|
|
104
|
+
* and mix freely; the graph does not know which was written.
|
|
105
|
+
*
|
|
106
|
+
* `onCleanup`, `getOwner` and `runWithOwner` keep their names. The rule here is losing
|
|
107
|
+
* a `create` that adds nothing, and none of those three has one; `cleanup` would also
|
|
108
|
+
* lose the sense that it registers a callback rather than performing one now.
|
|
109
|
+
*/
|
|
110
|
+
/**
|
|
111
|
+
* An owner scope with an explicit disposer.
|
|
112
|
+
*
|
|
113
|
+
* Every signal, memo, effect and nested scope created while `fn` runs belongs to this
|
|
114
|
+
* one, and `dispose()` takes all of them down together. Without an owner an effect has
|
|
115
|
+
* nothing to tear it down, which is the usual source of a leak.
|
|
116
|
+
*
|
|
117
|
+
* A root created inside another root is attached to it, so disposal is recursive. To
|
|
118
|
+
* detach deliberately, create the root where no owner is current.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* const stop = root((dispose) => {
|
|
123
|
+
* effect(() => render(state()));
|
|
124
|
+
* onCleanup(() => detachListeners());
|
|
125
|
+
* return dispose;
|
|
126
|
+
* });
|
|
127
|
+
* stop(); // effect and cleanup both run
|
|
128
|
+
* ```
|
|
129
|
+
*
|
|
130
|
+
* @returns Whatever `fn` returns. Return the disposer when the caller needs it.
|
|
131
|
+
*/
|
|
132
|
+
export function root(fn) {
|
|
133
|
+
return createRoot(fn);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The effect form `@fluixi/dom` wires its bindings with.
|
|
137
|
+
*
|
|
138
|
+
* Timing is identical to {@link effect} in this runtime: both are eager, and both
|
|
139
|
+
* re-run in the task that wrote their dependency. The render-versus-commit distinction
|
|
140
|
+
* the name suggests is a DOM-layer concern, not a graph one, so do not reach for this
|
|
141
|
+
* expecting different scheduling.
|
|
142
|
+
*
|
|
143
|
+
* What differs is that it is not reported to devtools. Every DOM binding goes through
|
|
144
|
+
* here, and a graph carrying one node per text node is not a graph anyone reads.
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```ts
|
|
148
|
+
* renderEffect(() => el.setAttribute('aria-expanded', String(open())));
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
export function renderEffect(fn, value) {
|
|
152
|
+
return createRenderEffect(fn, value);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* A tracked computation whose result nobody reads.
|
|
156
|
+
*
|
|
157
|
+
* Eager where {@link memo} is lazy. A memo that nothing reads never runs at all, so a
|
|
158
|
+
* memo written for its side effect silently does nothing; this is the form for work
|
|
159
|
+
* that has to happen on every change.
|
|
160
|
+
*
|
|
161
|
+
* Timing matches {@link effect}, and so does ordering: they run in creation order, not
|
|
162
|
+
* in two phases. A `computed` that writes a signal an effect reads has to be created
|
|
163
|
+
* first for the effect to see the settled value.
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```ts
|
|
167
|
+
* computed(() => {
|
|
168
|
+
* valid.set(email().includes('@')); // derive into another signal
|
|
169
|
+
* });
|
|
170
|
+
* ```
|
|
171
|
+
*
|
|
172
|
+
* @example `prev` threads the last result through, with no signal to hold it:
|
|
173
|
+
* ```ts
|
|
174
|
+
* computed((runs = 0) => {
|
|
175
|
+
* void query();
|
|
176
|
+
* return runs + 1;
|
|
177
|
+
* }, 0);
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
export function computed(fn, value) {
|
|
181
|
+
createComputed(fn, value);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* A context key: a value passed down an owner tree instead of through props.
|
|
185
|
+
*
|
|
186
|
+
* Lookup walks owners, not the DOM, so a consumer sees whatever provider encloses it
|
|
187
|
+
* reactively. A consumer with no provider above it gets `defaultValue`, which is why
|
|
188
|
+
* supplying one is usually better than handling undefined everywhere.
|
|
189
|
+
*
|
|
190
|
+
* Pass `name`. Unnamed, the key is a bare symbol and a devtools panel has nothing to
|
|
191
|
+
* label the node with.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* const Theme = context<'light' | 'dark'>('light', 'theme');
|
|
196
|
+
*
|
|
197
|
+
* // provider side, as a component
|
|
198
|
+
* Theme.Provider({ value: 'dark', children: () => renderPage() });
|
|
199
|
+
*
|
|
200
|
+
* // consumer side, anywhere below it
|
|
201
|
+
* const theme = useContext(Theme); // 'dark' here, 'light' with no provider
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
export function context(defaultValue, name) {
|
|
205
|
+
return createContext(defaultValue, name);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* A child scope of `parent`, created without entering it.
|
|
209
|
+
*
|
|
210
|
+
* Low level, and rarely the right tool. {@link root} both creates a scope and makes it
|
|
211
|
+
* current, which is what almost all code wants. This hands back an owner to hold and
|
|
212
|
+
* enter later with `runWithOwner`, for a scope whose lifetime does not match the call
|
|
213
|
+
* that created it: a cached subtree, or one list row among many.
|
|
214
|
+
*
|
|
215
|
+
* Disposing `parent` disposes this, since it is attached on creation.
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```ts
|
|
219
|
+
* const scope = childOwner(getOwner());
|
|
220
|
+
* // later, and possibly from another task
|
|
221
|
+
* runWithOwner(scope, () => effect(() => paint(row())));
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
export function childOwner(parent) {
|
|
225
|
+
return createChildOwner(parent);
|
|
226
|
+
}
|