@reckona/mreact-compat 0.0.65 → 0.0.67
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/package.json +4 -3
- package/src/class-component.ts +386 -0
- package/src/context.ts +140 -0
- package/src/devtools.ts +1275 -0
- package/src/dom-children.ts +34 -0
- package/src/dom-props.ts +408 -0
- package/src/element.ts +317 -0
- package/src/event-listeners.ts +27 -0
- package/src/event-priority.ts +1 -0
- package/src/event-replay.ts +154 -0
- package/src/event-types.ts +18 -0
- package/src/events.ts +384 -0
- package/src/fiber-child.ts +364 -0
- package/src/fiber-commit.ts +83 -0
- package/src/fiber-flags.ts +21 -0
- package/src/fiber-host.ts +1564 -0
- package/src/fiber-lanes.ts +99 -0
- package/src/fiber-reconciler.ts +639 -0
- package/src/fiber-scheduler.ts +435 -0
- package/src/fiber-work-loop.ts +224 -0
- package/src/fiber.ts +148 -0
- package/src/flight-decoder.ts +205 -0
- package/src/flight-element-builder.ts +110 -0
- package/src/flight-parser.ts +698 -0
- package/src/flight-protocol.ts +71 -0
- package/src/flight-types.ts +148 -0
- package/src/flight.ts +162 -0
- package/src/hooks.ts +1940 -0
- package/src/hydration.ts +314 -0
- package/src/index.ts +95 -0
- package/src/internal.ts +7 -0
- package/src/jsx-dev-runtime.ts +40 -0
- package/src/jsx-runtime.ts +119 -0
- package/src/prop-comparison.ts +50 -0
- package/src/reconcile-types.ts +26 -0
- package/src/reconciler.ts +692 -0
- package/src/render.ts +29 -0
- package/src/root.ts +493 -0
- package/src/scheduler.ts +157 -0
- package/src/suspense.ts +317 -0
- package/src/thenable.ts +7 -0
- package/src/url-safety.ts +7 -0
package/src/root.ts
ADDED
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
import type { ReactCompatNode } from "./element.js";
|
|
2
|
+
import {
|
|
3
|
+
createRootRuntime,
|
|
4
|
+
flushSyncUpdates,
|
|
5
|
+
hasStableExternalStores,
|
|
6
|
+
type RenderPriority,
|
|
7
|
+
type RootRuntime,
|
|
8
|
+
} from "./hooks.js";
|
|
9
|
+
import { commitDevToolsRoot, unmountDevToolsRoot } from "./devtools.js";
|
|
10
|
+
import {
|
|
11
|
+
applyStreamingHydrationFragments,
|
|
12
|
+
findContainingResumeBoundaryId,
|
|
13
|
+
getHydrationScope,
|
|
14
|
+
type HydrationRecoverableErrorInfo,
|
|
15
|
+
type RenderOptions,
|
|
16
|
+
} from "./hydration.js";
|
|
17
|
+
import {
|
|
18
|
+
enableEventHydrationManifestReplay,
|
|
19
|
+
readEventHydrationManifest,
|
|
20
|
+
replayQueuedHydrationEvents,
|
|
21
|
+
type EventHydrationManifest,
|
|
22
|
+
} from "./event-replay.js";
|
|
23
|
+
import {
|
|
24
|
+
ContinuousEventLane,
|
|
25
|
+
SyncLane,
|
|
26
|
+
TransitionLane,
|
|
27
|
+
type Lane,
|
|
28
|
+
} from "./fiber-lanes.js";
|
|
29
|
+
import {
|
|
30
|
+
createContainerFiberRoot,
|
|
31
|
+
enqueueRootRender,
|
|
32
|
+
} from "./fiber-work-loop.js";
|
|
33
|
+
import { commitFiberRoot } from "./fiber-commit.js";
|
|
34
|
+
import {
|
|
35
|
+
canRenderHostFiber,
|
|
36
|
+
commitHydratingHostFiberRoot,
|
|
37
|
+
renderHydratingHostFiberRoot,
|
|
38
|
+
renderHostFiberRoot,
|
|
39
|
+
} from "./fiber-host.js";
|
|
40
|
+
import type { Fiber, FiberRoot } from "./fiber.js";
|
|
41
|
+
import { renderIntoContainer } from "./reconciler.js";
|
|
42
|
+
|
|
43
|
+
export interface Root {
|
|
44
|
+
render(element: ReactCompatNode): void;
|
|
45
|
+
unmount(): void;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface RootOptions {
|
|
49
|
+
identifierPrefix?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface HydrateRootOptions {
|
|
53
|
+
onRecoverableError?: (
|
|
54
|
+
error: Error,
|
|
55
|
+
info: HydrationRecoverableErrorInfo,
|
|
56
|
+
) => void;
|
|
57
|
+
resumeId?: string;
|
|
58
|
+
consumeResumeMarkers?: boolean;
|
|
59
|
+
identifierPrefix?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface StreamingHydrationRoot {
|
|
63
|
+
hydrate(element: ReactCompatNode, options?: HydrateRootOptions): Root;
|
|
64
|
+
dispose(): void;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface StreamingHydrationRootOptions {
|
|
68
|
+
manifest?: EventHydrationManifest;
|
|
69
|
+
manifestRoot?: ParentNode;
|
|
70
|
+
fragmentRoot?: ParentNode;
|
|
71
|
+
applyOutOfOrderFragments?: boolean;
|
|
72
|
+
observeOutOfOrderFragments?: boolean;
|
|
73
|
+
selectiveHydration?: SelectiveHydrationOptions;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface SelectiveHydrationOptions {
|
|
77
|
+
element?: ReactCompatNode;
|
|
78
|
+
options?: HydrateRootOptions | ((event: Event) => HydrateRootOptions);
|
|
79
|
+
boundaries?: Record<string, SelectiveHydrationBoundary>;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface SelectiveHydrationBoundary {
|
|
83
|
+
element: ReactCompatNode;
|
|
84
|
+
options?: HydrateRootOptions | ((event: Event) => HydrateRootOptions);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const legacyRoots = new WeakMap<Element, Root>();
|
|
88
|
+
|
|
89
|
+
export function createRoot(
|
|
90
|
+
container: Element,
|
|
91
|
+
options: RootOptions = {},
|
|
92
|
+
): Root {
|
|
93
|
+
const fiberRoot = createContainerFiberRoot(container);
|
|
94
|
+
const runtime = createRootRuntime((priority = "sync") => {
|
|
95
|
+
if (runtime.currentElement !== undefined) {
|
|
96
|
+
enqueueRootRender(fiberRoot, runtime.currentElement, laneForRenderPriority(priority), () => {
|
|
97
|
+
if (canRenderHostFiber(runtime.currentElement as ReactCompatNode)) {
|
|
98
|
+
return renderHostFiberIntoContainer(
|
|
99
|
+
container,
|
|
100
|
+
fiberRoot,
|
|
101
|
+
runtime,
|
|
102
|
+
runtime.currentElement as ReactCompatNode,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
renderIntoContainer(container, runtime.currentElement, runtime);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}, options);
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
render(element) {
|
|
113
|
+
runtime.currentElement = element;
|
|
114
|
+
enqueueRootRender(fiberRoot, element, SyncLane, () => {
|
|
115
|
+
if (canRenderHostFiber(element)) {
|
|
116
|
+
return renderHostFiberIntoContainer(container, fiberRoot, runtime, element);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
renderIntoContainer(container, element, runtime);
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
unmount() {
|
|
123
|
+
runtime.currentElement = undefined;
|
|
124
|
+
runtime.dispose();
|
|
125
|
+
runtime.instances.clear();
|
|
126
|
+
unmountDevToolsRoot(container);
|
|
127
|
+
container.replaceChildren();
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function renderHostFiberIntoContainer(
|
|
133
|
+
container: Element,
|
|
134
|
+
fiberRoot: FiberRoot,
|
|
135
|
+
runtime: RootRuntime,
|
|
136
|
+
element: ReactCompatNode,
|
|
137
|
+
): Fiber {
|
|
138
|
+
for (let attempt = 0; attempt < 25; attempt += 1) {
|
|
139
|
+
runtime.beginRender();
|
|
140
|
+
let committed = false;
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
for (const portalContainer of runtime.portalContainers) {
|
|
144
|
+
portalContainer.replaceChildren();
|
|
145
|
+
}
|
|
146
|
+
runtime.portalContainers.clear();
|
|
147
|
+
|
|
148
|
+
const finishedWork = renderHostFiberRoot(fiberRoot, element, runtime);
|
|
149
|
+
|
|
150
|
+
if (!hasStableExternalStores(runtime)) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
fiberRoot.finishedWork = finishedWork;
|
|
155
|
+
commitFiberRoot(fiberRoot);
|
|
156
|
+
commitDevToolsRoot(container, fiberRoot);
|
|
157
|
+
committed = true;
|
|
158
|
+
return finishedWork;
|
|
159
|
+
} finally {
|
|
160
|
+
runtime.endRender(committed);
|
|
161
|
+
if (committed) {
|
|
162
|
+
runtime.flushEffects();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
throw new Error("Store unstable.");
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function renderHydratingHostFiberIntoContainer(
|
|
171
|
+
container: Element,
|
|
172
|
+
fiberRoot: FiberRoot,
|
|
173
|
+
runtime: RootRuntime,
|
|
174
|
+
element: ReactCompatNode,
|
|
175
|
+
options: RenderOptions & {
|
|
176
|
+
resumeId?: string;
|
|
177
|
+
consumeResumeMarkers?: boolean;
|
|
178
|
+
},
|
|
179
|
+
): Fiber {
|
|
180
|
+
for (let attempt = 0; attempt < 25; attempt += 1) {
|
|
181
|
+
runtime.beginRender();
|
|
182
|
+
let committed = false;
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
for (const portalContainer of runtime.portalContainers) {
|
|
186
|
+
portalContainer.replaceChildren();
|
|
187
|
+
}
|
|
188
|
+
runtime.portalContainers.clear();
|
|
189
|
+
|
|
190
|
+
const scope = getHydrationScope(container, options.resumeId);
|
|
191
|
+
const finishedWork = renderHydratingHostFiberRoot(
|
|
192
|
+
fiberRoot,
|
|
193
|
+
element,
|
|
194
|
+
runtime,
|
|
195
|
+
scope,
|
|
196
|
+
options,
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
if (!hasStableExternalStores(runtime)) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
commitHydratingHostFiberRoot(fiberRoot, finishedWork, scope, options);
|
|
204
|
+
fiberRoot.current = finishedWork;
|
|
205
|
+
fiberRoot.current.stateNode = fiberRoot;
|
|
206
|
+
fiberRoot.finishedWork = undefined;
|
|
207
|
+
fiberRoot.workInProgress = undefined;
|
|
208
|
+
fiberRoot.workInProgressRootRenderLanes = 0;
|
|
209
|
+
commitDevToolsRoot(container, fiberRoot);
|
|
210
|
+
committed = true;
|
|
211
|
+
return finishedWork;
|
|
212
|
+
} finally {
|
|
213
|
+
runtime.endRender(committed);
|
|
214
|
+
if (committed) {
|
|
215
|
+
runtime.flushEffects();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
throw new Error("Store unstable.");
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function render(element: ReactCompatNode, container: Element): void {
|
|
224
|
+
const root = legacyRoots.get(container) ?? createRoot(container);
|
|
225
|
+
legacyRoots.set(container, root);
|
|
226
|
+
root.render(element);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function flushSync<T>(callback: () => T): T {
|
|
230
|
+
return flushSyncUpdates(callback);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function hydrateRoot(
|
|
234
|
+
container: Element,
|
|
235
|
+
element: ReactCompatNode,
|
|
236
|
+
options: HydrateRootOptions = {},
|
|
237
|
+
): Root {
|
|
238
|
+
const fiberRoot = createContainerFiberRoot(container);
|
|
239
|
+
const renderOptions: RenderOptions & {
|
|
240
|
+
resumeId?: string;
|
|
241
|
+
consumeResumeMarkers?: boolean;
|
|
242
|
+
} = {
|
|
243
|
+
hydration:
|
|
244
|
+
options.onRecoverableError === undefined
|
|
245
|
+
? {}
|
|
246
|
+
: { onRecoverableError: options.onRecoverableError },
|
|
247
|
+
...(options.resumeId === undefined ? {} : { resumeId: options.resumeId }),
|
|
248
|
+
...(options.consumeResumeMarkers === undefined
|
|
249
|
+
? {}
|
|
250
|
+
: { consumeResumeMarkers: options.consumeResumeMarkers }),
|
|
251
|
+
};
|
|
252
|
+
const runtime = createRootRuntime((priority = "sync") => {
|
|
253
|
+
if (runtime.currentElement !== undefined) {
|
|
254
|
+
enqueueRootRender(fiberRoot, runtime.currentElement, laneForRenderPriority(priority), () => {
|
|
255
|
+
if (canRenderHostFiber(runtime.currentElement as ReactCompatNode)) {
|
|
256
|
+
return renderHydratingHostFiberIntoContainer(
|
|
257
|
+
container,
|
|
258
|
+
fiberRoot,
|
|
259
|
+
runtime,
|
|
260
|
+
runtime.currentElement as ReactCompatNode,
|
|
261
|
+
renderOptions,
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
renderIntoContainer(container, runtime.currentElement, runtime, renderOptions);
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}, {
|
|
269
|
+
...(options.identifierPrefix === undefined
|
|
270
|
+
? {}
|
|
271
|
+
: { identifierPrefix: options.identifierPrefix }),
|
|
272
|
+
idMode: "server",
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
const root: Root = {
|
|
276
|
+
render(nextElement) {
|
|
277
|
+
runtime.currentElement = nextElement;
|
|
278
|
+
enqueueRootRender(fiberRoot, nextElement, SyncLane, () => {
|
|
279
|
+
if (canRenderHostFiber(nextElement)) {
|
|
280
|
+
return renderHostFiberIntoContainer(container, fiberRoot, runtime, nextElement);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
renderIntoContainer(container, nextElement, runtime);
|
|
284
|
+
});
|
|
285
|
+
},
|
|
286
|
+
unmount() {
|
|
287
|
+
runtime.currentElement = undefined;
|
|
288
|
+
runtime.dispose();
|
|
289
|
+
runtime.instances.clear();
|
|
290
|
+
unmountDevToolsRoot(container);
|
|
291
|
+
container.replaceChildren();
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
runtime.currentElement = element;
|
|
296
|
+
enqueueRootRender(fiberRoot, element, SyncLane, () => {
|
|
297
|
+
if (canRenderHostFiber(element)) {
|
|
298
|
+
return renderHydratingHostFiberIntoContainer(
|
|
299
|
+
container,
|
|
300
|
+
fiberRoot,
|
|
301
|
+
runtime,
|
|
302
|
+
element,
|
|
303
|
+
renderOptions,
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
renderIntoContainer(container, element, runtime, renderOptions);
|
|
308
|
+
});
|
|
309
|
+
replayQueuedHydrationEvents(container);
|
|
310
|
+
return root;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function laneForRenderPriority(priority: RenderPriority): Lane {
|
|
314
|
+
if (priority === "transition") {
|
|
315
|
+
return TransitionLane;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (priority === "continuous") {
|
|
319
|
+
return ContinuousEventLane;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return SyncLane;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export function createStreamingHydrationRoot(
|
|
326
|
+
container: Element,
|
|
327
|
+
options: StreamingHydrationRootOptions = {},
|
|
328
|
+
): StreamingHydrationRoot {
|
|
329
|
+
const fragmentRoot = options.fragmentRoot ?? container.ownerDocument;
|
|
330
|
+
const manifestRoot = options.manifestRoot ?? container;
|
|
331
|
+
const manifest = options.manifest ?? readEventHydrationManifest(manifestRoot);
|
|
332
|
+
|
|
333
|
+
if (options.applyOutOfOrderFragments !== false) {
|
|
334
|
+
applyStreamingHydrationFragments(fragmentRoot);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
let hydratedRoot: Root | undefined;
|
|
338
|
+
const hydrate = (
|
|
339
|
+
element: ReactCompatNode,
|
|
340
|
+
hydrateOptions: HydrateRootOptions = {},
|
|
341
|
+
): Root => {
|
|
342
|
+
if (options.applyOutOfOrderFragments !== false) {
|
|
343
|
+
applyStreamingHydrationFragments(fragmentRoot);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const root = hydrateRoot(container, element, hydrateOptions);
|
|
347
|
+
hydratedRoot = root;
|
|
348
|
+
disposeReplayCaptureOnce();
|
|
349
|
+
return root;
|
|
350
|
+
};
|
|
351
|
+
const disposeReplayCapture = enableEventHydrationManifestReplay(
|
|
352
|
+
container,
|
|
353
|
+
manifest,
|
|
354
|
+
{
|
|
355
|
+
onCapturedEvent(event, target) {
|
|
356
|
+
const selectiveHydration = options.selectiveHydration;
|
|
357
|
+
const selectiveBoundary = resolveSelectiveHydrationBoundary(
|
|
358
|
+
container,
|
|
359
|
+
event,
|
|
360
|
+
target,
|
|
361
|
+
manifest,
|
|
362
|
+
selectiveHydration,
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
if (selectiveBoundary === undefined || hydratedRoot !== undefined) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
hydrate(
|
|
370
|
+
selectiveBoundary.element,
|
|
371
|
+
resolveSelectiveHydrationOptions(event, selectiveBoundary),
|
|
372
|
+
);
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
);
|
|
376
|
+
const observer =
|
|
377
|
+
options.observeOutOfOrderFragments === true &&
|
|
378
|
+
typeof MutationObserver !== "undefined" &&
|
|
379
|
+
fragmentRoot instanceof Node
|
|
380
|
+
? new MutationObserver(() => {
|
|
381
|
+
applyStreamingHydrationFragments(fragmentRoot);
|
|
382
|
+
})
|
|
383
|
+
: undefined;
|
|
384
|
+
let replayDisposed = false;
|
|
385
|
+
|
|
386
|
+
observer?.observe(fragmentRoot as Node, { childList: true, subtree: true });
|
|
387
|
+
|
|
388
|
+
const disposeReplayCaptureOnce = (): void => {
|
|
389
|
+
if (!replayDisposed) {
|
|
390
|
+
disposeReplayCapture();
|
|
391
|
+
replayDisposed = true;
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
return {
|
|
396
|
+
hydrate,
|
|
397
|
+
dispose() {
|
|
398
|
+
disposeReplayCaptureOnce();
|
|
399
|
+
observer?.disconnect();
|
|
400
|
+
},
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export function unmountComponentAtNode(container: Element): boolean {
|
|
405
|
+
const root = legacyRoots.get(container);
|
|
406
|
+
|
|
407
|
+
if (root !== undefined) {
|
|
408
|
+
root.unmount();
|
|
409
|
+
legacyRoots.delete(container);
|
|
410
|
+
return true;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const hadChildren = container.childNodes.length > 0;
|
|
414
|
+
container.replaceChildren();
|
|
415
|
+
return hadChildren;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function resolveSelectiveHydrationBoundary(
|
|
419
|
+
container: Element,
|
|
420
|
+
event: Event,
|
|
421
|
+
target: EventTarget,
|
|
422
|
+
manifest: EventHydrationManifest | undefined,
|
|
423
|
+
selectiveHydration: SelectiveHydrationOptions | undefined,
|
|
424
|
+
): SelectiveHydrationBoundary | undefined {
|
|
425
|
+
if (selectiveHydration === undefined) {
|
|
426
|
+
return undefined;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const resumeId = resolveSelectiveHydrationResumeId(
|
|
430
|
+
container,
|
|
431
|
+
event,
|
|
432
|
+
target,
|
|
433
|
+
manifest,
|
|
434
|
+
);
|
|
435
|
+
const boundary =
|
|
436
|
+
resumeId === undefined ? undefined : selectiveHydration.boundaries?.[resumeId];
|
|
437
|
+
|
|
438
|
+
if (boundary !== undefined && resumeId !== undefined) {
|
|
439
|
+
return {
|
|
440
|
+
element: boundary.element,
|
|
441
|
+
options: boundary.options ?? { resumeId, consumeResumeMarkers: true },
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (selectiveHydration.element === undefined) {
|
|
446
|
+
return undefined;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
return {
|
|
450
|
+
element: selectiveHydration.element,
|
|
451
|
+
...(selectiveHydration.options === undefined
|
|
452
|
+
? {}
|
|
453
|
+
: { options: selectiveHydration.options }),
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function resolveSelectiveHydrationOptions(
|
|
458
|
+
event: Event,
|
|
459
|
+
boundary: SelectiveHydrationBoundary,
|
|
460
|
+
): HydrateRootOptions {
|
|
461
|
+
return typeof boundary.options === "function"
|
|
462
|
+
? boundary.options(event)
|
|
463
|
+
: boundary.options ?? {};
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function resolveSelectiveHydrationResumeId(
|
|
467
|
+
container: Element,
|
|
468
|
+
event: Event,
|
|
469
|
+
target: EventTarget,
|
|
470
|
+
manifest: EventHydrationManifest | undefined,
|
|
471
|
+
): string | undefined {
|
|
472
|
+
if (!(target instanceof Node) || manifest === undefined) {
|
|
473
|
+
return undefined;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const containingResumeId = findContainingResumeBoundaryId(container, target);
|
|
477
|
+
|
|
478
|
+
if (containingResumeId === undefined) {
|
|
479
|
+
return undefined;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
return manifest.events.some(
|
|
483
|
+
(entry) =>
|
|
484
|
+
entry.event === event.type &&
|
|
485
|
+
getManifestResumeId(entry.id) === containingResumeId,
|
|
486
|
+
)
|
|
487
|
+
? containingResumeId
|
|
488
|
+
: undefined;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function getManifestResumeId(id: string): string {
|
|
492
|
+
return id.split(":")[0] ?? id;
|
|
493
|
+
}
|
package/src/scheduler.ts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cancelCallback,
|
|
3
|
+
forceFrameRate,
|
|
4
|
+
getFirstCallbackNode,
|
|
5
|
+
now,
|
|
6
|
+
requestPaint,
|
|
7
|
+
scheduleCallback,
|
|
8
|
+
shouldYieldToHost,
|
|
9
|
+
startLoggingSchedulerProfilingEvents,
|
|
10
|
+
stopLoggingSchedulerProfilingEvents,
|
|
11
|
+
type SchedulerProfilingEvent,
|
|
12
|
+
type SchedulerCallback,
|
|
13
|
+
type SchedulerPriority,
|
|
14
|
+
type SchedulerTask,
|
|
15
|
+
} from "./fiber-scheduler.js";
|
|
16
|
+
|
|
17
|
+
export type unstable_PriorityLevel = 1 | 2 | 3 | 4 | 5;
|
|
18
|
+
export type unstable_CallbackNode = SchedulerTask;
|
|
19
|
+
export type unstable_Callback = (
|
|
20
|
+
didTimeout: boolean,
|
|
21
|
+
) => unstable_Callback | null | void;
|
|
22
|
+
|
|
23
|
+
export const unstable_ImmediatePriority = 1;
|
|
24
|
+
export const unstable_UserBlockingPriority = 2;
|
|
25
|
+
export const unstable_NormalPriority = 3;
|
|
26
|
+
export const unstable_LowPriority = 4;
|
|
27
|
+
export const unstable_IdlePriority = 5;
|
|
28
|
+
export const unstable_Profiling = {
|
|
29
|
+
startLoggingProfilingEvents: startLoggingSchedulerProfilingEvents,
|
|
30
|
+
stopLoggingProfilingEvents: stopLoggingSchedulerProfilingEvents,
|
|
31
|
+
};
|
|
32
|
+
export type unstable_ProfilingEvent = SchedulerProfilingEvent;
|
|
33
|
+
|
|
34
|
+
let currentPriorityLevel: unstable_PriorityLevel = unstable_NormalPriority;
|
|
35
|
+
|
|
36
|
+
export function unstable_now(): number {
|
|
37
|
+
return now();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function unstable_scheduleCallback(
|
|
41
|
+
priorityLevel: unstable_PriorityLevel,
|
|
42
|
+
callback: unstable_Callback,
|
|
43
|
+
options?: { delay?: number },
|
|
44
|
+
): unstable_CallbackNode {
|
|
45
|
+
return scheduleCallback(
|
|
46
|
+
toSchedulerPriority(priorityLevel),
|
|
47
|
+
wrapScheduledCallback(priorityLevel, callback),
|
|
48
|
+
options,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function unstable_cancelCallback(task: unstable_CallbackNode): void {
|
|
53
|
+
cancelCallback(task);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function unstable_shouldYield(): boolean {
|
|
57
|
+
return shouldYieldToHost();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function unstable_requestPaint(): void {
|
|
61
|
+
requestPaint();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function unstable_forceFrameRate(fps: number): void {
|
|
65
|
+
forceFrameRate(fps);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function unstable_getCurrentPriorityLevel(): unstable_PriorityLevel {
|
|
69
|
+
return currentPriorityLevel;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function unstable_runWithPriority<T>(
|
|
73
|
+
priorityLevel: unstable_PriorityLevel,
|
|
74
|
+
callback: () => T,
|
|
75
|
+
): T {
|
|
76
|
+
return runWithPriorityLevel(priorityLevel, callback);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function unstable_next<T>(callback: () => T): T {
|
|
80
|
+
const nextPriority =
|
|
81
|
+
currentPriorityLevel === unstable_ImmediatePriority ||
|
|
82
|
+
currentPriorityLevel === unstable_UserBlockingPriority
|
|
83
|
+
? unstable_NormalPriority
|
|
84
|
+
: currentPriorityLevel;
|
|
85
|
+
return runWithPriorityLevel(nextPriority, callback);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function unstable_wrapCallback<TArgs extends unknown[], TResult>(
|
|
89
|
+
callback: (...args: TArgs) => TResult,
|
|
90
|
+
): (...args: TArgs) => TResult {
|
|
91
|
+
const capturedPriority = currentPriorityLevel;
|
|
92
|
+
return (...args) => runWithPriorityLevel(capturedPriority, () => callback(...args));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function unstable_getFirstCallbackNode(): unstable_CallbackNode | null {
|
|
96
|
+
return getFirstCallbackNode();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function unstable_pauseExecution(): void {
|
|
100
|
+
// React exposes this as an unstable public hook; this scheduler has no global pause state.
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function unstable_continueExecution(): void {
|
|
104
|
+
// Host callbacks are requested eagerly by scheduleCallback, so there is no paused queue to resume.
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function wrapScheduledCallback(
|
|
108
|
+
priorityLevel: unstable_PriorityLevel,
|
|
109
|
+
callback: unstable_Callback,
|
|
110
|
+
): SchedulerCallback {
|
|
111
|
+
return (didTimeout) =>
|
|
112
|
+
runWithPriorityLevel(priorityLevel, () => {
|
|
113
|
+
const continuation = callback(didTimeout);
|
|
114
|
+
|
|
115
|
+
if (typeof continuation === "function") {
|
|
116
|
+
return wrapScheduledCallback(priorityLevel, continuation);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return undefined;
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function runWithPriorityLevel<T>(
|
|
124
|
+
priorityLevel: unstable_PriorityLevel,
|
|
125
|
+
callback: () => T,
|
|
126
|
+
): T {
|
|
127
|
+
const previousPriority = currentPriorityLevel;
|
|
128
|
+
currentPriorityLevel = priorityLevel;
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
return callback();
|
|
132
|
+
} finally {
|
|
133
|
+
currentPriorityLevel = previousPriority;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function toSchedulerPriority(
|
|
138
|
+
priorityLevel: unstable_PriorityLevel,
|
|
139
|
+
): SchedulerPriority {
|
|
140
|
+
if (priorityLevel === unstable_ImmediatePriority) {
|
|
141
|
+
return "immediate";
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (priorityLevel === unstable_UserBlockingPriority) {
|
|
145
|
+
return "user-blocking";
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (priorityLevel === unstable_LowPriority) {
|
|
149
|
+
return "low";
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (priorityLevel === unstable_IdlePriority) {
|
|
153
|
+
return "idle";
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return "normal";
|
|
157
|
+
}
|