@reckona/mreact-compat 0.0.66 → 0.0.68
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/class-component.js.map +1 -1
- package/dist/context.js.map +1 -1
- package/dist/devtools.js.map +1 -1
- package/dist/dom-children.js.map +1 -1
- package/dist/dom-props.js.map +1 -1
- package/dist/element.js.map +1 -1
- package/dist/event-listeners.js.map +1 -1
- package/dist/event-priority.js.map +1 -1
- package/dist/event-replay.js.map +1 -1
- package/dist/event-types.js.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/fiber-child.js.map +1 -1
- package/dist/fiber-commit.js.map +1 -1
- package/dist/fiber-flags.js.map +1 -1
- package/dist/fiber-host.js.map +1 -1
- package/dist/fiber-lanes.js.map +1 -1
- package/dist/fiber-reconciler.js.map +1 -1
- package/dist/fiber-scheduler.js.map +1 -1
- package/dist/fiber-work-loop.js.map +1 -1
- package/dist/fiber.js.map +1 -1
- package/dist/flight-decoder.js.map +1 -1
- package/dist/flight-element-builder.js.map +1 -1
- package/dist/flight-parser.js.map +1 -1
- package/dist/flight-protocol.js.map +1 -1
- package/dist/flight-types.js.map +1 -1
- package/dist/flight.js.map +1 -1
- package/dist/hooks.js.map +1 -1
- package/dist/hydration.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal.js.map +1 -1
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/prop-comparison.js.map +1 -1
- package/dist/reconcile-types.js.map +1 -1
- package/dist/reconciler.js.map +1 -1
- package/dist/render.js.map +1 -1
- package/dist/root.js.map +1 -1
- package/dist/scheduler.js.map +1 -1
- package/dist/suspense.js.map +1 -1
- package/dist/thenable.js.map +1 -1
- package/dist/url-safety.js.map +1 -1
- 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/hooks.ts
ADDED
|
@@ -0,0 +1,1940 @@
|
|
|
1
|
+
import { scheduleCallback } from "./fiber-scheduler.js";
|
|
2
|
+
import {
|
|
3
|
+
Activity,
|
|
4
|
+
Fragment,
|
|
5
|
+
FORWARD_REF_TYPE,
|
|
6
|
+
MEMO_TYPE,
|
|
7
|
+
Profiler,
|
|
8
|
+
isReactCompatElement,
|
|
9
|
+
type ForwardRefType,
|
|
10
|
+
type MemoType,
|
|
11
|
+
type ReactCompatElement,
|
|
12
|
+
type ReactCompatNode,
|
|
13
|
+
} from "./element.js";
|
|
14
|
+
import {
|
|
15
|
+
isReactCompatContext,
|
|
16
|
+
isReactCompatConsumer,
|
|
17
|
+
isReactCompatProvider,
|
|
18
|
+
renderWithContextProvider,
|
|
19
|
+
useContext,
|
|
20
|
+
} from "./context.js";
|
|
21
|
+
import { isThenable } from "./thenable.js";
|
|
22
|
+
import { isDangerousHtmlAttribute, isDangerousHtmlOptIn } from "./url-safety.js";
|
|
23
|
+
import { escapeHtmlAttribute as escapeHtml } from "@reckona/mreact-shared/html-escape";
|
|
24
|
+
|
|
25
|
+
export interface RootRuntime {
|
|
26
|
+
currentElement?: unknown;
|
|
27
|
+
instances: Map<string, ComponentInstance>;
|
|
28
|
+
activeInstanceKeys: Set<string> | undefined;
|
|
29
|
+
activeProfilerPaths: Set<string> | undefined;
|
|
30
|
+
mountedProfilerPaths: Set<string>;
|
|
31
|
+
profilerBaseDurations: Map<string, number>;
|
|
32
|
+
pendingProfilerCommits: PendingProfilerCommit[];
|
|
33
|
+
pendingInsertionEffects: PendingEffect[];
|
|
34
|
+
pendingLayoutEffects: PendingEffect[];
|
|
35
|
+
pendingEffects: PendingEffect[];
|
|
36
|
+
externalStoreChecks: ExternalStoreCheck[];
|
|
37
|
+
portalContainers: Set<Element>;
|
|
38
|
+
idCounter: number;
|
|
39
|
+
identifierPrefix: string;
|
|
40
|
+
idMode: "client" | "server";
|
|
41
|
+
strictModeDepth: number;
|
|
42
|
+
profilerFlushDepth: number;
|
|
43
|
+
rerender(priority?: RenderPriority): void;
|
|
44
|
+
beginRender(): void;
|
|
45
|
+
endRender(committed?: boolean): void;
|
|
46
|
+
flushEffects(): void;
|
|
47
|
+
dispose(): void;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface ComponentInstance {
|
|
51
|
+
hooks: HookSlot[];
|
|
52
|
+
hookIndex: number;
|
|
53
|
+
dirty: boolean;
|
|
54
|
+
devToolsHooks: DevToolsHookValue[];
|
|
55
|
+
devToolsHookTypes: string[];
|
|
56
|
+
devToolsHookSuppressionDepth: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
type EffectCallback = () => void | (() => void);
|
|
60
|
+
type ProfilerPhase = "mount" | "update" | "nested-update";
|
|
61
|
+
type ProfilerOnRender = (
|
|
62
|
+
id: string,
|
|
63
|
+
phase: ProfilerPhase,
|
|
64
|
+
actualDuration: number,
|
|
65
|
+
baseDuration: number,
|
|
66
|
+
startTime: number,
|
|
67
|
+
commitTime: number,
|
|
68
|
+
) => void;
|
|
69
|
+
|
|
70
|
+
interface PendingEffect {
|
|
71
|
+
slot: Extract<HookSlot, { kind: "effect" }>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface PendingProfilerCommit {
|
|
75
|
+
id: string;
|
|
76
|
+
phase: ProfilerPhase;
|
|
77
|
+
onRender: ProfilerOnRender;
|
|
78
|
+
actualDuration: number;
|
|
79
|
+
baseDuration: number;
|
|
80
|
+
startTime: number;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface ExternalStoreCheck {
|
|
84
|
+
getSnapshot: () => unknown;
|
|
85
|
+
value: unknown;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface CacheScope {
|
|
89
|
+
functionCaches: WeakMap<(...args: never[]) => unknown, CacheTrieNode>;
|
|
90
|
+
controller: AbortController;
|
|
91
|
+
ownerStack: string[];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
interface CacheTrieNode {
|
|
95
|
+
primitiveChildren: Map<unknown, CacheTrieNode>;
|
|
96
|
+
objectChildren: WeakMap<object, CacheTrieNode>;
|
|
97
|
+
status?: "fulfilled" | "rejected";
|
|
98
|
+
value?: unknown;
|
|
99
|
+
reason?: unknown;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface DevToolsHookState {
|
|
103
|
+
hooks: DevToolsHookValue[];
|
|
104
|
+
hookTypes: string[];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export type DevToolsHookValue =
|
|
108
|
+
| { kind: "state"; value: unknown }
|
|
109
|
+
| { kind: "reducer"; value: unknown }
|
|
110
|
+
| { kind: "store"; value: unknown }
|
|
111
|
+
| { kind: "ref"; value: unknown }
|
|
112
|
+
| { kind: "memo"; value: unknown; deps?: readonly unknown[] }
|
|
113
|
+
| { kind: "callback"; value: unknown; deps?: readonly unknown[] }
|
|
114
|
+
| { kind: "id"; value: unknown }
|
|
115
|
+
| { kind: "imperative-handle"; deps?: readonly unknown[] }
|
|
116
|
+
| { kind: "transition"; value: unknown }
|
|
117
|
+
| { kind: "deferred"; value: unknown }
|
|
118
|
+
| { kind: "debug"; value: unknown }
|
|
119
|
+
| { kind: "effect"; effectKind: "insertion" | "layout" | "normal"; deps?: readonly unknown[] };
|
|
120
|
+
|
|
121
|
+
type HookSlot =
|
|
122
|
+
| { kind: "state"; value: unknown }
|
|
123
|
+
| {
|
|
124
|
+
kind: "action-state";
|
|
125
|
+
state: unknown;
|
|
126
|
+
pendingCount: number;
|
|
127
|
+
action: (previousState: unknown, payload: unknown) => unknown;
|
|
128
|
+
dispatch?: (payload: unknown) => void;
|
|
129
|
+
error?: unknown;
|
|
130
|
+
}
|
|
131
|
+
| {
|
|
132
|
+
kind: "optimistic";
|
|
133
|
+
baseState: unknown;
|
|
134
|
+
optimisticState: unknown;
|
|
135
|
+
update: (state: unknown, payload: unknown) => unknown;
|
|
136
|
+
dispatch?: (payload: unknown) => void;
|
|
137
|
+
}
|
|
138
|
+
| { kind: "store"; value: unknown }
|
|
139
|
+
| { kind: "ref"; value: { current: unknown } }
|
|
140
|
+
| { kind: "memo"; value: unknown; deps?: readonly unknown[] }
|
|
141
|
+
| { kind: "debug"; value: unknown }
|
|
142
|
+
| {
|
|
143
|
+
kind: "effect";
|
|
144
|
+
effectKind: "insertion" | "layout" | "normal";
|
|
145
|
+
callback: EffectCallback;
|
|
146
|
+
deps?: readonly unknown[];
|
|
147
|
+
cleanup?: () => void;
|
|
148
|
+
disposed?: boolean;
|
|
149
|
+
strictReplay?: boolean;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
let currentRuntime: RootRuntime | undefined;
|
|
153
|
+
let currentInstance: ComponentInstance | undefined;
|
|
154
|
+
let currentCacheScope: CacheScope | undefined;
|
|
155
|
+
const CACHE_SCOPE_SYMBOL = Symbol.for("modular.react.cache_scope");
|
|
156
|
+
const emptyCacheOwnerStack: string[] = [];
|
|
157
|
+
let syncVersion = 0;
|
|
158
|
+
let transitionVersion = 0;
|
|
159
|
+
let transitionDepth = 0;
|
|
160
|
+
let currentTransitionContext: TransitionContext | undefined;
|
|
161
|
+
let transitionRerenderScheduled = false;
|
|
162
|
+
let eventBatchDepth = 0;
|
|
163
|
+
let currentEventPriority: EventPriority = "default";
|
|
164
|
+
let eventRerenderScheduled = false;
|
|
165
|
+
const queuedTransitionRerenders = new Map<RootRuntime, TransitionContext>();
|
|
166
|
+
const queuedEventRerenders = new Set<RootRuntime>();
|
|
167
|
+
export const version = "19.2.6";
|
|
168
|
+
|
|
169
|
+
export function act<T>(callback: () => T): T extends PromiseLike<unknown> ? Promise<void> : void {
|
|
170
|
+
const result = callback();
|
|
171
|
+
|
|
172
|
+
return (isThenable(result) ? Promise.resolve(result).then(() => undefined) : undefined) as T extends PromiseLike<unknown>
|
|
173
|
+
? Promise<void>
|
|
174
|
+
: void;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export type EventPriority = "discrete" | "continuous" | "default";
|
|
178
|
+
export type RenderPriority = "sync" | "transition" | "continuous";
|
|
179
|
+
|
|
180
|
+
interface TransitionContext {
|
|
181
|
+
syncVersion: number;
|
|
182
|
+
transitionVersion: number;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export interface RootRuntimeOptions {
|
|
186
|
+
identifierPrefix?: string;
|
|
187
|
+
idMode?: "client" | "server";
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export interface RuntimeSnapshot {
|
|
191
|
+
instanceKeys: Set<string>;
|
|
192
|
+
portalContainers: Set<Element>;
|
|
193
|
+
pendingInsertionEffectsLength: number;
|
|
194
|
+
pendingLayoutEffectsLength: number;
|
|
195
|
+
pendingEffectsLength: number;
|
|
196
|
+
pendingProfilerCommitsLength: number;
|
|
197
|
+
profilerBaseDurations: Map<string, number>;
|
|
198
|
+
idCounter: number;
|
|
199
|
+
identifierPrefix: string;
|
|
200
|
+
idMode: "client" | "server";
|
|
201
|
+
strictModeDepth: number;
|
|
202
|
+
profilerFlushDepth: number;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function createRootRuntime(
|
|
206
|
+
rerender: (priority?: RenderPriority) => void,
|
|
207
|
+
options: RootRuntimeOptions = {},
|
|
208
|
+
): RootRuntime {
|
|
209
|
+
return {
|
|
210
|
+
instances: new Map(),
|
|
211
|
+
activeInstanceKeys: undefined,
|
|
212
|
+
activeProfilerPaths: undefined,
|
|
213
|
+
mountedProfilerPaths: new Set(),
|
|
214
|
+
profilerBaseDurations: new Map(),
|
|
215
|
+
pendingProfilerCommits: [],
|
|
216
|
+
pendingInsertionEffects: [],
|
|
217
|
+
pendingLayoutEffects: [],
|
|
218
|
+
pendingEffects: [],
|
|
219
|
+
externalStoreChecks: [],
|
|
220
|
+
portalContainers: new Set(),
|
|
221
|
+
idCounter: 0,
|
|
222
|
+
identifierPrefix: options.identifierPrefix ?? "",
|
|
223
|
+
idMode: options.idMode ?? "client",
|
|
224
|
+
strictModeDepth: 0,
|
|
225
|
+
profilerFlushDepth: 0,
|
|
226
|
+
rerender,
|
|
227
|
+
beginRender() {
|
|
228
|
+
this.activeInstanceKeys = new Set();
|
|
229
|
+
this.activeProfilerPaths = new Set();
|
|
230
|
+
this.pendingProfilerCommits = [];
|
|
231
|
+
this.pendingInsertionEffects = [];
|
|
232
|
+
this.pendingLayoutEffects = [];
|
|
233
|
+
this.pendingEffects = [];
|
|
234
|
+
this.externalStoreChecks = [];
|
|
235
|
+
},
|
|
236
|
+
endRender(committed = true) {
|
|
237
|
+
const profilerCommits = committed ? this.pendingProfilerCommits.splice(0) : [];
|
|
238
|
+
const activeProfilerPaths = this.activeProfilerPaths;
|
|
239
|
+
if (committed) {
|
|
240
|
+
cleanupInactiveInstances(this);
|
|
241
|
+
this.mountedProfilerPaths =
|
|
242
|
+
activeProfilerPaths === undefined ? new Set() : new Set(activeProfilerPaths);
|
|
243
|
+
} else {
|
|
244
|
+
this.pendingProfilerCommits = [];
|
|
245
|
+
}
|
|
246
|
+
this.activeInstanceKeys = undefined;
|
|
247
|
+
this.activeProfilerPaths = undefined;
|
|
248
|
+
currentRuntime = undefined;
|
|
249
|
+
currentInstance = undefined;
|
|
250
|
+
if (committed) {
|
|
251
|
+
flushProfilerCommits(this, profilerCommits);
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
flushEffects() {
|
|
255
|
+
this.profilerFlushDepth += 1;
|
|
256
|
+
try {
|
|
257
|
+
flushPendingEffects(this.pendingInsertionEffects);
|
|
258
|
+
const strictLayoutEffects = flushPendingEffects(this.pendingLayoutEffects);
|
|
259
|
+
const strictEffects = flushPendingEffects(this.pendingEffects);
|
|
260
|
+
const strictReplayEffects = [...strictLayoutEffects, ...strictEffects];
|
|
261
|
+
cleanupStrictEffects(strictReplayEffects);
|
|
262
|
+
replayStrictEffects(strictReplayEffects);
|
|
263
|
+
} finally {
|
|
264
|
+
this.profilerFlushDepth -= 1;
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
dispose() {
|
|
268
|
+
for (const instance of this.instances.values()) {
|
|
269
|
+
cleanupInstance(instance);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
this.pendingLayoutEffects = [];
|
|
273
|
+
this.pendingInsertionEffects = [];
|
|
274
|
+
this.pendingEffects = [];
|
|
275
|
+
this.pendingProfilerCommits = [];
|
|
276
|
+
this.activeProfilerPaths = undefined;
|
|
277
|
+
this.mountedProfilerPaths.clear();
|
|
278
|
+
this.profilerBaseDurations.clear();
|
|
279
|
+
for (const container of this.portalContainers) {
|
|
280
|
+
container.replaceChildren();
|
|
281
|
+
}
|
|
282
|
+
this.portalContainers.clear();
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export function createCacheScope(): CacheScope {
|
|
288
|
+
return {
|
|
289
|
+
functionCaches: new WeakMap(),
|
|
290
|
+
controller: new AbortController(),
|
|
291
|
+
ownerStack: [],
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export function refreshCacheScope(scope: CacheScope): void {
|
|
296
|
+
scope.controller.abort();
|
|
297
|
+
scope.functionCaches = new WeakMap();
|
|
298
|
+
scope.controller = new AbortController();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export function runWithCacheScope<T>(scope: CacheScope, callback: () => T): T {
|
|
302
|
+
const previousScope = currentCacheScope;
|
|
303
|
+
const previousGlobalScope = getGlobalCacheScope();
|
|
304
|
+
currentCacheScope = scope;
|
|
305
|
+
setGlobalCacheScope(scope);
|
|
306
|
+
|
|
307
|
+
try {
|
|
308
|
+
const result = callback();
|
|
309
|
+
|
|
310
|
+
if (isThenable(result)) {
|
|
311
|
+
return Promise.resolve(result).finally(() => {
|
|
312
|
+
currentCacheScope = previousScope;
|
|
313
|
+
setGlobalCacheScope(previousGlobalScope);
|
|
314
|
+
}) as T;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
currentCacheScope = previousScope;
|
|
318
|
+
setGlobalCacheScope(previousGlobalScope);
|
|
319
|
+
return result;
|
|
320
|
+
} catch (error) {
|
|
321
|
+
currentCacheScope = previousScope;
|
|
322
|
+
setGlobalCacheScope(previousGlobalScope);
|
|
323
|
+
throw error;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export function renderWithProfiler<T>(
|
|
328
|
+
runtime: RootRuntime,
|
|
329
|
+
path: string,
|
|
330
|
+
props: Record<string, unknown>,
|
|
331
|
+
render: () => T,
|
|
332
|
+
): T {
|
|
333
|
+
const startTime = getCurrentTime();
|
|
334
|
+
const phase: ProfilerPhase =
|
|
335
|
+
runtime.profilerFlushDepth > 0
|
|
336
|
+
? "nested-update"
|
|
337
|
+
: runtime.mountedProfilerPaths.has(path)
|
|
338
|
+
? "update"
|
|
339
|
+
: "mount";
|
|
340
|
+
|
|
341
|
+
try {
|
|
342
|
+
return render();
|
|
343
|
+
} finally {
|
|
344
|
+
runtime.activeProfilerPaths?.add(path);
|
|
345
|
+
const onRender = props.onRender;
|
|
346
|
+
const id = props.id;
|
|
347
|
+
|
|
348
|
+
if (typeof onRender === "function" && typeof id === "string") {
|
|
349
|
+
const actualDuration = Math.max(0, getCurrentTime() - startTime);
|
|
350
|
+
const baseDuration = Math.max(
|
|
351
|
+
runtime.profilerBaseDurations.get(path) ?? 0,
|
|
352
|
+
actualDuration,
|
|
353
|
+
);
|
|
354
|
+
runtime.profilerBaseDurations.set(path, baseDuration);
|
|
355
|
+
runtime.pendingProfilerCommits.push({
|
|
356
|
+
id,
|
|
357
|
+
phase,
|
|
358
|
+
onRender: onRender as ProfilerOnRender,
|
|
359
|
+
actualDuration,
|
|
360
|
+
baseDuration,
|
|
361
|
+
startTime,
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export function renderWithRootRuntime<T>(
|
|
368
|
+
runtime: RootRuntime,
|
|
369
|
+
path: string,
|
|
370
|
+
render: () => T,
|
|
371
|
+
): T {
|
|
372
|
+
const previousRuntime = currentRuntime;
|
|
373
|
+
const previousInstance = currentInstance;
|
|
374
|
+
const instance = runtime.instances.get(path) ?? {
|
|
375
|
+
hooks: [],
|
|
376
|
+
hookIndex: 0,
|
|
377
|
+
dirty: false,
|
|
378
|
+
devToolsHooks: [],
|
|
379
|
+
devToolsHookTypes: [],
|
|
380
|
+
devToolsHookSuppressionDepth: 0,
|
|
381
|
+
};
|
|
382
|
+
runtime.instances.set(path, instance);
|
|
383
|
+
runtime.activeInstanceKeys?.add(path);
|
|
384
|
+
instance.hookIndex = 0;
|
|
385
|
+
instance.dirty = false;
|
|
386
|
+
instance.devToolsHooks = [];
|
|
387
|
+
instance.devToolsHookTypes = [];
|
|
388
|
+
instance.devToolsHookSuppressionDepth = 0;
|
|
389
|
+
currentRuntime = runtime;
|
|
390
|
+
currentInstance = instance;
|
|
391
|
+
|
|
392
|
+
try {
|
|
393
|
+
return render();
|
|
394
|
+
} finally {
|
|
395
|
+
currentRuntime = previousRuntime;
|
|
396
|
+
currentInstance = previousInstance;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export function getDevToolsHookState(
|
|
401
|
+
runtime: RootRuntime,
|
|
402
|
+
path: string,
|
|
403
|
+
): DevToolsHookState | undefined {
|
|
404
|
+
const instance = runtime.instances.get(path);
|
|
405
|
+
|
|
406
|
+
if (instance === undefined) {
|
|
407
|
+
return undefined;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return {
|
|
411
|
+
hooks: [...instance.devToolsHooks],
|
|
412
|
+
hookTypes: [...instance.devToolsHookTypes],
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export function renderWithStrictMode<T>(
|
|
417
|
+
runtime: RootRuntime,
|
|
418
|
+
render: () => T,
|
|
419
|
+
): T {
|
|
420
|
+
runtime.strictModeDepth += 1;
|
|
421
|
+
|
|
422
|
+
try {
|
|
423
|
+
return render();
|
|
424
|
+
} finally {
|
|
425
|
+
runtime.strictModeDepth -= 1;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export function takeRuntimeSnapshot(runtime: RootRuntime): RuntimeSnapshot {
|
|
430
|
+
return {
|
|
431
|
+
instanceKeys: new Set(runtime.instances.keys()),
|
|
432
|
+
portalContainers: new Set(runtime.portalContainers),
|
|
433
|
+
pendingInsertionEffectsLength: runtime.pendingInsertionEffects.length,
|
|
434
|
+
pendingLayoutEffectsLength: runtime.pendingLayoutEffects.length,
|
|
435
|
+
pendingEffectsLength: runtime.pendingEffects.length,
|
|
436
|
+
pendingProfilerCommitsLength: runtime.pendingProfilerCommits.length,
|
|
437
|
+
profilerBaseDurations: new Map(runtime.profilerBaseDurations),
|
|
438
|
+
idCounter: runtime.idCounter,
|
|
439
|
+
identifierPrefix: runtime.identifierPrefix,
|
|
440
|
+
idMode: runtime.idMode,
|
|
441
|
+
strictModeDepth: runtime.strictModeDepth,
|
|
442
|
+
profilerFlushDepth: runtime.profilerFlushDepth,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export function restoreRuntimeSnapshot(
|
|
447
|
+
runtime: RootRuntime,
|
|
448
|
+
snapshot: RuntimeSnapshot,
|
|
449
|
+
): void {
|
|
450
|
+
runtime.pendingInsertionEffects.length = snapshot.pendingInsertionEffectsLength;
|
|
451
|
+
runtime.pendingLayoutEffects.length = snapshot.pendingLayoutEffectsLength;
|
|
452
|
+
runtime.pendingEffects.length = snapshot.pendingEffectsLength;
|
|
453
|
+
runtime.pendingProfilerCommits.length = snapshot.pendingProfilerCommitsLength;
|
|
454
|
+
runtime.profilerBaseDurations = new Map(snapshot.profilerBaseDurations);
|
|
455
|
+
runtime.idCounter = snapshot.idCounter;
|
|
456
|
+
runtime.identifierPrefix = snapshot.identifierPrefix;
|
|
457
|
+
runtime.idMode = snapshot.idMode;
|
|
458
|
+
runtime.strictModeDepth = snapshot.strictModeDepth;
|
|
459
|
+
runtime.profilerFlushDepth = snapshot.profilerFlushDepth;
|
|
460
|
+
|
|
461
|
+
for (const key of runtime.instances.keys()) {
|
|
462
|
+
if (!snapshot.instanceKeys.has(key)) {
|
|
463
|
+
runtime.instances.delete(key);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
for (const container of runtime.portalContainers) {
|
|
468
|
+
if (!snapshot.portalContainers.has(container)) {
|
|
469
|
+
container.replaceChildren();
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
runtime.portalContainers.clear();
|
|
474
|
+
for (const container of snapshot.portalContainers) {
|
|
475
|
+
runtime.portalContainers.add(container);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
export function useState<T>(
|
|
480
|
+
initial: T | (() => T),
|
|
481
|
+
): [T, (value: T | ((previous: T) => T)) => void] {
|
|
482
|
+
const runtime = requireRuntime();
|
|
483
|
+
const instance = requireInstance();
|
|
484
|
+
const index = instance.hookIndex;
|
|
485
|
+
instance.hookIndex += 1;
|
|
486
|
+
|
|
487
|
+
let slot = instance.hooks[index];
|
|
488
|
+
|
|
489
|
+
if (slot === undefined) {
|
|
490
|
+
slot = {
|
|
491
|
+
kind: "state",
|
|
492
|
+
value: typeof initial === "function" ? (initial as () => T)() : initial,
|
|
493
|
+
};
|
|
494
|
+
instance.hooks[index] = slot;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (slot.kind !== "state") {
|
|
498
|
+
throw new Error("Hook order changed between renders.");
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
const setState = (value: T | ((previous: T) => T)): void => {
|
|
502
|
+
const nextValue =
|
|
503
|
+
typeof value === "function"
|
|
504
|
+
? (value as (previous: T) => T)(slot.value as T)
|
|
505
|
+
: value;
|
|
506
|
+
|
|
507
|
+
if (Object.is(slot.value, nextValue)) {
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
slot.value = nextValue;
|
|
512
|
+
scheduleInstanceUpdate(runtime, instance);
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
recordDevToolsHook("useState", {
|
|
516
|
+
kind: "state",
|
|
517
|
+
value: slot.value,
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
return [slot.value as T, setState];
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
export function useReducer<TState, TAction, TInitial = TState>(
|
|
524
|
+
reducer: (state: TState, action: TAction) => TState,
|
|
525
|
+
initialArg: TInitial,
|
|
526
|
+
init?: (initialArg: TInitial) => TState,
|
|
527
|
+
): [TState, (action: TAction) => void] {
|
|
528
|
+
const [state, setState] = runWithoutDevToolsHookTracking(() =>
|
|
529
|
+
useState<TState>(() =>
|
|
530
|
+
init === undefined ? (initialArg as unknown as TState) : init(initialArg),
|
|
531
|
+
),
|
|
532
|
+
);
|
|
533
|
+
const reducerRef = runWithoutDevToolsHookTracking(() => useRef(reducer));
|
|
534
|
+
const dispatchRef = runWithoutDevToolsHookTracking(() =>
|
|
535
|
+
useRef<((action: TAction) => void) | undefined>(
|
|
536
|
+
undefined,
|
|
537
|
+
)
|
|
538
|
+
);
|
|
539
|
+
reducerRef.current = reducer;
|
|
540
|
+
|
|
541
|
+
if (dispatchRef.current === undefined) {
|
|
542
|
+
dispatchRef.current = (action: TAction): void => {
|
|
543
|
+
setState((previousState) => reducerRef.current(previousState, action));
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
recordDevToolsHook("useReducer", {
|
|
548
|
+
kind: "reducer",
|
|
549
|
+
value: state,
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
return [state, dispatchRef.current];
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
export function useRef<T>(initial: T): { current: T } {
|
|
556
|
+
const instance = requireInstance();
|
|
557
|
+
const index = instance.hookIndex;
|
|
558
|
+
instance.hookIndex += 1;
|
|
559
|
+
|
|
560
|
+
let slot = instance.hooks[index];
|
|
561
|
+
|
|
562
|
+
if (slot === undefined) {
|
|
563
|
+
slot = { kind: "ref", value: { current: initial } };
|
|
564
|
+
instance.hooks[index] = slot;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
if (slot.kind !== "ref") {
|
|
568
|
+
throw new Error("Hook order changed between renders.");
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
recordDevToolsHook("useRef", {
|
|
572
|
+
kind: "ref",
|
|
573
|
+
value: slot.value,
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
return slot.value as { current: T };
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
export function useId(): string {
|
|
580
|
+
const runtime = requireRuntime();
|
|
581
|
+
const idRef = runWithoutDevToolsHookTracking(() =>
|
|
582
|
+
useRef<string | undefined>(undefined)
|
|
583
|
+
);
|
|
584
|
+
|
|
585
|
+
if (idRef.current === undefined) {
|
|
586
|
+
const mode = runtime.idMode === "server" ? "R" : "r";
|
|
587
|
+
idRef.current = `_${runtime.identifierPrefix}${mode}_${runtime.idCounter}_`;
|
|
588
|
+
runtime.idCounter += 1;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
recordDevToolsHook("useId", {
|
|
592
|
+
kind: "id",
|
|
593
|
+
value: idRef.current,
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
return idRef.current;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
export function useImperativeHandle<T>(
|
|
600
|
+
ref: unknown,
|
|
601
|
+
create: () => T,
|
|
602
|
+
deps?: readonly unknown[],
|
|
603
|
+
): void {
|
|
604
|
+
const handle = runWithoutDevToolsHookTracking(() => useMemo(create, deps));
|
|
605
|
+
|
|
606
|
+
runWithoutDevToolsHookTracking(() =>
|
|
607
|
+
useInsertionEffect(() => {
|
|
608
|
+
assignRef(ref, handle);
|
|
609
|
+
return () => {
|
|
610
|
+
assignRef(ref, null);
|
|
611
|
+
};
|
|
612
|
+
}, [ref, handle])
|
|
613
|
+
);
|
|
614
|
+
recordDevToolsHook("useImperativeHandle", deps === undefined
|
|
615
|
+
? { kind: "imperative-handle" }
|
|
616
|
+
: { kind: "imperative-handle", deps });
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
export function useMemo<T>(factory: () => T, deps?: readonly unknown[]): T {
|
|
620
|
+
const instance = requireInstance();
|
|
621
|
+
const index = instance.hookIndex;
|
|
622
|
+
instance.hookIndex += 1;
|
|
623
|
+
|
|
624
|
+
let slot = instance.hooks[index];
|
|
625
|
+
|
|
626
|
+
if (slot !== undefined && slot.kind !== "memo") {
|
|
627
|
+
throw new Error("Hook order changed between renders.");
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
if (
|
|
631
|
+
slot === undefined ||
|
|
632
|
+
deps === undefined ||
|
|
633
|
+
slot.deps === undefined ||
|
|
634
|
+
!areHookInputsEqual(deps, slot.deps)
|
|
635
|
+
) {
|
|
636
|
+
const value = factory();
|
|
637
|
+
slot =
|
|
638
|
+
deps === undefined
|
|
639
|
+
? { kind: "memo", value }
|
|
640
|
+
: { kind: "memo", value, deps };
|
|
641
|
+
instance.hooks[index] = slot;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
recordDevToolsHook("useMemo", slot.deps === undefined
|
|
645
|
+
? { kind: "memo", value: slot.value }
|
|
646
|
+
: { kind: "memo", value: slot.value, deps: slot.deps });
|
|
647
|
+
|
|
648
|
+
return slot.value as T;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function assignRef<T>(ref: unknown, value: T | null): void {
|
|
652
|
+
if (typeof ref === "function") {
|
|
653
|
+
ref(value);
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
if (typeof ref === "object" && ref !== null && "current" in ref) {
|
|
658
|
+
(ref as { current: T | null }).current = value;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
function recordDevToolsHook(type: string, value: DevToolsHookValue): void {
|
|
663
|
+
const instance = currentInstance;
|
|
664
|
+
|
|
665
|
+
if (instance === undefined || instance.devToolsHookSuppressionDepth > 0) {
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
instance.devToolsHookTypes.push(type);
|
|
670
|
+
instance.devToolsHooks.push(value);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
function runWithoutDevToolsHookTracking<T>(callback: () => T): T {
|
|
674
|
+
const instance = requireInstance();
|
|
675
|
+
instance.devToolsHookSuppressionDepth += 1;
|
|
676
|
+
|
|
677
|
+
try {
|
|
678
|
+
return callback();
|
|
679
|
+
} finally {
|
|
680
|
+
instance.devToolsHookSuppressionDepth -= 1;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
export function useCallback<T extends (...args: never[]) => unknown>(
|
|
685
|
+
callback: T,
|
|
686
|
+
deps?: readonly unknown[],
|
|
687
|
+
): T {
|
|
688
|
+
const value = runWithoutDevToolsHookTracking(() => useMemo(() => callback, deps));
|
|
689
|
+
recordDevToolsHook("useCallback", deps === undefined
|
|
690
|
+
? { kind: "callback", value }
|
|
691
|
+
: { kind: "callback", value, deps });
|
|
692
|
+
return value;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
export function useDebugValue(_value: unknown, _format?: (value: unknown) => unknown): void {
|
|
696
|
+
const instance = requireInstance();
|
|
697
|
+
const index = instance.hookIndex;
|
|
698
|
+
instance.hookIndex += 1;
|
|
699
|
+
|
|
700
|
+
const value = _format === undefined ? _value : _format(_value);
|
|
701
|
+
let slot = instance.hooks[index];
|
|
702
|
+
|
|
703
|
+
if (slot !== undefined && slot.kind !== "debug") {
|
|
704
|
+
throw new Error("Hook order changed between renders.");
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
if (slot === undefined) {
|
|
708
|
+
slot = { kind: "debug", value };
|
|
709
|
+
instance.hooks[index] = slot;
|
|
710
|
+
recordDevToolsHook("useDebugValue", {
|
|
711
|
+
kind: "debug",
|
|
712
|
+
value,
|
|
713
|
+
});
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
slot.value = value;
|
|
718
|
+
recordDevToolsHook("useDebugValue", {
|
|
719
|
+
kind: "debug",
|
|
720
|
+
value,
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
export function useEffectEvent<TArgs extends unknown[], TResult>(
|
|
725
|
+
callback: (...args: TArgs) => TResult,
|
|
726
|
+
): (...args: TArgs) => TResult {
|
|
727
|
+
const ref = runWithoutDevToolsHookTracking(() => useRef(callback));
|
|
728
|
+
ref.current = callback;
|
|
729
|
+
|
|
730
|
+
const event = runWithoutDevToolsHookTracking(() =>
|
|
731
|
+
useCallback((...args: TArgs) => ref.current(...args), [])
|
|
732
|
+
);
|
|
733
|
+
recordDevToolsHook("useEffectEvent", {
|
|
734
|
+
kind: "callback",
|
|
735
|
+
value: event,
|
|
736
|
+
deps: [],
|
|
737
|
+
});
|
|
738
|
+
return event;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
export function useEffect(
|
|
742
|
+
callback: EffectCallback,
|
|
743
|
+
deps?: readonly unknown[],
|
|
744
|
+
): void {
|
|
745
|
+
useEffectImpl("normal", callback, deps);
|
|
746
|
+
recordDevToolsHook("useEffect", deps === undefined
|
|
747
|
+
? { kind: "effect", effectKind: "normal" }
|
|
748
|
+
: { kind: "effect", effectKind: "normal", deps });
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
export function useInsertionEffect(
|
|
752
|
+
callback: EffectCallback,
|
|
753
|
+
deps?: readonly unknown[],
|
|
754
|
+
): void {
|
|
755
|
+
useEffectImpl("insertion", callback, deps);
|
|
756
|
+
recordDevToolsHook("useInsertionEffect", deps === undefined
|
|
757
|
+
? { kind: "effect", effectKind: "insertion" }
|
|
758
|
+
: { kind: "effect", effectKind: "insertion", deps });
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
export function useLayoutEffect(
|
|
762
|
+
callback: EffectCallback,
|
|
763
|
+
deps?: readonly unknown[],
|
|
764
|
+
): void {
|
|
765
|
+
useEffectImpl("layout", callback, deps);
|
|
766
|
+
recordDevToolsHook("useLayoutEffect", deps === undefined
|
|
767
|
+
? { kind: "effect", effectKind: "layout" }
|
|
768
|
+
: { kind: "effect", effectKind: "layout", deps });
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
export function useSyncExternalStore<T>(
|
|
772
|
+
subscribe: (listener: () => void) => () => void,
|
|
773
|
+
getSnapshot: () => T,
|
|
774
|
+
getServerSnapshot: () => T = getSnapshot,
|
|
775
|
+
): T {
|
|
776
|
+
const runtime = requireRuntime();
|
|
777
|
+
const instance = requireInstance();
|
|
778
|
+
const index = instance.hookIndex;
|
|
779
|
+
instance.hookIndex += 1;
|
|
780
|
+
let slot = instance.hooks[index];
|
|
781
|
+
|
|
782
|
+
if (slot === undefined) {
|
|
783
|
+
slot = { kind: "store", value: getServerSnapshot() };
|
|
784
|
+
instance.hooks[index] = slot;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
if (slot.kind !== "store") {
|
|
788
|
+
throw new Error("Hook order changed between renders.");
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
const currentSnapshot = getSnapshot();
|
|
792
|
+
|
|
793
|
+
if (!Object.is(slot.value, currentSnapshot)) {
|
|
794
|
+
slot.value = currentSnapshot;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
recordExternalStoreCheck(getSnapshot, currentSnapshot);
|
|
798
|
+
|
|
799
|
+
runWithoutDevToolsHookTracking(() => useEffect(() => {
|
|
800
|
+
const checkForUpdates = (): void => {
|
|
801
|
+
const nextSnapshot = getSnapshot();
|
|
802
|
+
|
|
803
|
+
if (!Object.is(slot.value, nextSnapshot)) {
|
|
804
|
+
slot.value = nextSnapshot;
|
|
805
|
+
runtime.rerender("sync");
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
checkForUpdates();
|
|
810
|
+
return subscribe(checkForUpdates);
|
|
811
|
+
}, [subscribe, getSnapshot]));
|
|
812
|
+
|
|
813
|
+
recordDevToolsHook("useSyncExternalStore", {
|
|
814
|
+
kind: "store",
|
|
815
|
+
value: slot.value,
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
return slot.value as T;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
export function useActionState<TState, TPayload>(
|
|
822
|
+
action: (previousState: TState, payload: TPayload) => TState | Promise<TState>,
|
|
823
|
+
initialState: TState,
|
|
824
|
+
): [TState, (payload: TPayload) => void, boolean] {
|
|
825
|
+
const runtime = requireRuntime();
|
|
826
|
+
const instance = requireInstance();
|
|
827
|
+
const index = instance.hookIndex;
|
|
828
|
+
instance.hookIndex += 1;
|
|
829
|
+
let slot = instance.hooks[index];
|
|
830
|
+
|
|
831
|
+
if (slot !== undefined && slot.kind !== "action-state") {
|
|
832
|
+
throw new Error("Hook order changed between renders.");
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
if (slot === undefined) {
|
|
836
|
+
slot = {
|
|
837
|
+
kind: "action-state",
|
|
838
|
+
state: initialState,
|
|
839
|
+
pendingCount: 0,
|
|
840
|
+
action: action as (previousState: unknown, payload: unknown) => unknown,
|
|
841
|
+
};
|
|
842
|
+
instance.hooks[index] = slot;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
if ("error" in slot) {
|
|
846
|
+
throw slot.error;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
slot.action = action as (previousState: unknown, payload: unknown) => unknown;
|
|
850
|
+
|
|
851
|
+
if (slot.dispatch === undefined) {
|
|
852
|
+
slot.dispatch = (payload: unknown): void => {
|
|
853
|
+
runActionStateDispatch(slot, runtime, instance, payload);
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
recordDevToolsHook("useActionState", {
|
|
858
|
+
kind: "state",
|
|
859
|
+
value: slot.state,
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
return [
|
|
863
|
+
slot.state as TState,
|
|
864
|
+
slot.dispatch as (payload: TPayload) => void,
|
|
865
|
+
slot.pendingCount > 0,
|
|
866
|
+
];
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
export function useOptimistic<TState, TPayload>(
|
|
870
|
+
state: TState,
|
|
871
|
+
update?: (state: TState, payload: TPayload) => TState,
|
|
872
|
+
): [TState, (payload: TPayload) => void] {
|
|
873
|
+
const runtime = requireRuntime();
|
|
874
|
+
const instance = requireInstance();
|
|
875
|
+
const index = instance.hookIndex;
|
|
876
|
+
instance.hookIndex += 1;
|
|
877
|
+
let slot = instance.hooks[index];
|
|
878
|
+
const updateFn =
|
|
879
|
+
update === undefined
|
|
880
|
+
? (_current: unknown, payload: unknown) => payload
|
|
881
|
+
: update as (state: unknown, payload: unknown) => unknown;
|
|
882
|
+
|
|
883
|
+
if (slot !== undefined && slot.kind !== "optimistic") {
|
|
884
|
+
throw new Error("Hook order changed between renders.");
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
if (slot === undefined) {
|
|
888
|
+
slot = {
|
|
889
|
+
kind: "optimistic",
|
|
890
|
+
baseState: state,
|
|
891
|
+
optimisticState: state,
|
|
892
|
+
update: updateFn,
|
|
893
|
+
};
|
|
894
|
+
instance.hooks[index] = slot;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
slot.update = updateFn;
|
|
898
|
+
|
|
899
|
+
if (!Object.is(slot.baseState, state)) {
|
|
900
|
+
slot.baseState = state;
|
|
901
|
+
slot.optimisticState = state;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
if (slot.dispatch === undefined) {
|
|
905
|
+
slot.dispatch = (payload: unknown): void => {
|
|
906
|
+
slot.optimisticState = slot.update(slot.optimisticState, payload);
|
|
907
|
+
scheduleInstanceUpdate(runtime, instance);
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
recordDevToolsHook("useOptimistic", {
|
|
912
|
+
kind: "state",
|
|
913
|
+
value: slot.optimisticState,
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
return [slot.optimisticState as TState, slot.dispatch as (payload: TPayload) => void];
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
export function use<T>(usable: PromiseLike<T> | unknown): T {
|
|
920
|
+
if (isReactCompatContext(usable)) {
|
|
921
|
+
return useContext(usable) as T;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
if (isThenable(usable)) {
|
|
925
|
+
return readThenable(usable as PromiseLike<T>);
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
return usable as T;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
export function cache<TArgs extends unknown[], TResult>(
|
|
932
|
+
callback: (...args: TArgs) => TResult,
|
|
933
|
+
): (...args: TArgs) => TResult {
|
|
934
|
+
return (...args) => {
|
|
935
|
+
const scope = getCurrentCacheScope();
|
|
936
|
+
|
|
937
|
+
if (scope === undefined) {
|
|
938
|
+
return callback(...args);
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
const leaf = getCacheLeaf(scope, callback, args);
|
|
942
|
+
|
|
943
|
+
if (leaf.status === "fulfilled") {
|
|
944
|
+
return leaf.value as TResult;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
if (leaf.status === "rejected") {
|
|
948
|
+
throw leaf.reason;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
try {
|
|
952
|
+
const value = callback(...args);
|
|
953
|
+
leaf.status = "fulfilled";
|
|
954
|
+
leaf.value = value;
|
|
955
|
+
return value;
|
|
956
|
+
} catch (error) {
|
|
957
|
+
leaf.status = "rejected";
|
|
958
|
+
leaf.reason = error;
|
|
959
|
+
throw error;
|
|
960
|
+
}
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
export function cacheSignal(): AbortSignal | null {
|
|
965
|
+
return getCurrentCacheScope()?.controller.signal ?? null;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
export function captureOwnerStack(): string | null {
|
|
969
|
+
const stack = getCurrentCacheScope()?.ownerStack ?? emptyCacheOwnerStack;
|
|
970
|
+
return stack.length === 0 ? null : stack.join("\n");
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
export function unstable_useCacheRefresh(): () => void {
|
|
974
|
+
return useCallback(() => undefined, []);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
export function hasStableExternalStores(
|
|
978
|
+
runtime: RootRuntime,
|
|
979
|
+
): boolean {
|
|
980
|
+
return runtime.externalStoreChecks.every((check) =>
|
|
981
|
+
Object.is(check.getSnapshot(), check.value),
|
|
982
|
+
);
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
export function renderToString<TProps>(
|
|
986
|
+
component: (props: TProps) => ReactCompatNode,
|
|
987
|
+
props?: TProps,
|
|
988
|
+
options: RootRuntimeOptions = {},
|
|
989
|
+
): string {
|
|
990
|
+
const runtime = createRootRuntime(() => undefined, {
|
|
991
|
+
...options,
|
|
992
|
+
idMode: "server",
|
|
993
|
+
});
|
|
994
|
+
|
|
995
|
+
return runWithCacheScope(createCacheScope(), () => {
|
|
996
|
+
try {
|
|
997
|
+
const rendered = renderWithRootRuntime(runtime, "0", () => component(props as TProps));
|
|
998
|
+
return typeof rendered === "string"
|
|
999
|
+
? rendered
|
|
1000
|
+
: renderNodeToString(rendered, runtime, "0");
|
|
1001
|
+
} finally {
|
|
1002
|
+
runtime.dispose();
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
function renderNodeToString(
|
|
1008
|
+
node: ReactCompatNode,
|
|
1009
|
+
runtime: RootRuntime,
|
|
1010
|
+
path: string,
|
|
1011
|
+
): string {
|
|
1012
|
+
if (node === null || node === undefined || typeof node === "boolean") {
|
|
1013
|
+
return "";
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
if (typeof node === "string" || typeof node === "number") {
|
|
1017
|
+
return escapeHtml(node);
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
if (Array.isArray(node)) {
|
|
1021
|
+
return node.map((child, index) => renderNodeToString(child, runtime, `${path}.${index}`)).join("");
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
if (!isReactCompatElement(node)) {
|
|
1025
|
+
return "";
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
return renderElementToString(node, runtime, path);
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
function renderElementToString(
|
|
1032
|
+
element: ReactCompatElement,
|
|
1033
|
+
runtime: RootRuntime,
|
|
1034
|
+
path: string,
|
|
1035
|
+
): string {
|
|
1036
|
+
if (typeof element.type === "string") {
|
|
1037
|
+
if (element.type === "textarea") {
|
|
1038
|
+
return renderTextareaToString(element, runtime, path);
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
if (element.type === "select") {
|
|
1042
|
+
return renderSelectToString(element, runtime, path);
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
const attributes = element.type === "input"
|
|
1046
|
+
? renderInputAttributesToString(element.props)
|
|
1047
|
+
: Object.entries(element.props)
|
|
1048
|
+
.map(([name, value]) => renderHtmlAttribute(name, value))
|
|
1049
|
+
.filter((attribute) => attribute !== "")
|
|
1050
|
+
.join("");
|
|
1051
|
+
if (voidHtmlElements.has(element.type)) {
|
|
1052
|
+
return `<${element.type}${attributes}/>`;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
return `<${element.type}${attributes}>${renderNodeToString(element.props.children, runtime, `${path}.children`)}</${element.type}>`;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
if (element.type === Fragment) {
|
|
1059
|
+
return renderNodeToString(element.props.children, runtime, `${path}.fragment`);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
if (element.type === Activity) {
|
|
1063
|
+
if ((element.props as { mode?: unknown }).mode === "hidden") {
|
|
1064
|
+
return "";
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
return `<!--&-->${renderNodeToString(element.props.children, runtime, `${path}.activity`)}<!--/&-->`;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
if (element.type === Profiler) {
|
|
1071
|
+
return renderNodeToString(element.props.children, runtime, `${path}.profiler`);
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
if (isReactCompatProvider(element.type)) {
|
|
1075
|
+
return renderWithContextProvider(
|
|
1076
|
+
element.type,
|
|
1077
|
+
(element.props as { value?: unknown }).value,
|
|
1078
|
+
() => renderNodeToString(element.props.children, runtime, `${path}.provider`),
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
if (isReactCompatConsumer(element.type)) {
|
|
1083
|
+
const children = element.props.children;
|
|
1084
|
+
|
|
1085
|
+
if (typeof children === "function") {
|
|
1086
|
+
return renderNodeToString(
|
|
1087
|
+
(children as (value: unknown) => ReactCompatNode)(useContext(element.type.context)),
|
|
1088
|
+
runtime,
|
|
1089
|
+
`${path}.consumer`,
|
|
1090
|
+
);
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
return "";
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
if (isForwardRefType(element.type)) {
|
|
1097
|
+
const forwardRefType = element.type;
|
|
1098
|
+
return renderNodeToString(
|
|
1099
|
+
renderWithRootRuntime(runtime, `${path}.forwardRef`, () =>
|
|
1100
|
+
forwardRefType.render(element.props, element.ref),
|
|
1101
|
+
),
|
|
1102
|
+
runtime,
|
|
1103
|
+
`${path}.forwardRef`,
|
|
1104
|
+
);
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
if (isMemoType(element.type)) {
|
|
1108
|
+
return renderNodeToString(
|
|
1109
|
+
{
|
|
1110
|
+
...element,
|
|
1111
|
+
type: element.type.type,
|
|
1112
|
+
},
|
|
1113
|
+
runtime,
|
|
1114
|
+
`${path}.memo`,
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
if (isClassComponentType(element.type)) {
|
|
1119
|
+
const instance = new element.type(element.props);
|
|
1120
|
+
return renderNodeToString(
|
|
1121
|
+
renderWithRootRuntime(runtime, path, () => instance.render()),
|
|
1122
|
+
runtime,
|
|
1123
|
+
path,
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
if (typeof element.type === "function") {
|
|
1128
|
+
const component = element.type as (props: typeof element.props) => ReactCompatNode;
|
|
1129
|
+
return renderNodeToString(
|
|
1130
|
+
renderWithRootRuntime(runtime, path, () => component(element.props)),
|
|
1131
|
+
runtime,
|
|
1132
|
+
path,
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
return "";
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
function isClassComponentType(
|
|
1140
|
+
value: unknown,
|
|
1141
|
+
): value is new (props: Record<string, unknown>) => { render(): ReactCompatNode } {
|
|
1142
|
+
return (
|
|
1143
|
+
typeof value === "function" &&
|
|
1144
|
+
typeof (value as { prototype?: { render?: unknown } }).prototype?.render === "function"
|
|
1145
|
+
);
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
function renderTextareaToString(
|
|
1149
|
+
element: ReactCompatElement,
|
|
1150
|
+
runtime: RootRuntime,
|
|
1151
|
+
path: string,
|
|
1152
|
+
): string {
|
|
1153
|
+
const value =
|
|
1154
|
+
(element.props as { value?: unknown; defaultValue?: unknown }).value ??
|
|
1155
|
+
(element.props as { value?: unknown; defaultValue?: unknown }).defaultValue ??
|
|
1156
|
+
element.props.children;
|
|
1157
|
+
const attributes = Object.entries(element.props)
|
|
1158
|
+
.filter(([name]) => name !== "value" && name !== "defaultValue")
|
|
1159
|
+
.map(([name, child]) => renderHtmlAttribute(name, child))
|
|
1160
|
+
.filter((attribute) => attribute !== "")
|
|
1161
|
+
.join("");
|
|
1162
|
+
|
|
1163
|
+
return `<textarea${attributes}>${renderNodeToString(value as ReactCompatNode, runtime, `${path}.textarea`)}</textarea>`;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
function renderSelectToString(
|
|
1167
|
+
element: ReactCompatElement,
|
|
1168
|
+
runtime: RootRuntime,
|
|
1169
|
+
path: string,
|
|
1170
|
+
): string {
|
|
1171
|
+
const selectedValue =
|
|
1172
|
+
(element.props as { value?: unknown; defaultValue?: unknown }).value ??
|
|
1173
|
+
(element.props as { value?: unknown; defaultValue?: unknown }).defaultValue;
|
|
1174
|
+
const attributes = Object.entries(element.props)
|
|
1175
|
+
.filter(([name]) => name !== "value" && name !== "defaultValue")
|
|
1176
|
+
.map(([name, child]) => renderHtmlAttribute(name, child))
|
|
1177
|
+
.filter((attribute) => attribute !== "")
|
|
1178
|
+
.join("");
|
|
1179
|
+
|
|
1180
|
+
return `<select${attributes}>${renderSelectChildrenToString(
|
|
1181
|
+
element.props.children,
|
|
1182
|
+
selectedValue,
|
|
1183
|
+
runtime,
|
|
1184
|
+
`${path}.select`,
|
|
1185
|
+
)}</select>`;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
function renderSelectChildrenToString(
|
|
1189
|
+
children: ReactCompatNode,
|
|
1190
|
+
selectedValue: unknown,
|
|
1191
|
+
runtime: RootRuntime,
|
|
1192
|
+
path: string,
|
|
1193
|
+
): string {
|
|
1194
|
+
const childArray = Array.isArray(children) ? children : [children];
|
|
1195
|
+
|
|
1196
|
+
return childArray.map((child, index) => {
|
|
1197
|
+
if (!isReactCompatElement(child) || child.type !== "option") {
|
|
1198
|
+
return renderNodeToString(child, runtime, `${path}.${index}`);
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
const optionValue =
|
|
1202
|
+
(child.props as { value?: unknown }).value ?? child.props.children;
|
|
1203
|
+
const selected =
|
|
1204
|
+
selectedValue !== undefined && String(optionValue) === String(selectedValue);
|
|
1205
|
+
const props = selected
|
|
1206
|
+
? { ...child.props, selected: true }
|
|
1207
|
+
: child.props;
|
|
1208
|
+
|
|
1209
|
+
return renderElementToString({ ...child, props }, runtime, `${path}.${index}`);
|
|
1210
|
+
}).join("");
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
function renderInputAttributesToString(props: Record<string, unknown>): string {
|
|
1214
|
+
const hasValue = props.value !== undefined;
|
|
1215
|
+
const hasChecked = props.checked !== undefined;
|
|
1216
|
+
|
|
1217
|
+
return Object.entries(props)
|
|
1218
|
+
.filter(([name]) =>
|
|
1219
|
+
!((name === "defaultValue" && hasValue) || (name === "defaultChecked" && hasChecked))
|
|
1220
|
+
)
|
|
1221
|
+
.sort(([leftName], [rightName]) =>
|
|
1222
|
+
Number(isInputValueAttribute(leftName)) - Number(isInputValueAttribute(rightName))
|
|
1223
|
+
)
|
|
1224
|
+
.map(([name, value]) => renderHtmlAttribute(toInputHtmlAttributeName(name), value))
|
|
1225
|
+
.filter((attribute) => attribute !== "")
|
|
1226
|
+
.join("");
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
function renderHtmlAttribute(name: string, value: unknown): string {
|
|
1230
|
+
if (
|
|
1231
|
+
name === "children" ||
|
|
1232
|
+
name === "key" ||
|
|
1233
|
+
name === "ref" ||
|
|
1234
|
+
/^on[A-Z]/.test(name) ||
|
|
1235
|
+
value === null ||
|
|
1236
|
+
value === undefined ||
|
|
1237
|
+
value === false ||
|
|
1238
|
+
typeof value === "function"
|
|
1239
|
+
) {
|
|
1240
|
+
return "";
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
if (name === "style") {
|
|
1244
|
+
const style = renderStyleAttribute(value);
|
|
1245
|
+
return style === "" ? "" : ` style="${escapeHtml(style)}"`;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
const attributeName = toHtmlAttributeName(name);
|
|
1249
|
+
if (isDangerousHtmlAttribute(attributeName)) {
|
|
1250
|
+
return isDangerousHtmlOptIn(value)
|
|
1251
|
+
? ` ${attributeName}="${escapeHtml(value.__html)}"`
|
|
1252
|
+
: "";
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
if (typeof value === "object") {
|
|
1256
|
+
return "";
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
if (value === true) {
|
|
1260
|
+
return ` ${attributeName}=""`;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
return ` ${attributeName}="${escapeHtml(value)}"`;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
function isInputValueAttribute(name: string): boolean {
|
|
1267
|
+
return name === "value" || name === "defaultValue";
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
function toInputHtmlAttributeName(name: string): string {
|
|
1271
|
+
if (name === "defaultValue") {
|
|
1272
|
+
return "value";
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
if (name === "defaultChecked") {
|
|
1276
|
+
return "checked";
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
return name;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
function toHtmlAttributeName(name: string): string {
|
|
1283
|
+
return HTML_ATTRIBUTE_ALIASES[name] ?? name;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
const HTML_ATTRIBUTE_ALIASES: Record<string, string> = {
|
|
1287
|
+
acceptCharset: "accept-charset",
|
|
1288
|
+
autoFocus: "autofocus",
|
|
1289
|
+
autoPlay: "autoplay",
|
|
1290
|
+
charSet: "charset",
|
|
1291
|
+
className: "class",
|
|
1292
|
+
colSpan: "colspan",
|
|
1293
|
+
contentEditable: "contenteditable",
|
|
1294
|
+
crossOrigin: "crossorigin",
|
|
1295
|
+
encType: "enctype",
|
|
1296
|
+
formAction: "formaction",
|
|
1297
|
+
frameBorder: "frameborder",
|
|
1298
|
+
htmlFor: "for",
|
|
1299
|
+
httpEquiv: "http-equiv",
|
|
1300
|
+
maxLength: "maxlength",
|
|
1301
|
+
minLength: "minlength",
|
|
1302
|
+
noValidate: "novalidate",
|
|
1303
|
+
playsInline: "playsinline",
|
|
1304
|
+
readOnly: "readOnly",
|
|
1305
|
+
rowSpan: "rowspan",
|
|
1306
|
+
spellCheck: "spellcheck",
|
|
1307
|
+
srcDoc: "srcdoc",
|
|
1308
|
+
srcSet: "srcset",
|
|
1309
|
+
tabIndex: "tabindex",
|
|
1310
|
+
useMap: "usemap",
|
|
1311
|
+
};
|
|
1312
|
+
|
|
1313
|
+
function renderStyleAttribute(value: unknown): string {
|
|
1314
|
+
if (typeof value !== "object" || value === null) {
|
|
1315
|
+
return "";
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
return Object.entries(value)
|
|
1319
|
+
.filter(([, propertyValue]) =>
|
|
1320
|
+
propertyValue !== null &&
|
|
1321
|
+
propertyValue !== undefined &&
|
|
1322
|
+
typeof propertyValue !== "boolean" &&
|
|
1323
|
+
propertyValue !== "",
|
|
1324
|
+
)
|
|
1325
|
+
.map(([name, propertyValue]) =>
|
|
1326
|
+
`${toKebabCase(name)}:${renderCssValue(name, propertyValue)}`,
|
|
1327
|
+
)
|
|
1328
|
+
.join(";");
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
function renderCssValue(name: string, value: unknown): string {
|
|
1332
|
+
if (typeof value !== "number" || value === 0 || isUnitlessCssProperty(name)) {
|
|
1333
|
+
return String(value);
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
return `${value}px`;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
function toKebabCase(value: string): string {
|
|
1340
|
+
return value.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
function isUnitlessCssProperty(name: string): boolean {
|
|
1344
|
+
return (
|
|
1345
|
+
name === "flex" ||
|
|
1346
|
+
name === "fontWeight" ||
|
|
1347
|
+
name === "lineHeight" ||
|
|
1348
|
+
name === "opacity" ||
|
|
1349
|
+
name === "order" ||
|
|
1350
|
+
name === "zIndex" ||
|
|
1351
|
+
name === "zoom"
|
|
1352
|
+
);
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
const voidHtmlElements = new Set([
|
|
1356
|
+
"area",
|
|
1357
|
+
"base",
|
|
1358
|
+
"br",
|
|
1359
|
+
"col",
|
|
1360
|
+
"embed",
|
|
1361
|
+
"hr",
|
|
1362
|
+
"img",
|
|
1363
|
+
"input",
|
|
1364
|
+
"link",
|
|
1365
|
+
"meta",
|
|
1366
|
+
"param",
|
|
1367
|
+
"source",
|
|
1368
|
+
"track",
|
|
1369
|
+
"wbr",
|
|
1370
|
+
]);
|
|
1371
|
+
|
|
1372
|
+
function isForwardRefType(value: unknown): value is ForwardRefType {
|
|
1373
|
+
return (
|
|
1374
|
+
typeof value === "object" &&
|
|
1375
|
+
value !== null &&
|
|
1376
|
+
(value as { $$typeof?: unknown }).$$typeof === FORWARD_REF_TYPE
|
|
1377
|
+
);
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
function isMemoType(value: unknown): value is MemoType {
|
|
1381
|
+
return (
|
|
1382
|
+
typeof value === "object" &&
|
|
1383
|
+
value !== null &&
|
|
1384
|
+
(value as { $$typeof?: unknown }).$$typeof === MEMO_TYPE
|
|
1385
|
+
);
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
function readThenable<T>(thenable: PromiseLike<T>): T {
|
|
1389
|
+
const record = thenable as PromiseLike<T> & {
|
|
1390
|
+
status?: "pending" | "fulfilled" | "rejected";
|
|
1391
|
+
value?: T;
|
|
1392
|
+
reason?: unknown;
|
|
1393
|
+
};
|
|
1394
|
+
|
|
1395
|
+
if (record.status === "fulfilled") {
|
|
1396
|
+
return record.value as T;
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
if (record.status === "rejected") {
|
|
1400
|
+
throw record.reason;
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
if (record.status === undefined) {
|
|
1404
|
+
record.status = "pending";
|
|
1405
|
+
thenable.then(
|
|
1406
|
+
(value) => {
|
|
1407
|
+
if (record.status === "pending") {
|
|
1408
|
+
record.status = "fulfilled";
|
|
1409
|
+
record.value = value;
|
|
1410
|
+
}
|
|
1411
|
+
},
|
|
1412
|
+
(reason) => {
|
|
1413
|
+
if (record.status === "pending") {
|
|
1414
|
+
record.status = "rejected";
|
|
1415
|
+
record.reason = reason;
|
|
1416
|
+
}
|
|
1417
|
+
},
|
|
1418
|
+
);
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
throw thenable;
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
export type TransitionScope = () => void;
|
|
1425
|
+
export type StartTransition = (scope: TransitionScope) => void;
|
|
1426
|
+
|
|
1427
|
+
export function startTransition(scope: TransitionScope): void {
|
|
1428
|
+
const context = {
|
|
1429
|
+
syncVersion,
|
|
1430
|
+
transitionVersion: ++transitionVersion,
|
|
1431
|
+
};
|
|
1432
|
+
scheduleCallback("low", () => {
|
|
1433
|
+
if (!isTransitionContextCurrent(context)) {
|
|
1434
|
+
return;
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
runTransitionScope(scope, context);
|
|
1438
|
+
});
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
export function runWithEventPriority<T>(
|
|
1442
|
+
priority: EventPriority,
|
|
1443
|
+
callback: () => T,
|
|
1444
|
+
): T {
|
|
1445
|
+
const previousPriority = currentEventPriority;
|
|
1446
|
+
currentEventPriority = priority;
|
|
1447
|
+
eventBatchDepth += 1;
|
|
1448
|
+
|
|
1449
|
+
try {
|
|
1450
|
+
return callback();
|
|
1451
|
+
} finally {
|
|
1452
|
+
eventBatchDepth -= 1;
|
|
1453
|
+
currentEventPriority = previousPriority;
|
|
1454
|
+
|
|
1455
|
+
if (eventBatchDepth === 0) {
|
|
1456
|
+
flushEventRerendersForPriority(priority);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
export function flushSyncUpdates<T>(callback: () => T): T {
|
|
1462
|
+
const previousEventBatchDepth = eventBatchDepth;
|
|
1463
|
+
const previousEventPriority = currentEventPriority;
|
|
1464
|
+
eventBatchDepth = 0;
|
|
1465
|
+
currentEventPriority = "discrete";
|
|
1466
|
+
|
|
1467
|
+
try {
|
|
1468
|
+
const value = callback();
|
|
1469
|
+
flushQueuedEventRerenders();
|
|
1470
|
+
return value;
|
|
1471
|
+
} finally {
|
|
1472
|
+
eventBatchDepth = previousEventBatchDepth;
|
|
1473
|
+
currentEventPriority = previousEventPriority;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
export function useTransition(): [boolean, StartTransition] {
|
|
1478
|
+
const [pending, setPending] = runWithoutDevToolsHookTracking(() => useState(false));
|
|
1479
|
+
const startTransitionWithPending: StartTransition = (scope) => {
|
|
1480
|
+
setPending(true);
|
|
1481
|
+
const context = {
|
|
1482
|
+
syncVersion,
|
|
1483
|
+
transitionVersion: ++transitionVersion,
|
|
1484
|
+
};
|
|
1485
|
+
scheduleCallback("low", () => {
|
|
1486
|
+
if (!isTransitionContextCurrent(context)) {
|
|
1487
|
+
setPending(false);
|
|
1488
|
+
return;
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
runTransitionScope(() => {
|
|
1492
|
+
scope();
|
|
1493
|
+
setPending(false);
|
|
1494
|
+
}, context);
|
|
1495
|
+
});
|
|
1496
|
+
};
|
|
1497
|
+
|
|
1498
|
+
recordDevToolsHook("useTransition", {
|
|
1499
|
+
kind: "transition",
|
|
1500
|
+
value: pending,
|
|
1501
|
+
});
|
|
1502
|
+
|
|
1503
|
+
return [
|
|
1504
|
+
pending,
|
|
1505
|
+
startTransitionWithPending,
|
|
1506
|
+
];
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
export function useDeferredValue<T>(value: T): T {
|
|
1510
|
+
const [deferredValue, setDeferredValue] = runWithoutDevToolsHookTracking(() =>
|
|
1511
|
+
useState(value)
|
|
1512
|
+
);
|
|
1513
|
+
|
|
1514
|
+
runWithoutDevToolsHookTracking(() =>
|
|
1515
|
+
useEffect(() => {
|
|
1516
|
+
if (Object.is(deferredValue, value)) {
|
|
1517
|
+
return;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
startTransition(() => {
|
|
1521
|
+
setDeferredValue(value);
|
|
1522
|
+
});
|
|
1523
|
+
}, [value, deferredValue])
|
|
1524
|
+
);
|
|
1525
|
+
|
|
1526
|
+
const currentValue = Object.is(deferredValue, value) ? value : deferredValue;
|
|
1527
|
+
|
|
1528
|
+
recordDevToolsHook("useDeferredValue", {
|
|
1529
|
+
kind: "deferred",
|
|
1530
|
+
value: currentValue,
|
|
1531
|
+
});
|
|
1532
|
+
|
|
1533
|
+
return currentValue;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
function runTransitionScope(
|
|
1537
|
+
scope: TransitionScope,
|
|
1538
|
+
context: TransitionContext,
|
|
1539
|
+
): void {
|
|
1540
|
+
transitionDepth += 1;
|
|
1541
|
+
const previousContext = currentTransitionContext;
|
|
1542
|
+
currentTransitionContext = context;
|
|
1543
|
+
|
|
1544
|
+
try {
|
|
1545
|
+
scope();
|
|
1546
|
+
} finally {
|
|
1547
|
+
currentTransitionContext = previousContext;
|
|
1548
|
+
transitionDepth -= 1;
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
function queueTransitionRerender(
|
|
1553
|
+
runtime: RootRuntime,
|
|
1554
|
+
context: TransitionContext,
|
|
1555
|
+
): void {
|
|
1556
|
+
queuedTransitionRerenders.set(runtime, context);
|
|
1557
|
+
|
|
1558
|
+
if (transitionRerenderScheduled) {
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
transitionRerenderScheduled = true;
|
|
1563
|
+
scheduleCallback("low", flushQueuedTransitionRerenders);
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
function queueEventRerender(runtime: RootRuntime): void {
|
|
1567
|
+
queuedEventRerenders.add(runtime);
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
function flushEventRerendersForPriority(priority: EventPriority): void {
|
|
1571
|
+
if (priority === "discrete") {
|
|
1572
|
+
flushQueuedEventRerenders("sync");
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
if (eventRerenderScheduled || queuedEventRerenders.size === 0) {
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
eventRerenderScheduled = true;
|
|
1581
|
+
scheduleCallback(priority === "continuous" ? "normal" : "low", () => {
|
|
1582
|
+
eventRerenderScheduled = false;
|
|
1583
|
+
flushQueuedEventRerenders(
|
|
1584
|
+
priority === "continuous" ? "continuous" : "sync",
|
|
1585
|
+
);
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
function flushQueuedEventRerenders(priority: RenderPriority = "sync"): void {
|
|
1590
|
+
const runtimes = Array.from(queuedEventRerenders);
|
|
1591
|
+
queuedEventRerenders.clear();
|
|
1592
|
+
|
|
1593
|
+
for (const runtime of runtimes) {
|
|
1594
|
+
runtime.rerender(priority);
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
function flushQueuedTransitionRerenders(): void {
|
|
1599
|
+
transitionRerenderScheduled = false;
|
|
1600
|
+
const entries = Array.from(queuedTransitionRerenders.entries());
|
|
1601
|
+
queuedTransitionRerenders.clear();
|
|
1602
|
+
|
|
1603
|
+
for (const [runtime, context] of entries) {
|
|
1604
|
+
if (isTransitionContextCurrent(context)) {
|
|
1605
|
+
runtime.rerender("transition");
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
function isTransitionContextCurrent(context: TransitionContext): boolean {
|
|
1611
|
+
return (
|
|
1612
|
+
context.syncVersion === syncVersion &&
|
|
1613
|
+
context.transitionVersion === transitionVersion
|
|
1614
|
+
);
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
function useEffectImpl(
|
|
1618
|
+
effectKind: "insertion" | "layout" | "normal",
|
|
1619
|
+
callback: EffectCallback,
|
|
1620
|
+
deps?: readonly unknown[],
|
|
1621
|
+
): void {
|
|
1622
|
+
const runtime = requireRuntime();
|
|
1623
|
+
const instance = requireInstance();
|
|
1624
|
+
const index = instance.hookIndex;
|
|
1625
|
+
instance.hookIndex += 1;
|
|
1626
|
+
|
|
1627
|
+
let slot = instance.hooks[index];
|
|
1628
|
+
|
|
1629
|
+
if (slot !== undefined && slot.kind !== "effect") {
|
|
1630
|
+
throw new Error("Hook order changed between renders.");
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
const shouldRun =
|
|
1634
|
+
slot === undefined ||
|
|
1635
|
+
deps === undefined ||
|
|
1636
|
+
slot.deps === undefined ||
|
|
1637
|
+
!areHookInputsEqual(deps, slot.deps);
|
|
1638
|
+
|
|
1639
|
+
if (slot === undefined) {
|
|
1640
|
+
slot =
|
|
1641
|
+
deps === undefined
|
|
1642
|
+
? { kind: "effect", effectKind, callback }
|
|
1643
|
+
: { kind: "effect", effectKind, callback, deps };
|
|
1644
|
+
instance.hooks[index] = slot;
|
|
1645
|
+
} else {
|
|
1646
|
+
slot.effectKind = effectKind;
|
|
1647
|
+
slot.callback = callback;
|
|
1648
|
+
slot.disposed = false;
|
|
1649
|
+
|
|
1650
|
+
if (deps === undefined) {
|
|
1651
|
+
delete slot.deps;
|
|
1652
|
+
} else {
|
|
1653
|
+
slot.deps = deps;
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
slot.strictReplay =
|
|
1658
|
+
runtime.strictModeDepth > 0 && effectKind !== "insertion";
|
|
1659
|
+
|
|
1660
|
+
if (shouldRun) {
|
|
1661
|
+
const queue =
|
|
1662
|
+
effectKind === "insertion"
|
|
1663
|
+
? runtime.pendingInsertionEffects
|
|
1664
|
+
: effectKind === "layout"
|
|
1665
|
+
? runtime.pendingLayoutEffects
|
|
1666
|
+
: runtime.pendingEffects;
|
|
1667
|
+
queue.push({ slot });
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
function recordExternalStoreCheck<T>(
|
|
1672
|
+
getSnapshot: () => T,
|
|
1673
|
+
value: T,
|
|
1674
|
+
): void {
|
|
1675
|
+
currentRuntime?.externalStoreChecks.push({ getSnapshot, value });
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
function flushPendingEffects(queue: PendingEffect[]): PendingEffect[] {
|
|
1679
|
+
const pending = queue.splice(0);
|
|
1680
|
+
const strictReplay: PendingEffect[] = [];
|
|
1681
|
+
|
|
1682
|
+
for (const { slot } of pending) {
|
|
1683
|
+
if (slot.disposed === true) {
|
|
1684
|
+
continue;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
slot.cleanup?.();
|
|
1688
|
+
const shouldReplay = slot.strictReplay === true && slot.cleanup === undefined;
|
|
1689
|
+
const cleanup = slot.callback();
|
|
1690
|
+
|
|
1691
|
+
if (typeof cleanup === "function") {
|
|
1692
|
+
slot.cleanup = cleanup;
|
|
1693
|
+
} else {
|
|
1694
|
+
delete slot.cleanup;
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
if (shouldReplay) {
|
|
1698
|
+
strictReplay.push({ slot });
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
return strictReplay;
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
function replayStrictEffects(effects: PendingEffect[]): void {
|
|
1706
|
+
for (const { slot } of effects) {
|
|
1707
|
+
if (slot.disposed === true) {
|
|
1708
|
+
continue;
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
const cleanup = slot.callback();
|
|
1712
|
+
|
|
1713
|
+
if (typeof cleanup === "function") {
|
|
1714
|
+
slot.cleanup = cleanup;
|
|
1715
|
+
} else {
|
|
1716
|
+
delete slot.cleanup;
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
function flushProfilerCommits(
|
|
1722
|
+
runtime: RootRuntime,
|
|
1723
|
+
commits: PendingProfilerCommit[],
|
|
1724
|
+
): void {
|
|
1725
|
+
if (commits.length === 0) {
|
|
1726
|
+
return;
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
const commitTime = getCurrentTime();
|
|
1730
|
+
runtime.profilerFlushDepth += 1;
|
|
1731
|
+
|
|
1732
|
+
try {
|
|
1733
|
+
for (const commit of commits) {
|
|
1734
|
+
commit.onRender(
|
|
1735
|
+
commit.id,
|
|
1736
|
+
commit.phase,
|
|
1737
|
+
commit.actualDuration,
|
|
1738
|
+
commit.baseDuration,
|
|
1739
|
+
commit.startTime,
|
|
1740
|
+
commitTime,
|
|
1741
|
+
);
|
|
1742
|
+
}
|
|
1743
|
+
} finally {
|
|
1744
|
+
runtime.profilerFlushDepth -= 1;
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
function runActionStateDispatch(
|
|
1749
|
+
slot: Extract<HookSlot, { kind: "action-state" }>,
|
|
1750
|
+
runtime: RootRuntime,
|
|
1751
|
+
instance: ComponentInstance,
|
|
1752
|
+
payload: unknown,
|
|
1753
|
+
): void {
|
|
1754
|
+
let result: unknown;
|
|
1755
|
+
|
|
1756
|
+
try {
|
|
1757
|
+
result = slot.action(slot.state, payload);
|
|
1758
|
+
} catch (error) {
|
|
1759
|
+
slot.error = error;
|
|
1760
|
+
scheduleInstanceUpdate(runtime, instance);
|
|
1761
|
+
return;
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
if (!isThenable(result)) {
|
|
1765
|
+
slot.state = result;
|
|
1766
|
+
scheduleInstanceUpdate(runtime, instance);
|
|
1767
|
+
return;
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
slot.pendingCount += 1;
|
|
1771
|
+
scheduleInstanceUpdate(runtime, instance);
|
|
1772
|
+
result.then(
|
|
1773
|
+
(nextState) => {
|
|
1774
|
+
slot.state = nextState;
|
|
1775
|
+
slot.pendingCount = Math.max(0, slot.pendingCount - 1);
|
|
1776
|
+
scheduleInstanceUpdate(runtime, instance);
|
|
1777
|
+
},
|
|
1778
|
+
(error) => {
|
|
1779
|
+
slot.error = error;
|
|
1780
|
+
slot.pendingCount = Math.max(0, slot.pendingCount - 1);
|
|
1781
|
+
scheduleInstanceUpdate(runtime, instance);
|
|
1782
|
+
},
|
|
1783
|
+
);
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
function scheduleInstanceUpdate(
|
|
1787
|
+
runtime: RootRuntime,
|
|
1788
|
+
instance: ComponentInstance,
|
|
1789
|
+
): void {
|
|
1790
|
+
instance.dirty = true;
|
|
1791
|
+
if (transitionDepth === 0) {
|
|
1792
|
+
syncVersion += 1;
|
|
1793
|
+
if (eventBatchDepth > 0) {
|
|
1794
|
+
queueEventRerender(runtime);
|
|
1795
|
+
return;
|
|
1796
|
+
}
|
|
1797
|
+
runtime.rerender("sync");
|
|
1798
|
+
return;
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
if (currentTransitionContext !== undefined) {
|
|
1802
|
+
queueTransitionRerender(runtime, currentTransitionContext);
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
function getCacheLeaf(
|
|
1807
|
+
scope: CacheScope,
|
|
1808
|
+
callback: (...args: never[]) => unknown,
|
|
1809
|
+
args: readonly unknown[],
|
|
1810
|
+
): CacheTrieNode {
|
|
1811
|
+
let node = scope.functionCaches.get(callback);
|
|
1812
|
+
|
|
1813
|
+
if (node === undefined) {
|
|
1814
|
+
node = createCacheTrieNode();
|
|
1815
|
+
scope.functionCaches.set(callback, node);
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
for (const arg of args) {
|
|
1819
|
+
node = getCacheChild(node, arg);
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
return node;
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
function getCacheChild(node: CacheTrieNode, key: unknown): CacheTrieNode {
|
|
1826
|
+
if ((typeof key === "object" && key !== null) || typeof key === "function") {
|
|
1827
|
+
const objectKey = key as object;
|
|
1828
|
+
let child = node.objectChildren.get(objectKey);
|
|
1829
|
+
|
|
1830
|
+
if (child === undefined) {
|
|
1831
|
+
child = createCacheTrieNode();
|
|
1832
|
+
node.objectChildren.set(objectKey, child);
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
return child;
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
let child = node.primitiveChildren.get(key);
|
|
1839
|
+
|
|
1840
|
+
if (child === undefined) {
|
|
1841
|
+
child = createCacheTrieNode();
|
|
1842
|
+
node.primitiveChildren.set(key, child);
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
return child;
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
function createCacheTrieNode(): CacheTrieNode {
|
|
1849
|
+
return {
|
|
1850
|
+
primitiveChildren: new Map(),
|
|
1851
|
+
objectChildren: new WeakMap(),
|
|
1852
|
+
};
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
function getCurrentCacheScope(): CacheScope | undefined {
|
|
1856
|
+
return currentCacheScope ?? getGlobalCacheScope();
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
function getGlobalCacheScope(): CacheScope | undefined {
|
|
1860
|
+
return (globalThis as { [CACHE_SCOPE_SYMBOL]?: CacheScope })[CACHE_SCOPE_SYMBOL];
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
function setGlobalCacheScope(scope: CacheScope | undefined): void {
|
|
1864
|
+
if (scope === undefined) {
|
|
1865
|
+
delete (globalThis as { [CACHE_SCOPE_SYMBOL]?: CacheScope })[CACHE_SCOPE_SYMBOL];
|
|
1866
|
+
return;
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
(globalThis as { [CACHE_SCOPE_SYMBOL]?: CacheScope })[CACHE_SCOPE_SYMBOL] = scope;
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
function cleanupStrictEffects(effects: PendingEffect[]): void {
|
|
1873
|
+
for (const { slot } of effects) {
|
|
1874
|
+
if (slot.disposed !== true) {
|
|
1875
|
+
slot.cleanup?.();
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
function cleanupInactiveInstances(runtime: RootRuntime): void {
|
|
1881
|
+
const activeInstanceKeys = runtime.activeInstanceKeys;
|
|
1882
|
+
|
|
1883
|
+
if (activeInstanceKeys === undefined) {
|
|
1884
|
+
return;
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
for (const [key, instance] of runtime.instances) {
|
|
1888
|
+
if (!activeInstanceKeys.has(key)) {
|
|
1889
|
+
cleanupInstance(instance);
|
|
1890
|
+
runtime.instances.delete(key);
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
function cleanupInstance(instance: ComponentInstance): void {
|
|
1896
|
+
for (const slot of instance.hooks) {
|
|
1897
|
+
if (slot?.kind === "effect") {
|
|
1898
|
+
slot.disposed = true;
|
|
1899
|
+
slot.cleanup?.();
|
|
1900
|
+
delete slot.cleanup;
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
function requireRuntime(): RootRuntime {
|
|
1906
|
+
if (currentRuntime === undefined) {
|
|
1907
|
+
throw new Error("Hooks can only be called while rendering.");
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
return currentRuntime;
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
function requireInstance(): ComponentInstance {
|
|
1914
|
+
if (currentInstance === undefined) {
|
|
1915
|
+
throw new Error("Hooks can only be called while rendering.");
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
return currentInstance;
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
function areHookInputsEqual(
|
|
1922
|
+
nextDeps: readonly unknown[],
|
|
1923
|
+
previousDeps: readonly unknown[],
|
|
1924
|
+
): boolean {
|
|
1925
|
+
if (nextDeps.length !== previousDeps.length) {
|
|
1926
|
+
return false;
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1929
|
+
for (let index = 0; index < nextDeps.length; index += 1) {
|
|
1930
|
+
if (!Object.is(nextDeps[index], previousDeps[index])) {
|
|
1931
|
+
return false;
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
return true;
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
function getCurrentTime(): number {
|
|
1939
|
+
return typeof performance === "undefined" ? Date.now() : performance.now();
|
|
1940
|
+
}
|