@solidjs/signals 2.0.0-rc.17 → 2.0.0-rc.19
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/dev-shared.js +426 -241
- package/dist/dev.attribution.js +19 -16
- package/dist/dev.js +768 -409
- package/dist/observe/boundaries.js +88 -67
- package/dist/observe/core/action.js +8 -0
- package/dist/observe/core/async.js +183 -138
- package/dist/observe/core/attribution.js +30 -28
- package/dist/observe/core/constants.js +23 -1
- package/dist/observe/core/core.js +185 -157
- package/dist/observe/core/effect.js +34 -37
- package/dist/observe/core/graph.js +8 -8
- package/dist/observe/core/heap.js +5 -5
- package/dist/observe/core/lanes.js +104 -84
- package/dist/observe/core/owner.js +17 -16
- package/dist/observe/core/scheduler.js +61 -47
- package/dist/observe/core/truth.js +6 -6
- package/dist/observe/core/verdict.js +15 -15
- package/dist/observe/deferred.js +40 -38
- package/dist/observe/from.js +248 -0
- package/dist/observe/index.js +4 -2
- package/dist/observe/map.js +22 -22
- package/dist/observe/reveal.js +5 -5
- package/dist/observe/signals.js +57 -15
- package/dist/observe/store/affects.js +1 -1
- package/dist/observe/store/hooks.js +3 -0
- package/dist/observe/store/optimistic.js +11 -11
- package/dist/observe/store/projection.js +34 -21
- package/dist/observe/store/reconcile.js +138 -122
- package/dist/observe/store/store.js +628 -641
- package/dist/observe/store/target.js +1 -5
- package/dist/observe/store/utils.js +7 -2
- package/dist/prod/boundaries.js +153 -132
- package/dist/prod/core/action.js +8 -0
- package/dist/prod/core/async.js +242 -197
- package/dist/prod/core/constants.js +16 -1
- package/dist/prod/core/core.js +166 -138
- package/dist/prod/core/effect.js +31 -34
- package/dist/prod/core/graph.js +5 -5
- package/dist/prod/core/heap.js +12 -12
- package/dist/prod/core/lanes.js +98 -78
- package/dist/prod/core/owner.js +15 -14
- package/dist/prod/core/scheduler.js +64 -50
- package/dist/prod/core/truth.js +6 -6
- package/dist/prod/core/verdict.js +17 -17
- package/dist/prod/deferred.js +40 -38
- package/dist/prod/from.js +248 -0
- package/dist/prod/index.js +4 -2
- package/dist/prod/map.js +14 -14
- package/dist/prod/reveal.js +8 -8
- package/dist/prod/signals.js +46 -4
- package/dist/prod/store/affects.js +1 -1
- package/dist/prod/store/hooks.js +3 -0
- package/dist/prod/store/optimistic.js +16 -16
- package/dist/prod/store/projection.js +22 -9
- package/dist/prod/store/reconcile.js +138 -122
- package/dist/prod/store/store.js +308 -331
- package/dist/prod/store/target.js +13 -17
- package/dist/prod/store/utils.js +2 -0
- package/dist/types/core/action.d.ts +8 -0
- package/dist/types/core/async.d.ts +12 -2
- package/dist/types/core/constants.d.ts +25 -0
- package/dist/types/core/core.d.ts +33 -4
- package/dist/types/core/dev.d.ts +1 -1
- package/dist/types/core/index.d.ts +1 -1
- package/dist/types/core/lanes.d.ts +5 -1
- package/dist/types/core/scheduler.d.ts +17 -3
- package/dist/types/from.d.ts +47 -0
- package/dist/types/index.d.ts +4 -1
- package/dist/types/signals.d.ts +37 -0
- package/dist/types/store/target.d.ts +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { isThenable, onSupersede } from "./core/async.js";
|
|
2
|
+
|
|
3
|
+
import { CONFIG_CHILDREN_FORBIDDEN } from "./core/constants.js";
|
|
4
|
+
|
|
5
|
+
import { cleanup, getOwner } from "./core/owner.js";
|
|
6
|
+
|
|
7
|
+
// `from` — a push source (callback subscription, Observable, AsyncIterable)
|
|
8
|
+
// as an AsyncIterable a computation can return or `for await` over:
|
|
9
|
+
// const value = createMemo(() => from(source));
|
|
10
|
+
// A subscription keeps the latest value: values that arrive between pulls
|
|
11
|
+
// coalesce. An AsyncIterable streams through unchanged. Either way the source
|
|
12
|
+
// opens when the result is iterated and closes on return(), on supersede (the
|
|
13
|
+
// owning computation re-runs) and on owner disposal, whichever comes first.
|
|
14
|
+
function toSubscribe(e) {
|
|
15
|
+
if (typeof e === "function") return e;
|
|
16
|
+
// TC39 / RxJS interop: `Symbol.observable` (or "@@observable") returns the observable.
|
|
17
|
+
// Read per call, not at module scope, so the module stays side-effect free.
|
|
18
|
+
const n = Symbol.observable;
|
|
19
|
+
const r = (n && e?.[n]) ?? e?.["@@observable"];
|
|
20
|
+
const t = typeof r === "function" ? r.call(e) : e;
|
|
21
|
+
if (t && typeof t.subscribe === "function") return (e, n, r) => t.subscribe({
|
|
22
|
+
next: e,
|
|
23
|
+
error: n,
|
|
24
|
+
complete: r
|
|
25
|
+
});
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const DONE = {
|
|
30
|
+
value: undefined,
|
|
31
|
+
done: true
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Ties an iterator's `finish` to the computation iterating it. Solid reaches
|
|
36
|
+
* an iterator's return() only when the compute returns the iterable directly.
|
|
37
|
+
* Inside an async generator the generator's own return() is queued behind its
|
|
38
|
+
* pending `await`, and owner cleanups wait for the replacing pass to commit,
|
|
39
|
+
* so close on supersede, with owner disposal as the backstop. No owner (an
|
|
40
|
+
* async compute iterating it after its first `await`, or plain iteration):
|
|
41
|
+
* no registration and no diagnostic, so only return() closes it. Scopes that
|
|
42
|
+
* forbid cleanups rely on supersede and return().
|
|
43
|
+
*/ function bindToOwner(e) {
|
|
44
|
+
const n = getOwner();
|
|
45
|
+
if (!n) return;
|
|
46
|
+
onSupersede(e);
|
|
47
|
+
if (!(n.l & CONFIG_CHILDREN_FORBIDDEN)) cleanup(e);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* An AsyncIterable as a stream bound to the iterating computation: every
|
|
52
|
+
* value passes through (no coalescing). `finish` calls the inner return()
|
|
53
|
+
* once and settles pending pulls as done, so a `for await` over it exits as
|
|
54
|
+
* soon as the computation re-runs — even when the inner iterator is an async
|
|
55
|
+
* generator whose own return() the language queues behind its pending
|
|
56
|
+
* `await`.
|
|
57
|
+
*/ function wrapIterable(e) {
|
|
58
|
+
return {
|
|
59
|
+
[Symbol.asyncIterator]() {
|
|
60
|
+
const n = e[Symbol.asyncIterator]();
|
|
61
|
+
let r = false;
|
|
62
|
+
const t = new Set;
|
|
63
|
+
const finish = () => {
|
|
64
|
+
if (r) return DONE;
|
|
65
|
+
r = true;
|
|
66
|
+
for (const e of t) e(DONE);
|
|
67
|
+
t.clear();
|
|
68
|
+
try {
|
|
69
|
+
const e = n.return?.();
|
|
70
|
+
if (isThenable(e)) e.then(undefined, () => {});
|
|
71
|
+
} catch {}
|
|
72
|
+
return DONE;
|
|
73
|
+
};
|
|
74
|
+
bindToOwner(finish);
|
|
75
|
+
return {
|
|
76
|
+
next(...e) {
|
|
77
|
+
if (r) return Promise.resolve(DONE);
|
|
78
|
+
const o = n.next(...e);
|
|
79
|
+
// A bare result (the producer's buffered fast path) passes through.
|
|
80
|
+
if (!isThenable(o)) return o;
|
|
81
|
+
return new Promise((e, n) => {
|
|
82
|
+
t.add(e);
|
|
83
|
+
o.then(n => t.delete(e) && e(n), r => t.delete(e) && n(r));
|
|
84
|
+
});
|
|
85
|
+
},
|
|
86
|
+
return() {
|
|
87
|
+
return Promise.resolve(finish());
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const toCleanup = e => typeof e === "function" ? e : e && typeof e.unsubscribe === "function" ? () => e.unsubscribe() : () => {};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Converts a callback subscription, an Observable or an AsyncIterable into an
|
|
98
|
+
* AsyncIterable for a Solid computation. A subscription keeps only the latest
|
|
99
|
+
* value, and a value the source emits during `subscribe` is served without a
|
|
100
|
+
* loading frame; an AsyncIterable streams every value through.
|
|
101
|
+
*
|
|
102
|
+
* The source closes on supersede — the owning computation re-running — and
|
|
103
|
+
* on owner disposal. Inside an async generator memo that holds for a
|
|
104
|
+
* `for await` that starts before the first `await`; one that starts after it
|
|
105
|
+
* has no owner to bind to, so its source closes only when the loop ends.
|
|
106
|
+
* Prefer returning `from(...)` from its own memo, with awaited inputs read
|
|
107
|
+
* from upstream memos and transforms done in a downstream memo.
|
|
108
|
+
*
|
|
109
|
+
* Iterate the result with `for await` or return it from a computation: its
|
|
110
|
+
* `next()` returns an already-buffered value as a bare result, not a promise.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* const position = createMemo(() =>
|
|
115
|
+
* from<Position>((next, error) => {
|
|
116
|
+
* const id = navigator.geolocation.watchPosition(next, error);
|
|
117
|
+
* return () => navigator.geolocation.clearWatch(id);
|
|
118
|
+
* })
|
|
119
|
+
* );
|
|
120
|
+
* const ticks = createMemo(() => from(interval$(rate())));
|
|
121
|
+
* ```
|
|
122
|
+
*/ function from(e) {
|
|
123
|
+
const n = toSubscribe(e);
|
|
124
|
+
if (!n) {
|
|
125
|
+
if (e && typeof e[Symbol.asyncIterator] === "function") return wrapIterable(e);
|
|
126
|
+
throw new TypeError("from(): expected a subscribe function, an Observable or an AsyncIterable");
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
[Symbol.asyncIterator]() {
|
|
130
|
+
let e;
|
|
131
|
+
let r = false;
|
|
132
|
+
let t = false;
|
|
133
|
+
let o = false;
|
|
134
|
+
let u;
|
|
135
|
+
let f = null;
|
|
136
|
+
let l = null;
|
|
137
|
+
let s = false;
|
|
138
|
+
const close = () => {
|
|
139
|
+
if (s) return;
|
|
140
|
+
s = true;
|
|
141
|
+
t = true;
|
|
142
|
+
const e = l;
|
|
143
|
+
l = null;
|
|
144
|
+
// A throwing unsubscribe must not escape: at supersede this runs
|
|
145
|
+
// inside flush(), ahead of the replacing pass (the returned-iterator
|
|
146
|
+
// path swallows it the same way).
|
|
147
|
+
try {
|
|
148
|
+
e?.();
|
|
149
|
+
} catch {}
|
|
150
|
+
};
|
|
151
|
+
const settle = () => {
|
|
152
|
+
if (!f) return;
|
|
153
|
+
const n = f;
|
|
154
|
+
if (r) {
|
|
155
|
+
f = null;
|
|
156
|
+
r = false;
|
|
157
|
+
n.resolve({
|
|
158
|
+
value: e,
|
|
159
|
+
done: false
|
|
160
|
+
});
|
|
161
|
+
} else if (o) {
|
|
162
|
+
f = null;
|
|
163
|
+
o = false;
|
|
164
|
+
n.reject(u);
|
|
165
|
+
} else if (t) {
|
|
166
|
+
f = null;
|
|
167
|
+
n.resolve({
|
|
168
|
+
value: undefined,
|
|
169
|
+
done: true
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
const i = n(n => {
|
|
174
|
+
if (t) return;
|
|
175
|
+
e = n;
|
|
176
|
+
r = true;
|
|
177
|
+
settle();
|
|
178
|
+
}, e => {
|
|
179
|
+
if (t) return;
|
|
180
|
+
o = true;
|
|
181
|
+
u = e;
|
|
182
|
+
t = true;
|
|
183
|
+
settle();
|
|
184
|
+
close();
|
|
185
|
+
}, () => {
|
|
186
|
+
if (t) return;
|
|
187
|
+
t = true;
|
|
188
|
+
settle();
|
|
189
|
+
close();
|
|
190
|
+
});
|
|
191
|
+
l = toCleanup(i);
|
|
192
|
+
// Completed or errored during subscribe: release what it just returned.
|
|
193
|
+
if (s) {
|
|
194
|
+
const e = l;
|
|
195
|
+
l = null;
|
|
196
|
+
try {
|
|
197
|
+
e();
|
|
198
|
+
} catch {}
|
|
199
|
+
}
|
|
200
|
+
// Idempotent: return(), supersede and disposal may all reach it.
|
|
201
|
+
const finish = () => {
|
|
202
|
+
close();
|
|
203
|
+
r = false;
|
|
204
|
+
if (f) {
|
|
205
|
+
const e = f;
|
|
206
|
+
f = null;
|
|
207
|
+
e.resolve(DONE);
|
|
208
|
+
}
|
|
209
|
+
return DONE;
|
|
210
|
+
};
|
|
211
|
+
bindToOwner(finish);
|
|
212
|
+
return {
|
|
213
|
+
next() {
|
|
214
|
+
// A buffered value is returned as a bare result, not a promise: the
|
|
215
|
+
// iterator consumer lands it in the same pass, so a source that
|
|
216
|
+
// emits during subscribe (BehaviorSubject-style) shows its value
|
|
217
|
+
// with no loading frame. `for await` accepts either form.
|
|
218
|
+
if (r) {
|
|
219
|
+
r = false;
|
|
220
|
+
return {
|
|
221
|
+
value: e,
|
|
222
|
+
done: false
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
if (o) {
|
|
226
|
+
o = false;
|
|
227
|
+
return Promise.reject(u);
|
|
228
|
+
}
|
|
229
|
+
if (t) return Promise.resolve({
|
|
230
|
+
value: undefined,
|
|
231
|
+
done: true
|
|
232
|
+
});
|
|
233
|
+
return new Promise((e, n) => {
|
|
234
|
+
f = {
|
|
235
|
+
resolve: e,
|
|
236
|
+
reject: n
|
|
237
|
+
};
|
|
238
|
+
});
|
|
239
|
+
},
|
|
240
|
+
return() {
|
|
241
|
+
return Promise.resolve(finish());
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export { from };
|
package/dist/prod/index.js
CHANGED
|
@@ -18,7 +18,7 @@ export { $REFRESH, SUPPORTS_PROXY } from "./core/constants.js";
|
|
|
18
18
|
|
|
19
19
|
export { setConsoleFooter } from "./core/dev.js";
|
|
20
20
|
|
|
21
|
-
export { ROOT_ERROR_HOOK, enforceLoadingBoundary, flush, resetErrorHalt } from "./core/scheduler.js";
|
|
21
|
+
export { ROOT_ERROR_HOOK, clock, enforceLoadingBoundary, flush, resetErrorHalt } from "./core/scheduler.js";
|
|
22
22
|
|
|
23
23
|
import "./core/effect.js";
|
|
24
24
|
|
|
@@ -26,7 +26,7 @@ export { configureClientErrors } from "./core/error-hooks.js";
|
|
|
26
26
|
|
|
27
27
|
export { storeName } from "./store/edges.js";
|
|
28
28
|
|
|
29
|
-
export { createEffect, createMemo, createOptimistic, createReaction, createRenderEffect, createSignal, createTrackedEffect, onCleanup, onSettled, refresh, resolve, until } from "./signals.js";
|
|
29
|
+
export { createEffect, createMemo, createOptimistic, createReaction, createRenderEffect, createSignal, createTrackedEffect, onCleanup, onFlush, onSettled, refresh, resolve, until } from "./signals.js";
|
|
30
30
|
|
|
31
31
|
export { mapArray, repeat } from "./map.js";
|
|
32
32
|
|
|
@@ -36,6 +36,8 @@ export { affects } from "./affects.js";
|
|
|
36
36
|
|
|
37
37
|
export { createDeferred } from "./deferred.js";
|
|
38
38
|
|
|
39
|
+
export { from } from "./from.js";
|
|
40
|
+
|
|
39
41
|
export { flatten } from "./flatten.js";
|
|
40
42
|
|
|
41
43
|
export { createErrorBoundary, createLoadingBoundary } from "./boundaries.js";
|
package/dist/prod/map.js
CHANGED
|
@@ -21,7 +21,7 @@ function mapArray(t, e, i) {
|
|
|
21
21
|
const n = e.length > 1;
|
|
22
22
|
const r = e;
|
|
23
23
|
const o = {
|
|
24
|
-
|
|
24
|
+
H: createOwner(),
|
|
25
25
|
it: 0,
|
|
26
26
|
st: t,
|
|
27
27
|
ot: [],
|
|
@@ -32,7 +32,7 @@ function mapArray(t, e, i) {
|
|
|
32
32
|
ct: s || i?.keyed === false ? [] : undefined,
|
|
33
33
|
lt: n && i?.keyed !== false ? [] : undefined,
|
|
34
34
|
ut: i?.keyed === false,
|
|
35
|
-
|
|
35
|
+
L: i?.fallback
|
|
36
36
|
};
|
|
37
37
|
const f = computed(updateKeyedMap.bind(o), undefined);
|
|
38
38
|
f.l &= ~CONFIG_AUTO_DISPOSE;
|
|
@@ -263,11 +263,11 @@ function updateKeyedMap() {
|
|
|
263
263
|
// the flight's reader (pending tracking + post-settle retry) instead of
|
|
264
264
|
// vanishing. Set per pass: the first pass runs inside `computed()`, before
|
|
265
265
|
// the node exists to the caller.
|
|
266
|
-
this.
|
|
266
|
+
this.H.Ye = getOwner();
|
|
267
267
|
const t = this.st() || [], e = t.length;
|
|
268
268
|
t[$TRACK];
|
|
269
269
|
// top level tracking (a store array's container node)
|
|
270
|
-
runWithOwner(this.
|
|
270
|
+
runWithOwner(this.H, () => {
|
|
271
271
|
let i, s,
|
|
272
272
|
// The stage slot a mapper writes its row/index signal into: `j` on the
|
|
273
273
|
// create-all path, `j - start` on the general path, whose stage arrays
|
|
@@ -293,7 +293,7 @@ function updateKeyedMap() {
|
|
|
293
293
|
// fast path for empty arrays
|
|
294
294
|
if (e === 0) {
|
|
295
295
|
if (this.it !== 0) {
|
|
296
|
-
this.
|
|
296
|
+
this.H.dispose(false);
|
|
297
297
|
this.tn = [];
|
|
298
298
|
this.ot = [];
|
|
299
299
|
this.ht = [];
|
|
@@ -301,11 +301,11 @@ function updateKeyedMap() {
|
|
|
301
301
|
this.ct && (this.ct = []);
|
|
302
302
|
this.lt && (this.lt = []);
|
|
303
303
|
}
|
|
304
|
-
if (this.
|
|
304
|
+
if (this.L && !this.ht.length) {
|
|
305
305
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
306
306
|
// dispose it before re-creating
|
|
307
307
|
this.tn[0]?.dispose();
|
|
308
|
-
this.ht[0] = runWithOwner(this.tn[0] = createOwner(), this.
|
|
308
|
+
this.ht[0] = runWithOwner(this.tn[0] = createOwner(), this.L);
|
|
309
309
|
}
|
|
310
310
|
}
|
|
311
311
|
// fast path for new create
|
|
@@ -502,7 +502,7 @@ function updateKeyedMap() {
|
|
|
502
502
|
*/ function repeat(t, e, i) {
|
|
503
503
|
const s = e;
|
|
504
504
|
const n = {
|
|
505
|
-
|
|
505
|
+
H: createOwner(),
|
|
506
506
|
it: 0,
|
|
507
507
|
dt: 0,
|
|
508
508
|
wt: t,
|
|
@@ -510,7 +510,7 @@ function updateKeyedMap() {
|
|
|
510
510
|
tn: [],
|
|
511
511
|
ht: [],
|
|
512
512
|
Ot: i?.from,
|
|
513
|
-
|
|
513
|
+
L: i?.fallback
|
|
514
514
|
};
|
|
515
515
|
const r = computed(updateRepeat.bind(n));
|
|
516
516
|
r.l &= ~CONFIG_AUTO_DISPOSE;
|
|
@@ -526,24 +526,24 @@ function updateKeyedMap() {
|
|
|
526
526
|
// disjoint-window/front-clear/end-clear/shift special cases.
|
|
527
527
|
function updateRepeat() {
|
|
528
528
|
// As in updateKeyedMap: the node is the row callbacks' reader, per pass.
|
|
529
|
-
this.
|
|
529
|
+
this.H.Ye = getOwner();
|
|
530
530
|
const t = this.wt();
|
|
531
531
|
const e = this.Ot?.() || 0;
|
|
532
|
-
runWithOwner(this.
|
|
532
|
+
runWithOwner(this.H, () => {
|
|
533
533
|
if (t === 0) {
|
|
534
534
|
if (this.it !== 0) {
|
|
535
|
-
this.
|
|
535
|
+
this.H.dispose(false);
|
|
536
536
|
this.tn = [];
|
|
537
537
|
this.ht = [];
|
|
538
538
|
this.it = 0;
|
|
539
539
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
540
540
|
this.dt = 0;
|
|
541
541
|
}
|
|
542
|
-
if (this.
|
|
542
|
+
if (this.L && !this.ht.length) {
|
|
543
543
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
544
544
|
// dispose it before re-creating
|
|
545
545
|
this.tn[0]?.dispose();
|
|
546
|
-
this.ht[0] = runWithOwner(this.tn[0] = createOwner(), this.
|
|
546
|
+
this.ht[0] = runWithOwner(this.tn[0] = createOwner(), this.L);
|
|
547
547
|
}
|
|
548
548
|
return;
|
|
549
549
|
}
|
package/dist/prod/reveal.js
CHANGED
|
@@ -76,7 +76,7 @@ class RevealController {
|
|
|
76
76
|
/** A slot that has left this controller's ownership: a boundary that has
|
|
77
77
|
* shown content, a nested group that is ready. Shown is shown — it counts
|
|
78
78
|
* as ready whatever happens to it later (a re-arm gates nobody else). */ gt(t) {
|
|
79
|
-
return (isController(t) ? t._parent : t.
|
|
79
|
+
return (isController(t) ? t._parent : t.v) !== this;
|
|
80
80
|
}
|
|
81
81
|
/** The slots this controller still owns, in registration order — the
|
|
82
82
|
* ones the order's state is forced on. */ Lt(t) {
|
|
@@ -106,7 +106,7 @@ class RevealController {
|
|
|
106
106
|
}
|
|
107
107
|
return t !== "natural";
|
|
108
108
|
}
|
|
109
|
-
|
|
109
|
+
te(t) {
|
|
110
110
|
if (this.At.includes(t)) return;
|
|
111
111
|
this.At.push(t);
|
|
112
112
|
// Gated from the start (collapsed in a collapsed sequential tail); the
|
|
@@ -118,13 +118,13 @@ class RevealController {
|
|
|
118
118
|
t.ee = e;
|
|
119
119
|
t._t();
|
|
120
120
|
} else {
|
|
121
|
-
t.
|
|
121
|
+
t.v = this;
|
|
122
122
|
t.$ = true;
|
|
123
123
|
t.ee = e;
|
|
124
124
|
}
|
|
125
125
|
untrack(() => this._t());
|
|
126
126
|
}
|
|
127
|
-
|
|
127
|
+
oe(t) {
|
|
128
128
|
const e = this.At.indexOf(t);
|
|
129
129
|
if (e >= 0) this.At.splice(e, 1);
|
|
130
130
|
untrack(() => this._t());
|
|
@@ -194,8 +194,8 @@ class RevealController {
|
|
|
194
194
|
});
|
|
195
195
|
if (false) ;
|
|
196
196
|
if (r) {
|
|
197
|
-
r.
|
|
198
|
-
cleanup(() => r.
|
|
197
|
+
r.te(i);
|
|
198
|
+
cleanup(() => r.oe(i));
|
|
199
199
|
}
|
|
200
200
|
return e;
|
|
201
201
|
});
|
|
@@ -204,9 +204,9 @@ class RevealController {
|
|
|
204
204
|
// Installed at module evaluation — present exactly when something imports
|
|
205
205
|
// `createRevealOrder`; a Loading boundary without one pays a null check.
|
|
206
206
|
setRevealHooks({
|
|
207
|
-
oe: (t, e) => t.oe(e),
|
|
208
207
|
te: (t, e) => t.te(e),
|
|
209
|
-
|
|
208
|
+
oe: (t, e) => t.oe(e),
|
|
209
|
+
V: t => t._t()
|
|
210
210
|
});
|
|
211
211
|
|
|
212
212
|
export { createRevealOrder };
|
package/dist/prod/signals.js
CHANGED
|
@@ -6,7 +6,7 @@ import { CONFIG_CHILDREN_FORBIDDEN, EFFECT_USER, $REFRESH, CONFIG_AUTO_DISPOSE,
|
|
|
6
6
|
|
|
7
7
|
import { computed, signal, runWithOwner, setMemo, setSignal, markRefresh, read, untrack } from "./core/core.js";
|
|
8
8
|
|
|
9
|
-
import { globalQueue, flushTransaction, dirtyQueue, GlobalQueue, resolveTx, passTx, staleReader, joinFuture } from "./core/scheduler.js";
|
|
9
|
+
import { schedule, globalQueue, flushTransaction, dirtyQueue, GlobalQueue, resolveTx, passTx, staleReader, joinFuture } from "./core/scheduler.js";
|
|
10
10
|
|
|
11
11
|
import { cleanup, createRoot, getOwner, dispose } from "./core/owner.js";
|
|
12
12
|
|
|
@@ -463,7 +463,7 @@ function createMemo(e, t) {
|
|
|
463
463
|
// guessed node's own re-ask is not answered by it (#3895): park
|
|
464
464
|
// on that flight, or reject with its error.
|
|
465
465
|
const e = read(t);
|
|
466
|
-
if (t.l & CONFIG_GUESS && t.m & (STATUS_PENDING | STATUS_ERROR)) throw t.T?.
|
|
466
|
+
if (t.l & CONFIG_GUESS && t.m & (STATUS_PENDING | STATUS_ERROR)) throw t.T?.U;
|
|
467
467
|
return e;
|
|
468
468
|
}, t => {
|
|
469
469
|
n(typeof e === "function" ? t : e);
|
|
@@ -657,7 +657,7 @@ function createMemo(e, t) {
|
|
|
657
657
|
// still holding the optimistic value — reads do not pull (#3411). Fall
|
|
658
658
|
// to the next pass while the heap has work; `run` swapped the queue,
|
|
659
659
|
// so this lands there, and `enqueue` keeps the drain alive.
|
|
660
|
-
if (dirtyQueue.et >= dirtyQueue.
|
|
660
|
+
if (dirtyQueue.et >= dirtyQueue.Fe) return globalQueue.enqueue(EFFECT_USER, fire);
|
|
661
661
|
// Unowned, out-of-band fire (no owner, or a children-forbidden one this
|
|
662
662
|
// one-shot must not bind to): a returned cleanup has no lifecycle to
|
|
663
663
|
// attach to. Reject it in dev; in production the return is simply
|
|
@@ -666,4 +666,46 @@ function createMemo(e, t) {
|
|
|
666
666
|
});
|
|
667
667
|
}
|
|
668
668
|
|
|
669
|
-
|
|
669
|
+
/**
|
|
670
|
+
* Schedules `callback` to run **once**, right after the pending flush
|
|
671
|
+
* finishes, in the same microtask checkpoint (before the browser paints).
|
|
672
|
+
* Unlike `onSettled`, it never waits on async work: if that flush is held by
|
|
673
|
+
* a pending transition, the callback still runs.
|
|
674
|
+
*
|
|
675
|
+
* Its main use is keeping a write out of another update's hold. Writes made
|
|
676
|
+
* in the same synchronous frame are applied together, so when one of them
|
|
677
|
+
* starts async work (a route change, a fetch), the others are held with it
|
|
678
|
+
* until it resolves. A write made in `onFlush` happens after that flush, so
|
|
679
|
+
* it is its own update: it commits on its own unless something it changes
|
|
680
|
+
* also derives from the held work (a memo or `createEffect` reading both),
|
|
681
|
+
* in which case it joins that hold as any later write would.
|
|
682
|
+
*
|
|
683
|
+
* Call it from event handlers and effect callbacks (including
|
|
684
|
+
* `createTrackedEffect` and `onSettled` bodies). In an owned scope such as a
|
|
685
|
+
* component body or a computation it warns in dev: use `onSettled` there.
|
|
686
|
+
*
|
|
687
|
+
* - A write in the callback lands after any write made inline in the same
|
|
688
|
+
* frame. Don't write the same signal both inside and outside it; use a
|
|
689
|
+
* functional setter if the order matters.
|
|
690
|
+
* - Several `onFlush` callbacks run in call order and batch into one flush.
|
|
691
|
+
* - `queueMicrotask` is not a substitute: called before the frame's first
|
|
692
|
+
* write, it runs before that flush and its write joins it.
|
|
693
|
+
*
|
|
694
|
+
* @example
|
|
695
|
+
* ```tsx
|
|
696
|
+
* // A menu closes now even when the consumer's onSelect starts async work.
|
|
697
|
+
* const select = (id: string) => {
|
|
698
|
+
* onFlush(() => setOpen(false));
|
|
699
|
+
* props.onSelect?.(id);
|
|
700
|
+
* };
|
|
701
|
+
* ```
|
|
702
|
+
*
|
|
703
|
+
* @param callback Function to run once after the pending flush
|
|
704
|
+
*/ function onFlush(e) {
|
|
705
|
+
// The frame's flush is queued (or already draining) ahead of this
|
|
706
|
+
// microtask, so the callback's writes start a flush of their own.
|
|
707
|
+
schedule();
|
|
708
|
+
queueMicrotask(e);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
export { accessor, createEffect, createMemo, createOptimistic, createReaction, createRenderEffect, createSignal, createTrackedEffect, onCleanup, onFlush, onSettled, refresh, resolve, until };
|
|
@@ -72,7 +72,7 @@ function scopeOf(e, o) {
|
|
|
72
72
|
if (f !== undefined) {
|
|
73
73
|
if (f.pb !== null) o.eo.add(f.v);
|
|
74
74
|
// The writer's view: the tick's own unflushed guesses are in motion too.
|
|
75
|
-
if (f.fam?.opt === true) r = optHooks.view(f, r, true);
|
|
75
|
+
if (optHooks && f.fam?.opt === true) r = optHooks.view(f, r, true);
|
|
76
76
|
const e = f.n;
|
|
77
77
|
if (e !== null) for (const o of Reflect.ownKeys(e))
|
|
78
78
|
// Another mark's carrier is its own channel: counting it here would
|
package/dist/prod/store/hooks.js
CHANGED
|
@@ -83,7 +83,7 @@ function notifyOptimisticWrites(e, n) {
|
|
|
83
83
|
// inner store's truth for its key before guessing over it.
|
|
84
84
|
const o = e.ch ? e.v : null;
|
|
85
85
|
const guess = (e, n, i, r) => {
|
|
86
|
-
if (o !== null) e.
|
|
86
|
+
if (o !== null) e.le = i ? n in t : unwrapValue(t[n]);
|
|
87
87
|
// By value: a function leaf is a value, not an updater (#3017).
|
|
88
88
|
optimisticWrite(e, () => r);
|
|
89
89
|
};
|
|
@@ -274,7 +274,7 @@ function arrangementEqual(e, n, t) {
|
|
|
274
274
|
if (!t) return fold(e, n);
|
|
275
275
|
const i = e.O;
|
|
276
276
|
if (i === undefined || e.ze !== $TRACK) return;
|
|
277
|
-
const r = e.T.
|
|
277
|
+
const r = e.T.P;
|
|
278
278
|
if (!(r instanceof LaneView)) return;
|
|
279
279
|
if (!Array.isArray(n) || !Array.isArray(r.rows)) {
|
|
280
280
|
r.base = n;
|
|
@@ -318,7 +318,7 @@ function arrangementEqual(e, n, t) {
|
|
|
318
318
|
// key's new object is the same row, its target adopted it).
|
|
319
319
|
if (n === undefined) {
|
|
320
320
|
if (!sameRow(d[e], f[e], o)) laneSet(getNode(i, e), f[e], c);
|
|
321
|
-
} else if (!sameRow(n.l & CONFIG_OVERRIDE ? n.T.
|
|
321
|
+
} else if (!sameRow(n.l & CONFIG_OVERRIDE ? n.T.P : d[e], f[e], o)) laneSet(n, f[e], c);
|
|
322
322
|
}
|
|
323
323
|
if (p !== null) {
|
|
324
324
|
for (let e = f.length; ;e++) {
|
|
@@ -342,8 +342,8 @@ function arrangementEqual(e, n, t) {
|
|
|
342
342
|
const i = txOf(e);
|
|
343
343
|
// A guess the screen never showed is void at the correction (D-34); a
|
|
344
344
|
// keyed arrangement guess's view carries its removed-keys set.
|
|
345
|
-
if (!i.
|
|
346
|
-
const r = e.T.
|
|
345
|
+
if (!i.ge || !(t?.l & CONFIG_OVERRIDE) || !t.T.P?.removed) return false;
|
|
346
|
+
const r = e.T.P;
|
|
347
347
|
if ((!e.xe || !e.xe(r, n)) && !GlobalQueue.nn(r, n)) {
|
|
348
348
|
i.folded = foldedRead;
|
|
349
349
|
insertSubs(e);
|
|
@@ -365,8 +365,8 @@ function arrangementEqual(e, n, t) {
|
|
|
365
365
|
const t = txOf(n);
|
|
366
366
|
joinPassAt(e, resolveTx(t._parent ?? t));
|
|
367
367
|
}
|
|
368
|
-
if (n.
|
|
369
|
-
return n.l & CONFIG_SLOT_NODE ? GlobalQueue.fn(n) : n.
|
|
368
|
+
if (n.ie !== NOT_PENDING) return n.ie;
|
|
369
|
+
return n.l & CONFIG_SLOT_NODE ? GlobalQueue.fn(n) : n.le;
|
|
370
370
|
}
|
|
371
371
|
|
|
372
372
|
function sameRow(e, n, t) {
|
|
@@ -383,8 +383,8 @@ function sameRow(e, n, t) {
|
|
|
383
383
|
if (!(e.l & CONFIG_OVERRIDE)) {
|
|
384
384
|
e.l |= CONFIG_OVERRIDE;
|
|
385
385
|
list(e, t);
|
|
386
|
-
} else if (i.
|
|
387
|
-
i.
|
|
386
|
+
} else if (i.P === n) return;
|
|
387
|
+
i.P = n;
|
|
388
388
|
if (e.o !== null) {
|
|
389
389
|
insertSubs(e);
|
|
390
390
|
laneDirty(e, t);
|
|
@@ -430,7 +430,7 @@ function sweepOverlaid() {
|
|
|
430
430
|
// The container shows its backing again (a shown arrangement guess
|
|
431
431
|
// that ended without a landing left its `LaneView` as the value).
|
|
432
432
|
const t = e.k;
|
|
433
|
-
if (t !== null && t.
|
|
433
|
+
if (t !== null && t.le instanceof LaneView) t.le = t.le.base;
|
|
434
434
|
}
|
|
435
435
|
if (n.size === 0) overlaidFamilies.delete(e);
|
|
436
436
|
}
|
|
@@ -447,8 +447,8 @@ function sweepOverlaid() {
|
|
|
447
447
|
if (i !== null) for (const e of Reflect.ownKeys(i)) {
|
|
448
448
|
const r = i[e];
|
|
449
449
|
const o = untrack(() => unwrapValue(n[e]));
|
|
450
|
-
if (r.xe && r.xe(r.
|
|
451
|
-
r.
|
|
450
|
+
if (r.xe && r.xe(r.le, o)) continue;
|
|
451
|
+
r.le = o;
|
|
452
452
|
// (The lane's end notified it this epoch when the shown value and the
|
|
453
453
|
// covered one differed — its readers re-derive already.)
|
|
454
454
|
if (r.o !== null && r.Me !== notifyEpoch) {
|
|
@@ -460,8 +460,8 @@ function sweepOverlaid() {
|
|
|
460
460
|
if (r !== null) for (const e of Reflect.ownKeys(r)) {
|
|
461
461
|
const i = r[e];
|
|
462
462
|
const o = untrack(() => e in n);
|
|
463
|
-
if (i.
|
|
464
|
-
i.
|
|
463
|
+
if (i.le === o) continue;
|
|
464
|
+
i.le = o;
|
|
465
465
|
if (i.o !== null && i.Me !== notifyEpoch) {
|
|
466
466
|
insertSubs(i);
|
|
467
467
|
t = true;
|
|
@@ -470,9 +470,9 @@ function sweepOverlaid() {
|
|
|
470
470
|
// The arrangement the readers saw (the shown guess) against the inner's
|
|
471
471
|
// now: a structural reader re-derives when they differ.
|
|
472
472
|
const o = e.k;
|
|
473
|
-
if (o !== null && o.o !== null && o.
|
|
473
|
+
if (o !== null && o.o !== null && o.le instanceof LaneView && o.Me !== notifyEpoch) {
|
|
474
474
|
const i = Array.isArray(n) ? untrack(() => n.map(unwrapValue)) : n;
|
|
475
|
-
if (!arrangementEqual(o.
|
|
475
|
+
if (!arrangementEqual(o.le.rows, i, e.fam?.key ?? null)) {
|
|
476
476
|
insertSubs(o);
|
|
477
477
|
t = true;
|
|
478
478
|
}
|