@reckona/mreact-compat 0.0.90 → 0.0.92
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/class-component.d.ts +20 -6
- package/dist/class-component.d.ts.map +1 -1
- package/dist/class-component.js +94 -51
- package/dist/class-component.js.map +1 -1
- package/dist/context.d.ts +19 -3
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +55 -6
- package/dist/context.js.map +1 -1
- package/dist/dom-children.d.ts +2 -0
- package/dist/dom-children.d.ts.map +1 -1
- package/dist/dom-children.js +103 -1
- package/dist/dom-children.js.map +1 -1
- package/dist/dom-host-rules.d.ts +10 -0
- package/dist/dom-host-rules.d.ts.map +1 -0
- package/dist/dom-host-rules.js +86 -0
- package/dist/dom-host-rules.js.map +1 -0
- package/dist/dom-props.d.ts +3 -2
- package/dist/dom-props.d.ts.map +1 -1
- package/dist/dom-props.js +229 -33
- package/dist/dom-props.js.map +1 -1
- package/dist/element.d.ts +9 -4
- package/dist/element.d.ts.map +1 -1
- package/dist/element.js +101 -26
- package/dist/element.js.map +1 -1
- package/dist/event-listeners.d.ts +4 -4
- package/dist/event-listeners.d.ts.map +1 -1
- package/dist/event-listeners.js +1 -1
- package/dist/event-listeners.js.map +1 -1
- package/dist/event-types.d.ts +10 -0
- package/dist/event-types.d.ts.map +1 -1
- package/dist/event-types.js.map +1 -1
- package/dist/events.js +22 -1
- package/dist/events.js.map +1 -1
- package/dist/fiber-commit.d.ts +2 -1
- package/dist/fiber-commit.d.ts.map +1 -1
- package/dist/fiber-commit.js +13 -1
- package/dist/fiber-commit.js.map +1 -1
- package/dist/fiber-reconciler.d.ts.map +1 -1
- package/dist/fiber-reconciler.js +28 -7
- package/dist/fiber-reconciler.js.map +1 -1
- package/dist/fiber-work-loop.d.ts.map +1 -1
- package/dist/fiber-work-loop.js +4 -3
- package/dist/fiber-work-loop.js.map +1 -1
- package/dist/fiber.d.ts +5 -0
- package/dist/fiber.d.ts.map +1 -1
- package/dist/fiber.js +9 -0
- package/dist/fiber.js.map +1 -1
- package/dist/hooks-entry.d.ts +3 -0
- package/dist/hooks-entry.d.ts.map +1 -0
- package/dist/hooks-entry.js +2 -0
- package/dist/hooks-entry.js.map +1 -0
- package/dist/hooks.d.ts +39 -5
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +373 -326
- package/dist/hooks.js.map +1 -1
- package/dist/host-reconciler.d.ts +3 -0
- package/dist/host-reconciler.d.ts.map +1 -1
- package/dist/host-reconciler.js +1152 -64
- package/dist/host-reconciler.js.map +1 -1
- package/dist/hydration.d.ts +1 -1
- package/dist/hydration.d.ts.map +1 -1
- package/dist/hydration.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/react-default.d.ts +4 -4
- package/dist/react-default.d.ts.map +1 -1
- package/dist/react-default.js +2 -1
- package/dist/react-default.js.map +1 -1
- package/dist/reconciler.d.ts.map +1 -1
- package/dist/reconciler.js +38 -22
- package/dist/reconciler.js.map +1 -1
- package/dist/root.d.ts.map +1 -1
- package/dist/root.js +48 -13
- package/dist/root.js.map +1 -1
- package/dist/server-render.d.ts +6 -0
- package/dist/server-render.d.ts.map +1 -0
- package/dist/server-render.js +307 -0
- package/dist/server-render.js.map +1 -0
- package/package.json +6 -2
- package/src/class-component.ts +216 -51
- package/src/context.ts +108 -9
- package/src/dom-children.ts +155 -1
- package/src/dom-host-rules.ts +115 -0
- package/src/dom-props.ts +297 -46
- package/src/element.ts +141 -31
- package/src/event-listeners.ts +6 -6
- package/src/event-types.ts +10 -0
- package/src/events.ts +32 -10
- package/src/fiber-commit.ts +16 -1
- package/src/fiber-reconciler.ts +39 -6
- package/src/fiber-work-loop.ts +4 -3
- package/src/fiber.ts +14 -0
- package/src/hooks-entry.ts +24 -0
- package/src/hooks.ts +482 -479
- package/src/host-reconciler.ts +1628 -94
- package/src/hydration.ts +1 -1
- package/src/index.ts +1 -1
- package/src/react-default.ts +1 -1
- package/src/reconciler.ts +61 -22
- package/src/root.ts +55 -12
- package/src/server-render.ts +478 -0
package/src/class-component.ts
CHANGED
|
@@ -5,6 +5,8 @@ import type { ReconcileNode, ReconcileResult } from "./reconcile-types.js";
|
|
|
5
5
|
import { isThenable } from "./thenable.js";
|
|
6
6
|
import { shallowEqual } from "./prop-comparison.js";
|
|
7
7
|
|
|
8
|
+
const CLASS_COMPONENT_RUNTIME_OWNER = Symbol.for("modular.react.class_component_runtime");
|
|
9
|
+
|
|
8
10
|
export interface ClassComponentInstance {
|
|
9
11
|
props: Record<string, unknown>;
|
|
10
12
|
state?: Record<string, unknown>;
|
|
@@ -46,43 +48,144 @@ export interface ClassComponentType {
|
|
|
46
48
|
getDerivedStateFromError?: (error: Error) => Record<string, unknown> | null;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
export
|
|
51
|
+
export interface Component<
|
|
50
52
|
P extends Record<string, unknown> = Record<string, unknown>,
|
|
51
53
|
S extends Record<string, unknown> = Record<string, unknown>,
|
|
52
54
|
> {
|
|
53
55
|
props: P;
|
|
54
56
|
state?: S;
|
|
55
|
-
setState
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
setState(
|
|
58
|
+
partial:
|
|
59
|
+
| Partial<S>
|
|
60
|
+
| ((
|
|
61
|
+
previousState: Readonly<S>,
|
|
62
|
+
props: Readonly<P>,
|
|
63
|
+
) => Partial<S> | S | null),
|
|
64
|
+
callback?: () => void,
|
|
65
|
+
): void;
|
|
66
|
+
forceUpdate(callback?: () => void): void;
|
|
67
|
+
render(): ReactCompatNode;
|
|
68
|
+
}
|
|
61
69
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
70
|
+
export interface ComponentConstructor {
|
|
71
|
+
new <
|
|
72
|
+
P extends Record<string, unknown> = Record<string, unknown>,
|
|
73
|
+
S extends Record<string, unknown> = Record<string, unknown>,
|
|
74
|
+
>(props: P): Component<P, S>;
|
|
75
|
+
<
|
|
76
|
+
P extends Record<string, unknown> = Record<string, unknown>,
|
|
77
|
+
S extends Record<string, unknown> = Record<string, unknown>,
|
|
78
|
+
>(this: Component<P, S>, props: P): void;
|
|
79
|
+
prototype: Component<any, any>;
|
|
65
80
|
}
|
|
66
81
|
|
|
67
|
-
export
|
|
82
|
+
export const Component: ComponentConstructor = function Component<
|
|
83
|
+
P extends Record<string, unknown> = Record<string, unknown>,
|
|
84
|
+
S extends Record<string, unknown> = Record<string, unknown>,
|
|
85
|
+
>(this: Component<P, S>, props: P): void {
|
|
86
|
+
this.props = props;
|
|
87
|
+
} as ComponentConstructor;
|
|
88
|
+
|
|
89
|
+
Component.prototype.setState = function setState<
|
|
90
|
+
P extends Record<string, unknown>,
|
|
91
|
+
S extends Record<string, unknown>,
|
|
92
|
+
>(
|
|
93
|
+
this: Component<P, S>,
|
|
94
|
+
partial:
|
|
95
|
+
| Partial<S>
|
|
96
|
+
| ((
|
|
97
|
+
previousState: Readonly<S>,
|
|
98
|
+
props: Readonly<P>,
|
|
99
|
+
) => Partial<S> | S | null),
|
|
100
|
+
callback?: () => void,
|
|
101
|
+
): void {
|
|
102
|
+
enqueueClassSetState(
|
|
103
|
+
this as unknown as ClassComponentInstance,
|
|
104
|
+
partial as Parameters<NonNullable<ClassComponentInstance["setState"]>>[0],
|
|
105
|
+
callback,
|
|
106
|
+
);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
Component.prototype.forceUpdate = function forceUpdate(
|
|
110
|
+
this: Component,
|
|
111
|
+
callback?: () => void,
|
|
112
|
+
): void {
|
|
113
|
+
enqueueClassForceUpdate(this as unknown as ClassComponentInstance, callback);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
Component.prototype.render = function render(): ReactCompatNode {
|
|
117
|
+
return null;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export interface PureComponent<
|
|
68
121
|
P extends Record<string, unknown> = Record<string, unknown>,
|
|
69
122
|
S extends Record<string, unknown> = Record<string, unknown>,
|
|
70
123
|
> extends Component<P, S> {
|
|
71
|
-
shouldComponentUpdate(nextProps: P, nextState: S): boolean
|
|
72
|
-
|
|
73
|
-
|
|
124
|
+
shouldComponentUpdate(nextProps: P, nextState: S): boolean;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface PureComponentConstructor {
|
|
128
|
+
new <
|
|
129
|
+
P extends Record<string, unknown> = Record<string, unknown>,
|
|
130
|
+
S extends Record<string, unknown> = Record<string, unknown>,
|
|
131
|
+
>(props: P): PureComponent<P, S>;
|
|
132
|
+
<
|
|
133
|
+
P extends Record<string, unknown> = Record<string, unknown>,
|
|
134
|
+
S extends Record<string, unknown> = Record<string, unknown>,
|
|
135
|
+
>(this: PureComponent<P, S>, props: P): void;
|
|
136
|
+
prototype: PureComponent<any, any>;
|
|
74
137
|
}
|
|
75
138
|
|
|
139
|
+
export const PureComponent: PureComponentConstructor = function PureComponent<
|
|
140
|
+
P extends Record<string, unknown> = Record<string, unknown>,
|
|
141
|
+
S extends Record<string, unknown> = Record<string, unknown>,
|
|
142
|
+
>(this: PureComponent<P, S>, props: P): void {
|
|
143
|
+
(Component as unknown as (this: unknown, props: unknown) => void).call(
|
|
144
|
+
this,
|
|
145
|
+
props,
|
|
146
|
+
);
|
|
147
|
+
} as PureComponentConstructor;
|
|
148
|
+
|
|
149
|
+
PureComponent.prototype = Object.create(Component.prototype) as PureComponent<any, any>;
|
|
150
|
+
PureComponent.prototype.constructor = PureComponent;
|
|
151
|
+
PureComponent.prototype.shouldComponentUpdate = function shouldComponentUpdate<
|
|
152
|
+
P extends Record<string, unknown>,
|
|
153
|
+
S extends Record<string, unknown>,
|
|
154
|
+
>(
|
|
155
|
+
this: PureComponent<P, S>,
|
|
156
|
+
nextProps: P,
|
|
157
|
+
nextState: S,
|
|
158
|
+
): boolean {
|
|
159
|
+
return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state ?? {}, nextState ?? {});
|
|
160
|
+
};
|
|
161
|
+
|
|
76
162
|
interface ClassLifecycleSnapshot {
|
|
77
163
|
previousState?: Record<string, unknown>;
|
|
164
|
+
nextState?: Record<string, unknown>;
|
|
78
165
|
force?: boolean;
|
|
79
166
|
snapshot?: unknown;
|
|
80
167
|
}
|
|
81
168
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
169
|
+
interface ClassUpdateContext {
|
|
170
|
+
runtime: RootRuntime;
|
|
171
|
+
path: string;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
interface ClassComponentGlobalState {
|
|
175
|
+
lifecycleSnapshots: WeakMap<ClassComponentInstance, ClassLifecycleSnapshot>;
|
|
176
|
+
updateContexts: WeakMap<ClassComponentInstance, ClassUpdateContext>;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const CLASS_COMPONENT_STATE_KEY = Symbol.for("modular.react.class_component_state");
|
|
180
|
+
const classComponentGlobalState =
|
|
181
|
+
((globalThis as typeof globalThis & Record<symbol, ClassComponentGlobalState | undefined>)[
|
|
182
|
+
CLASS_COMPONENT_STATE_KEY
|
|
183
|
+
] ??= {
|
|
184
|
+
lifecycleSnapshots: new WeakMap(),
|
|
185
|
+
updateContexts: new WeakMap(),
|
|
186
|
+
});
|
|
187
|
+
const classLifecycleSnapshots = classComponentGlobalState.lifecycleSnapshots;
|
|
188
|
+
const classUpdateContexts = classComponentGlobalState.updateContexts;
|
|
86
189
|
|
|
87
190
|
export type ClassComponentRenderResult =
|
|
88
191
|
| {
|
|
@@ -152,6 +255,7 @@ export function renderClassComponentWithRuntime(
|
|
|
152
255
|
props: Record<string, unknown>,
|
|
153
256
|
runtime: RootRuntime,
|
|
154
257
|
path: string,
|
|
258
|
+
options: { hasDirtyDescendant?: boolean } = {},
|
|
155
259
|
): ClassComponentRenderResult {
|
|
156
260
|
return renderWithRootRuntime(runtime, path, () => {
|
|
157
261
|
const instanceRef = useRef<ClassComponentInstance | undefined>(undefined);
|
|
@@ -163,6 +267,7 @@ export function renderClassComponentWithRuntime(
|
|
|
163
267
|
|
|
164
268
|
if (hasDifferentType) {
|
|
165
269
|
classLifecycleSnapshots.delete(previousInstance);
|
|
270
|
+
classUpdateContexts.delete(previousInstance);
|
|
166
271
|
didCommitRef.current = false;
|
|
167
272
|
instanceRef.current = undefined;
|
|
168
273
|
}
|
|
@@ -176,15 +281,20 @@ export function renderClassComponentWithRuntime(
|
|
|
176
281
|
const previousState = snapshot?.previousState ?? instance.state ?? {};
|
|
177
282
|
|
|
178
283
|
instanceRef.current = instance;
|
|
179
|
-
installClassUpdateMethods(instance, runtime);
|
|
180
|
-
|
|
181
|
-
|
|
284
|
+
installClassUpdateMethods(instance, runtime, path);
|
|
285
|
+
const nextState = resolveDerivedStateFromProps(
|
|
286
|
+
type,
|
|
287
|
+
props,
|
|
288
|
+
snapshot?.nextState ?? instance.state ?? {},
|
|
289
|
+
);
|
|
182
290
|
const shouldSkipUpdate =
|
|
183
291
|
didCommitRef.current &&
|
|
184
292
|
snapshot?.force !== true &&
|
|
293
|
+
options.hasDirtyDescendant !== true &&
|
|
185
294
|
instance.shouldComponentUpdate?.(props, nextState) === false;
|
|
186
295
|
|
|
187
296
|
instance.props = props;
|
|
297
|
+
instance.state = nextState;
|
|
188
298
|
installClassLifecycleEffects(
|
|
189
299
|
instance,
|
|
190
300
|
didCommitRef,
|
|
@@ -221,7 +331,7 @@ export function renderClassComponentWithRuntime(
|
|
|
221
331
|
|
|
222
332
|
return { kind: "render", node: fallbackNode, instance, type };
|
|
223
333
|
}
|
|
224
|
-
});
|
|
334
|
+
}, CLASS_COMPONENT_RUNTIME_OWNER);
|
|
225
335
|
}
|
|
226
336
|
|
|
227
337
|
export function applyDerivedStateFromProps(
|
|
@@ -230,14 +340,22 @@ export function applyDerivedStateFromProps(
|
|
|
230
340
|
nextProps: Record<string, unknown>,
|
|
231
341
|
previousState: Record<string, unknown>,
|
|
232
342
|
): void {
|
|
343
|
+
instance.state = resolveDerivedStateFromProps(type, nextProps, previousState);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export function resolveDerivedStateFromProps(
|
|
347
|
+
type: ClassComponentType,
|
|
348
|
+
nextProps: Record<string, unknown>,
|
|
349
|
+
previousState: Record<string, unknown>,
|
|
350
|
+
): Record<string, unknown> {
|
|
233
351
|
const derivedState = type.getDerivedStateFromProps?.(nextProps, previousState);
|
|
234
352
|
|
|
235
353
|
if (derivedState === undefined || derivedState === null) {
|
|
236
|
-
return;
|
|
354
|
+
return previousState;
|
|
237
355
|
}
|
|
238
356
|
|
|
239
|
-
|
|
240
|
-
...
|
|
357
|
+
return {
|
|
358
|
+
...previousState,
|
|
241
359
|
...derivedState,
|
|
242
360
|
};
|
|
243
361
|
}
|
|
@@ -329,35 +447,78 @@ export function reconcileErrorBoundary(
|
|
|
329
447
|
function installClassUpdateMethods(
|
|
330
448
|
instance: ClassComponentInstance,
|
|
331
449
|
runtime: RootRuntime,
|
|
450
|
+
path: string,
|
|
332
451
|
): void {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
instance.state = {
|
|
345
|
-
...previousState,
|
|
346
|
-
...nextPartial,
|
|
347
|
-
};
|
|
348
|
-
}
|
|
452
|
+
classUpdateContexts.set(instance, { runtime, path });
|
|
453
|
+
instance.setState = Component.prototype.setState;
|
|
454
|
+
instance.forceUpdate = Component.prototype.forceUpdate;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function enqueueClassSetState(
|
|
458
|
+
instance: ClassComponentInstance,
|
|
459
|
+
partial: Parameters<NonNullable<ClassComponentInstance["setState"]>>[0],
|
|
460
|
+
callback?: () => void,
|
|
461
|
+
): void {
|
|
462
|
+
const updateContext = classUpdateContexts.get(instance);
|
|
349
463
|
|
|
350
|
-
|
|
464
|
+
if (updateContext === undefined) {
|
|
351
465
|
callback?.call(instance);
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const snapshot = classLifecycleSnapshots.get(instance);
|
|
470
|
+
const previousState = snapshot?.previousState ?? instance.state ?? {};
|
|
471
|
+
const baseState = snapshot?.nextState ?? instance.state ?? {};
|
|
472
|
+
const nextPartial =
|
|
473
|
+
typeof partial === "function"
|
|
474
|
+
? partial(baseState, instance.props)
|
|
475
|
+
: partial;
|
|
476
|
+
|
|
477
|
+
const nextState =
|
|
478
|
+
nextPartial === null
|
|
479
|
+
? baseState
|
|
480
|
+
: {
|
|
481
|
+
...baseState,
|
|
482
|
+
...nextPartial,
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
classLifecycleSnapshots.set(instance, {
|
|
486
|
+
...snapshot,
|
|
487
|
+
previousState,
|
|
488
|
+
nextState,
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
markClassInstanceDirty(updateContext);
|
|
492
|
+
callback?.call(instance);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function enqueueClassForceUpdate(
|
|
496
|
+
instance: ClassComponentInstance,
|
|
497
|
+
callback?: () => void,
|
|
498
|
+
): void {
|
|
499
|
+
const updateContext = classUpdateContexts.get(instance);
|
|
500
|
+
|
|
501
|
+
if (updateContext === undefined) {
|
|
359
502
|
callback?.call(instance);
|
|
360
|
-
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
classLifecycleSnapshots.set(instance, {
|
|
507
|
+
previousState: instance.state ?? {},
|
|
508
|
+
force: true,
|
|
509
|
+
});
|
|
510
|
+
markClassInstanceDirty(updateContext);
|
|
511
|
+
callback?.call(instance);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function markClassInstanceDirty(updateContext: ClassUpdateContext): void {
|
|
515
|
+
const runtimeInstance = updateContext.runtime.instances.get(updateContext.path) as
|
|
516
|
+
| { dirty?: boolean }
|
|
517
|
+
| undefined;
|
|
518
|
+
if (runtimeInstance !== undefined) {
|
|
519
|
+
runtimeInstance.dirty = true;
|
|
520
|
+
}
|
|
521
|
+
updateContext.runtime.rerender();
|
|
361
522
|
}
|
|
362
523
|
|
|
363
524
|
function installClassLifecycleEffects(
|
|
@@ -369,7 +530,10 @@ function installClassLifecycleEffects(
|
|
|
369
530
|
replacedInstance?: ClassComponentInstance,
|
|
370
531
|
): void {
|
|
371
532
|
useLayoutEffect(() => {
|
|
372
|
-
replacedInstance
|
|
533
|
+
if (replacedInstance !== undefined) {
|
|
534
|
+
replacedInstance.componentWillUnmount?.();
|
|
535
|
+
classUpdateContexts.delete(replacedInstance);
|
|
536
|
+
}
|
|
373
537
|
|
|
374
538
|
if (skipUpdate) {
|
|
375
539
|
classLifecycleSnapshots.delete(instance);
|
|
@@ -394,6 +558,7 @@ function installClassLifecycleEffects(
|
|
|
394
558
|
return () => {
|
|
395
559
|
instance.componentWillUnmount?.();
|
|
396
560
|
classLifecycleSnapshots.delete(instance);
|
|
561
|
+
classUpdateContexts.delete(instance);
|
|
397
562
|
};
|
|
398
563
|
}, []);
|
|
399
564
|
}
|
package/src/context.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const REACT_COMPAT_PROVIDER_TYPE = Symbol.for("
|
|
2
|
-
const REACT_COMPAT_CONSUMER_TYPE = Symbol.for("
|
|
1
|
+
const REACT_COMPAT_PROVIDER_TYPE = Symbol.for("react.context");
|
|
2
|
+
const REACT_COMPAT_CONSUMER_TYPE = Symbol.for("react.consumer");
|
|
3
3
|
|
|
4
4
|
export interface ReactCompatContext<T> {
|
|
5
5
|
defaultValue: T;
|
|
@@ -9,18 +9,50 @@ export interface ReactCompatContext<T> {
|
|
|
9
9
|
displayName: string | undefined;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
export interface ReactCompatExternalContext<T> {
|
|
13
|
+
$$typeof: typeof REACT_COMPAT_PROVIDER_TYPE;
|
|
14
|
+
_currentValue?: T;
|
|
15
|
+
_currentValue2?: T;
|
|
16
|
+
_defaultValue?: T;
|
|
17
|
+
Provider?: unknown;
|
|
18
|
+
Consumer?: unknown;
|
|
19
|
+
displayName?: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type ReactCompatContextLike<T> =
|
|
23
|
+
| ReactCompatContext<T>
|
|
24
|
+
| ReactCompatExternalContext<T>;
|
|
25
|
+
|
|
12
26
|
export interface ReactCompatProvider<T> {
|
|
13
27
|
$$typeof: typeof REACT_COMPAT_PROVIDER_TYPE;
|
|
14
|
-
context
|
|
28
|
+
context?: ReactCompatContextLike<T>;
|
|
15
29
|
displayName: string | undefined;
|
|
16
30
|
}
|
|
17
31
|
|
|
18
32
|
export interface ReactCompatConsumer<T> {
|
|
19
33
|
$$typeof: typeof REACT_COMPAT_CONSUMER_TYPE;
|
|
20
|
-
context
|
|
34
|
+
context?: ReactCompatContextLike<T>;
|
|
35
|
+
_context?: ReactCompatContextLike<T>;
|
|
21
36
|
displayName: string | undefined;
|
|
22
37
|
}
|
|
23
38
|
|
|
39
|
+
type ContextReadObserver = (context: ReactCompatContextLike<unknown>, value: unknown) => void;
|
|
40
|
+
interface ContextReadObserverState {
|
|
41
|
+
current: ContextReadObserver | undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const externalContextValues = new WeakMap<object, unknown[]>();
|
|
45
|
+
|
|
46
|
+
const CONTEXT_READ_OBSERVER_STATE_KEY = Symbol.for(
|
|
47
|
+
"modular.react.context_read_observer_state",
|
|
48
|
+
);
|
|
49
|
+
const contextReadObserverState =
|
|
50
|
+
((globalThis as typeof globalThis & Record<symbol, ContextReadObserverState | undefined>)[
|
|
51
|
+
CONTEXT_READ_OBSERVER_STATE_KEY
|
|
52
|
+
] ??= {
|
|
53
|
+
current: undefined,
|
|
54
|
+
});
|
|
55
|
+
|
|
24
56
|
export function createContext<T>(defaultValue: T): ReactCompatContext<T> {
|
|
25
57
|
const context: ReactCompatContext<T> = {
|
|
26
58
|
defaultValue,
|
|
@@ -62,8 +94,37 @@ function installContextDisplayName<T>(context: ReactCompatContext<T>): void {
|
|
|
62
94
|
});
|
|
63
95
|
}
|
|
64
96
|
|
|
65
|
-
export function useContext<T>(context:
|
|
66
|
-
|
|
97
|
+
export function useContext<T>(context: ReactCompatContextLike<T>): T {
|
|
98
|
+
const value = readContextValue(context);
|
|
99
|
+
contextReadObserverState.current?.(context as ReactCompatContextLike<unknown>, value);
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function readContextValue<T>(context: ReactCompatContextLike<T>): T {
|
|
104
|
+
if (isInternalContextRecord(context)) {
|
|
105
|
+
return context.values.at(-1) ?? context.defaultValue;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
(externalContextValues.get(context)?.at(-1) as T | undefined) ??
|
|
110
|
+
context._currentValue ??
|
|
111
|
+
context._currentValue2 ??
|
|
112
|
+
(context._defaultValue as T)
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function withContextReadObserver<T>(
|
|
117
|
+
observer: ContextReadObserver,
|
|
118
|
+
render: () => T,
|
|
119
|
+
): T {
|
|
120
|
+
const previousObserver = contextReadObserverState.current;
|
|
121
|
+
contextReadObserverState.current = observer;
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
return render();
|
|
125
|
+
} finally {
|
|
126
|
+
contextReadObserverState.current = previousObserver;
|
|
127
|
+
}
|
|
67
128
|
}
|
|
68
129
|
|
|
69
130
|
export function isReactCompatProvider(
|
|
@@ -117,11 +178,27 @@ export function pushContextProvider<T>(
|
|
|
117
178
|
provider: ReactCompatProvider<T>,
|
|
118
179
|
value: T,
|
|
119
180
|
): void {
|
|
120
|
-
|
|
181
|
+
const context = providerContext(provider);
|
|
182
|
+
|
|
183
|
+
if (isInternalContextRecord(context)) {
|
|
184
|
+
context.values.push(value);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const values = externalContextValues.get(context) ?? [];
|
|
189
|
+
values.push(value);
|
|
190
|
+
externalContextValues.set(context, values);
|
|
121
191
|
}
|
|
122
192
|
|
|
123
193
|
export function popContextProvider<T>(provider: ReactCompatProvider<T>): void {
|
|
124
|
-
|
|
194
|
+
const context = providerContext(provider);
|
|
195
|
+
|
|
196
|
+
if (isInternalContextRecord(context)) {
|
|
197
|
+
context.values.pop();
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
externalContextValues.get(context)?.pop();
|
|
125
202
|
}
|
|
126
203
|
|
|
127
204
|
export function renderContextProviderToString<T>(
|
|
@@ -136,5 +213,27 @@ export function renderContextConsumerToString<T>(
|
|
|
136
213
|
consumer: ReactCompatConsumer<T>,
|
|
137
214
|
render: (value: T) => string,
|
|
138
215
|
): string {
|
|
139
|
-
return render(useContext(consumer
|
|
216
|
+
return render(useContext(consumerContext(consumer)));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export function providerContext<T>(
|
|
220
|
+
provider: ReactCompatProvider<T>,
|
|
221
|
+
): ReactCompatContextLike<T> {
|
|
222
|
+
return provider.context ?? (provider as unknown as ReactCompatExternalContext<T>);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function consumerContext<T>(
|
|
226
|
+
consumer: ReactCompatConsumer<T>,
|
|
227
|
+
): ReactCompatContextLike<T> {
|
|
228
|
+
return (
|
|
229
|
+
consumer.context ??
|
|
230
|
+
consumer._context ??
|
|
231
|
+
(consumer as unknown as ReactCompatExternalContext<T>)
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function isInternalContextRecord<T>(
|
|
236
|
+
context: ReactCompatContextLike<T>,
|
|
237
|
+
): context is ReactCompatContext<T> {
|
|
238
|
+
return "values" in context && Array.isArray(context.values);
|
|
140
239
|
}
|