@reckona/mreact-compat 0.0.66 → 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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reckona/mreact-compat",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.67",
|
|
4
4
|
"description": "React-compatible runtime implementation for mreact.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"compatibility",
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
"dist/**/*.js",
|
|
25
25
|
"dist/**/*.js.map",
|
|
26
26
|
"dist/**/*.d.ts",
|
|
27
|
-
"dist/**/*.d.ts.map"
|
|
27
|
+
"dist/**/*.d.ts.map",
|
|
28
|
+
"src/**/*"
|
|
28
29
|
],
|
|
29
30
|
"type": "module",
|
|
30
31
|
"sideEffects": false,
|
|
@@ -64,6 +65,6 @@
|
|
|
64
65
|
"access": "public"
|
|
65
66
|
},
|
|
66
67
|
"dependencies": {
|
|
67
|
-
"@reckona/mreact-shared": "0.0.
|
|
68
|
+
"@reckona/mreact-shared": "0.0.67"
|
|
68
69
|
}
|
|
69
70
|
}
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { renderWithRootRuntime, useLayoutEffect, useRef, type RootRuntime } from "./hooks.js";
|
|
2
|
+
import type { ReactCompatElement, ReactCompatNode } from "./element.js";
|
|
3
|
+
import { withHydrationComponentStack, type RenderOptions } from "./hydration.js";
|
|
4
|
+
import type { ReconcileNode, ReconcileResult } from "./reconcile-types.js";
|
|
5
|
+
import { isThenable } from "./thenable.js";
|
|
6
|
+
import { shallowEqual } from "./prop-comparison.js";
|
|
7
|
+
|
|
8
|
+
export interface ClassComponentInstance {
|
|
9
|
+
props: Record<string, unknown>;
|
|
10
|
+
state?: Record<string, unknown>;
|
|
11
|
+
setState?: (
|
|
12
|
+
partial:
|
|
13
|
+
| Record<string, unknown>
|
|
14
|
+
| ((
|
|
15
|
+
previousState: Record<string, unknown>,
|
|
16
|
+
props: Record<string, unknown>,
|
|
17
|
+
) => Record<string, unknown> | null),
|
|
18
|
+
callback?: () => void,
|
|
19
|
+
) => void;
|
|
20
|
+
forceUpdate?: (callback?: () => void) => void;
|
|
21
|
+
render(): ReactCompatNode;
|
|
22
|
+
componentDidMount?: () => void;
|
|
23
|
+
componentDidUpdate?: (
|
|
24
|
+
previousProps: Record<string, unknown>,
|
|
25
|
+
previousState: Record<string, unknown>,
|
|
26
|
+
snapshot?: unknown,
|
|
27
|
+
) => void;
|
|
28
|
+
componentWillUnmount?: () => void;
|
|
29
|
+
shouldComponentUpdate?: (
|
|
30
|
+
nextProps: Record<string, unknown>,
|
|
31
|
+
nextState: Record<string, unknown>,
|
|
32
|
+
) => boolean;
|
|
33
|
+
getSnapshotBeforeUpdate?: (
|
|
34
|
+
previousProps: Record<string, unknown>,
|
|
35
|
+
previousState: Record<string, unknown>,
|
|
36
|
+
) => unknown;
|
|
37
|
+
componentDidCatch?: (error: Error, info: { componentStack: string }) => void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ClassComponentType {
|
|
41
|
+
new (props: Record<string, unknown>): ClassComponentInstance;
|
|
42
|
+
getDerivedStateFromError?: (error: Error) => Record<string, unknown> | null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class Component<
|
|
46
|
+
P extends Record<string, unknown> = Record<string, unknown>,
|
|
47
|
+
S extends Record<string, unknown> = Record<string, unknown>,
|
|
48
|
+
> {
|
|
49
|
+
props: P;
|
|
50
|
+
state?: S;
|
|
51
|
+
setState!: ClassComponentInstance["setState"];
|
|
52
|
+
forceUpdate!: ClassComponentInstance["forceUpdate"];
|
|
53
|
+
|
|
54
|
+
constructor(props: P) {
|
|
55
|
+
this.props = props;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
render(): ReactCompatNode {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export class PureComponent<
|
|
64
|
+
P extends Record<string, unknown> = Record<string, unknown>,
|
|
65
|
+
S extends Record<string, unknown> = Record<string, unknown>,
|
|
66
|
+
> extends Component<P, S> {
|
|
67
|
+
shouldComponentUpdate(nextProps: P, nextState: S): boolean {
|
|
68
|
+
return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state ?? {}, nextState ?? {});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface ClassLifecycleSnapshot {
|
|
73
|
+
previousState?: Record<string, unknown>;
|
|
74
|
+
force?: boolean;
|
|
75
|
+
snapshot?: unknown;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const classLifecycleSnapshots = new WeakMap<
|
|
79
|
+
ClassComponentInstance,
|
|
80
|
+
ClassLifecycleSnapshot
|
|
81
|
+
>();
|
|
82
|
+
|
|
83
|
+
export type ClassComponentRenderResult =
|
|
84
|
+
| {
|
|
85
|
+
kind: "render";
|
|
86
|
+
node: ReactCompatNode;
|
|
87
|
+
instance: ClassComponentInstance;
|
|
88
|
+
type: ClassComponentType;
|
|
89
|
+
}
|
|
90
|
+
| { kind: "skip" };
|
|
91
|
+
|
|
92
|
+
export function reconcileClassComponent(
|
|
93
|
+
parent: ParentNode,
|
|
94
|
+
previousNodes: readonly Node[],
|
|
95
|
+
type: ClassComponentType,
|
|
96
|
+
props: Record<string, unknown>,
|
|
97
|
+
runtime: RootRuntime,
|
|
98
|
+
path: string,
|
|
99
|
+
options: RenderOptions,
|
|
100
|
+
reconcileNode: ReconcileNode,
|
|
101
|
+
onInstance?: (instance: ClassComponentInstance) => void,
|
|
102
|
+
): ReconcileResult {
|
|
103
|
+
const rendered = renderClassComponentWithRuntime(type, props, runtime, path);
|
|
104
|
+
|
|
105
|
+
if (rendered.kind === "skip") {
|
|
106
|
+
return { nodes: previousNodes.slice(0, 1), consumed: previousNodes.length };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
onInstance?.(rendered.instance);
|
|
110
|
+
const childOptions = withHydrationComponentStack(
|
|
111
|
+
options,
|
|
112
|
+
getClassComponentName(type),
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
return reconcileNode(
|
|
117
|
+
parent,
|
|
118
|
+
previousNodes,
|
|
119
|
+
rendered.node,
|
|
120
|
+
runtime,
|
|
121
|
+
`${path}.class`,
|
|
122
|
+
childOptions,
|
|
123
|
+
);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
const fallbackNode = recoverClassComponentError(
|
|
126
|
+
rendered.type,
|
|
127
|
+
rendered.instance,
|
|
128
|
+
error,
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
if (fallbackNode === undefined) {
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return reconcileNode(
|
|
136
|
+
parent,
|
|
137
|
+
previousNodes,
|
|
138
|
+
fallbackNode,
|
|
139
|
+
runtime,
|
|
140
|
+
`${path}.class.fallback`,
|
|
141
|
+
childOptions,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function renderClassComponentWithRuntime(
|
|
147
|
+
type: ClassComponentType,
|
|
148
|
+
props: Record<string, unknown>,
|
|
149
|
+
runtime: RootRuntime,
|
|
150
|
+
path: string,
|
|
151
|
+
): ClassComponentRenderResult {
|
|
152
|
+
return renderWithRootRuntime(runtime, path, () => {
|
|
153
|
+
const instanceRef = useRef<ClassComponentInstance | undefined>(undefined);
|
|
154
|
+
const didCommitRef = useRef(false);
|
|
155
|
+
const previousInstance = instanceRef.current;
|
|
156
|
+
const hasDifferentType =
|
|
157
|
+
previousInstance !== undefined && !(previousInstance instanceof type);
|
|
158
|
+
const replacedInstance = hasDifferentType ? previousInstance : undefined;
|
|
159
|
+
|
|
160
|
+
if (hasDifferentType) {
|
|
161
|
+
classLifecycleSnapshots.delete(previousInstance);
|
|
162
|
+
didCommitRef.current = false;
|
|
163
|
+
instanceRef.current = undefined;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const instance =
|
|
167
|
+
instanceRef.current !== undefined && instanceRef.current instanceof type
|
|
168
|
+
? instanceRef.current
|
|
169
|
+
: new type(props);
|
|
170
|
+
const previousProps = instance.props;
|
|
171
|
+
const snapshot = classLifecycleSnapshots.get(instance);
|
|
172
|
+
const previousState = snapshot?.previousState ?? instance.state ?? {};
|
|
173
|
+
const nextState = instance.state ?? {};
|
|
174
|
+
|
|
175
|
+
instanceRef.current = instance;
|
|
176
|
+
installClassUpdateMethods(instance, runtime);
|
|
177
|
+
const shouldSkipUpdate =
|
|
178
|
+
didCommitRef.current &&
|
|
179
|
+
snapshot?.force !== true &&
|
|
180
|
+
instance.shouldComponentUpdate?.(props, nextState) === false;
|
|
181
|
+
|
|
182
|
+
instance.props = props;
|
|
183
|
+
installClassLifecycleEffects(
|
|
184
|
+
instance,
|
|
185
|
+
didCommitRef,
|
|
186
|
+
previousProps,
|
|
187
|
+
previousState,
|
|
188
|
+
shouldSkipUpdate,
|
|
189
|
+
replacedInstance,
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
if (shouldSkipUpdate) {
|
|
193
|
+
return { kind: "skip" };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
const node = instance.render();
|
|
198
|
+
|
|
199
|
+
if (didCommitRef.current) {
|
|
200
|
+
classLifecycleSnapshots.set(instance, {
|
|
201
|
+
...classLifecycleSnapshots.get(instance),
|
|
202
|
+
snapshot: instance.getSnapshotBeforeUpdate?.(
|
|
203
|
+
previousProps ?? {},
|
|
204
|
+
previousState,
|
|
205
|
+
),
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return { kind: "render", node, instance, type };
|
|
210
|
+
} catch (error) {
|
|
211
|
+
const fallbackNode = recoverClassComponentError(type, instance, error);
|
|
212
|
+
|
|
213
|
+
if (fallbackNode === undefined) {
|
|
214
|
+
throw error;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return { kind: "render", node: fallbackNode, instance, type };
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function recoverClassComponentError(
|
|
223
|
+
type: ClassComponentType,
|
|
224
|
+
instance: ClassComponentInstance,
|
|
225
|
+
error: unknown,
|
|
226
|
+
): ReactCompatNode | undefined {
|
|
227
|
+
if (isThenable(error) || !isErrorBoundaryClass(type, instance)) {
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const normalizedError =
|
|
232
|
+
error instanceof Error ? error : new Error(String(error));
|
|
233
|
+
const derivedState = type.getDerivedStateFromError?.(normalizedError);
|
|
234
|
+
|
|
235
|
+
if (derivedState !== undefined && derivedState !== null) {
|
|
236
|
+
instance.state = {
|
|
237
|
+
...instance.state,
|
|
238
|
+
...derivedState,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
instance.componentDidCatch?.(normalizedError, { componentStack: "" });
|
|
243
|
+
return instance.render();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export function isClassComponentType(value: unknown): value is ClassComponentType {
|
|
247
|
+
return (
|
|
248
|
+
typeof value === "function" &&
|
|
249
|
+
typeof (value as { prototype?: { render?: unknown } }).prototype?.render ===
|
|
250
|
+
"function"
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function getClassComponentName(type: ClassComponentType): string {
|
|
255
|
+
return type.name === "" ? "Anonymous" : type.name;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export function reconcileErrorBoundary(
|
|
259
|
+
parent: ParentNode,
|
|
260
|
+
previousNodes: readonly Node[],
|
|
261
|
+
element: ReactCompatElement,
|
|
262
|
+
runtime: RootRuntime,
|
|
263
|
+
path: string,
|
|
264
|
+
options: RenderOptions,
|
|
265
|
+
reconcileNode: ReconcileNode,
|
|
266
|
+
): ReconcileResult {
|
|
267
|
+
try {
|
|
268
|
+
return reconcileNode(
|
|
269
|
+
parent,
|
|
270
|
+
previousNodes,
|
|
271
|
+
element.props.children,
|
|
272
|
+
runtime,
|
|
273
|
+
`${path}.eb`,
|
|
274
|
+
options,
|
|
275
|
+
);
|
|
276
|
+
} catch (error) {
|
|
277
|
+
if (isThenable(error)) {
|
|
278
|
+
throw error;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const normalizedError =
|
|
282
|
+
error instanceof Error ? error : new Error(String(error));
|
|
283
|
+
const onError = element.props.onError;
|
|
284
|
+
|
|
285
|
+
if (typeof onError === "function") {
|
|
286
|
+
(onError as (error: Error) => void)(normalizedError);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const fallback = element.props.fallback;
|
|
290
|
+
const fallbackNode =
|
|
291
|
+
typeof fallback === "function"
|
|
292
|
+
? (fallback as (error: Error) => ReactCompatNode)(normalizedError)
|
|
293
|
+
: null;
|
|
294
|
+
|
|
295
|
+
return reconcileNode(
|
|
296
|
+
parent,
|
|
297
|
+
previousNodes,
|
|
298
|
+
fallbackNode,
|
|
299
|
+
runtime,
|
|
300
|
+
`${path}.eb.fallback`,
|
|
301
|
+
options,
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function installClassUpdateMethods(
|
|
307
|
+
instance: ClassComponentInstance,
|
|
308
|
+
runtime: RootRuntime,
|
|
309
|
+
): void {
|
|
310
|
+
instance.setState = (partial, callback): void => {
|
|
311
|
+
const previousState = instance.state ?? {};
|
|
312
|
+
if (!classLifecycleSnapshots.has(instance)) {
|
|
313
|
+
classLifecycleSnapshots.set(instance, { previousState });
|
|
314
|
+
}
|
|
315
|
+
const nextPartial =
|
|
316
|
+
typeof partial === "function"
|
|
317
|
+
? partial(previousState, instance.props)
|
|
318
|
+
: partial;
|
|
319
|
+
|
|
320
|
+
if (nextPartial !== null) {
|
|
321
|
+
instance.state = {
|
|
322
|
+
...previousState,
|
|
323
|
+
...nextPartial,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
runtime.rerender();
|
|
328
|
+
callback?.call(instance);
|
|
329
|
+
};
|
|
330
|
+
instance.forceUpdate = (callback): void => {
|
|
331
|
+
classLifecycleSnapshots.set(instance, {
|
|
332
|
+
previousState: instance.state ?? {},
|
|
333
|
+
force: true,
|
|
334
|
+
});
|
|
335
|
+
runtime.rerender();
|
|
336
|
+
callback?.call(instance);
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function installClassLifecycleEffects(
|
|
341
|
+
instance: ClassComponentInstance,
|
|
342
|
+
didCommitRef: { current: boolean },
|
|
343
|
+
previousProps: Record<string, unknown> | undefined,
|
|
344
|
+
previousState: Record<string, unknown>,
|
|
345
|
+
skipUpdate: boolean,
|
|
346
|
+
replacedInstance?: ClassComponentInstance,
|
|
347
|
+
): void {
|
|
348
|
+
useLayoutEffect(() => {
|
|
349
|
+
replacedInstance?.componentWillUnmount?.();
|
|
350
|
+
|
|
351
|
+
if (skipUpdate) {
|
|
352
|
+
classLifecycleSnapshots.delete(instance);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (didCommitRef.current) {
|
|
357
|
+
instance.componentDidUpdate?.(
|
|
358
|
+
previousProps ?? {},
|
|
359
|
+
previousState,
|
|
360
|
+
classLifecycleSnapshots.get(instance)?.snapshot,
|
|
361
|
+
);
|
|
362
|
+
} else {
|
|
363
|
+
didCommitRef.current = true;
|
|
364
|
+
instance.componentDidMount?.();
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
classLifecycleSnapshots.delete(instance);
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
useLayoutEffect(() => {
|
|
371
|
+
return () => {
|
|
372
|
+
instance.componentWillUnmount?.();
|
|
373
|
+
classLifecycleSnapshots.delete(instance);
|
|
374
|
+
};
|
|
375
|
+
}, []);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function isErrorBoundaryClass(
|
|
379
|
+
type: ClassComponentType,
|
|
380
|
+
instance: ClassComponentInstance,
|
|
381
|
+
): boolean {
|
|
382
|
+
return (
|
|
383
|
+
typeof type.getDerivedStateFromError === "function" ||
|
|
384
|
+
typeof instance.componentDidCatch === "function"
|
|
385
|
+
);
|
|
386
|
+
}
|
package/src/context.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
const REACT_COMPAT_PROVIDER_TYPE = Symbol.for("modular.react.provider");
|
|
2
|
+
const REACT_COMPAT_CONSUMER_TYPE = Symbol.for("modular.react.consumer");
|
|
3
|
+
|
|
4
|
+
export interface ReactCompatContext<T> {
|
|
5
|
+
defaultValue: T;
|
|
6
|
+
values: T[];
|
|
7
|
+
Provider: ReactCompatProvider<T>;
|
|
8
|
+
Consumer: ReactCompatConsumer<T>;
|
|
9
|
+
displayName: string | undefined;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ReactCompatProvider<T> {
|
|
13
|
+
$$typeof: typeof REACT_COMPAT_PROVIDER_TYPE;
|
|
14
|
+
context: ReactCompatContext<T>;
|
|
15
|
+
displayName: string | undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ReactCompatConsumer<T> {
|
|
19
|
+
$$typeof: typeof REACT_COMPAT_CONSUMER_TYPE;
|
|
20
|
+
context: ReactCompatContext<T>;
|
|
21
|
+
displayName: string | undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function createContext<T>(defaultValue: T): ReactCompatContext<T> {
|
|
25
|
+
const context: ReactCompatContext<T> = {
|
|
26
|
+
defaultValue,
|
|
27
|
+
values: [],
|
|
28
|
+
Provider: undefined as unknown as ReactCompatProvider<T>,
|
|
29
|
+
Consumer: undefined as unknown as ReactCompatConsumer<T>,
|
|
30
|
+
displayName: undefined,
|
|
31
|
+
};
|
|
32
|
+
context.Provider = {
|
|
33
|
+
$$typeof: REACT_COMPAT_PROVIDER_TYPE,
|
|
34
|
+
context,
|
|
35
|
+
displayName: undefined,
|
|
36
|
+
};
|
|
37
|
+
context.Consumer = {
|
|
38
|
+
$$typeof: REACT_COMPAT_CONSUMER_TYPE,
|
|
39
|
+
context,
|
|
40
|
+
displayName: undefined,
|
|
41
|
+
};
|
|
42
|
+
installContextDisplayName(context);
|
|
43
|
+
return context;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function installContextDisplayName<T>(context: ReactCompatContext<T>): void {
|
|
47
|
+
let displayName: string | undefined;
|
|
48
|
+
|
|
49
|
+
Object.defineProperty(context, "displayName", {
|
|
50
|
+
configurable: true,
|
|
51
|
+
enumerable: true,
|
|
52
|
+
get() {
|
|
53
|
+
return displayName;
|
|
54
|
+
},
|
|
55
|
+
set(value: string | undefined) {
|
|
56
|
+
displayName = value;
|
|
57
|
+
context.Provider.displayName =
|
|
58
|
+
value === undefined ? undefined : `${value}.Provider`;
|
|
59
|
+
context.Consumer.displayName =
|
|
60
|
+
value === undefined ? undefined : `${value}.Consumer`;
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function useContext<T>(context: ReactCompatContext<T>): T {
|
|
66
|
+
return context.values.at(-1) ?? context.defaultValue;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function isReactCompatProvider(
|
|
70
|
+
value: unknown,
|
|
71
|
+
): value is ReactCompatProvider<unknown> {
|
|
72
|
+
return (
|
|
73
|
+
typeof value === "object" &&
|
|
74
|
+
value !== null &&
|
|
75
|
+
(value as { $$typeof?: unknown }).$$typeof === REACT_COMPAT_PROVIDER_TYPE
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function isReactCompatContext(
|
|
80
|
+
value: unknown,
|
|
81
|
+
): value is ReactCompatContext<unknown> {
|
|
82
|
+
return (
|
|
83
|
+
typeof value === "object" &&
|
|
84
|
+
value !== null &&
|
|
85
|
+
"Provider" in value &&
|
|
86
|
+
"Consumer" in value &&
|
|
87
|
+
isReactCompatProvider((value as { Provider?: unknown }).Provider) &&
|
|
88
|
+
isReactCompatConsumer((value as { Consumer?: unknown }).Consumer)
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function isReactCompatConsumer(
|
|
93
|
+
value: unknown,
|
|
94
|
+
): value is ReactCompatConsumer<unknown> {
|
|
95
|
+
return (
|
|
96
|
+
typeof value === "object" &&
|
|
97
|
+
value !== null &&
|
|
98
|
+
(value as { $$typeof?: unknown }).$$typeof === REACT_COMPAT_CONSUMER_TYPE
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function renderWithContextProvider<T, R>(
|
|
103
|
+
provider: ReactCompatProvider<T>,
|
|
104
|
+
value: T,
|
|
105
|
+
render: () => R,
|
|
106
|
+
): R {
|
|
107
|
+
pushContextProvider(provider, value);
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
return render();
|
|
111
|
+
} finally {
|
|
112
|
+
popContextProvider(provider);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function pushContextProvider<T>(
|
|
117
|
+
provider: ReactCompatProvider<T>,
|
|
118
|
+
value: T,
|
|
119
|
+
): void {
|
|
120
|
+
provider.context.values.push(value);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function popContextProvider<T>(provider: ReactCompatProvider<T>): void {
|
|
124
|
+
provider.context.values.pop();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function renderContextProviderToString<T>(
|
|
128
|
+
provider: ReactCompatProvider<T>,
|
|
129
|
+
value: T,
|
|
130
|
+
render: () => string,
|
|
131
|
+
): string {
|
|
132
|
+
return renderWithContextProvider(provider, value, render);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function renderContextConsumerToString<T>(
|
|
136
|
+
consumer: ReactCompatConsumer<T>,
|
|
137
|
+
render: (value: T) => string,
|
|
138
|
+
): string {
|
|
139
|
+
return render(useContext(consumer.context));
|
|
140
|
+
}
|