@reckona/mreact-compat 0.0.91 → 0.0.93

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.
Files changed (104) hide show
  1. package/README.md +1 -0
  2. package/dist/class-component.d.ts +22 -6
  3. package/dist/class-component.d.ts.map +1 -1
  4. package/dist/class-component.js +157 -51
  5. package/dist/class-component.js.map +1 -1
  6. package/dist/context.d.ts +19 -3
  7. package/dist/context.d.ts.map +1 -1
  8. package/dist/context.js +55 -6
  9. package/dist/context.js.map +1 -1
  10. package/dist/dom-children.d.ts +2 -0
  11. package/dist/dom-children.d.ts.map +1 -1
  12. package/dist/dom-children.js +103 -1
  13. package/dist/dom-children.js.map +1 -1
  14. package/dist/dom-host-rules.d.ts +10 -0
  15. package/dist/dom-host-rules.d.ts.map +1 -0
  16. package/dist/dom-host-rules.js +86 -0
  17. package/dist/dom-host-rules.js.map +1 -0
  18. package/dist/dom-props.d.ts +3 -2
  19. package/dist/dom-props.d.ts.map +1 -1
  20. package/dist/dom-props.js +229 -33
  21. package/dist/dom-props.js.map +1 -1
  22. package/dist/element.d.ts +9 -4
  23. package/dist/element.d.ts.map +1 -1
  24. package/dist/element.js +101 -26
  25. package/dist/element.js.map +1 -1
  26. package/dist/event-listeners.d.ts +4 -4
  27. package/dist/event-listeners.d.ts.map +1 -1
  28. package/dist/event-listeners.js +1 -1
  29. package/dist/event-listeners.js.map +1 -1
  30. package/dist/event-types.d.ts +10 -0
  31. package/dist/event-types.d.ts.map +1 -1
  32. package/dist/event-types.js.map +1 -1
  33. package/dist/events.js +22 -1
  34. package/dist/events.js.map +1 -1
  35. package/dist/fiber-commit.d.ts +2 -1
  36. package/dist/fiber-commit.d.ts.map +1 -1
  37. package/dist/fiber-commit.js +13 -1
  38. package/dist/fiber-commit.js.map +1 -1
  39. package/dist/fiber-reconciler.d.ts.map +1 -1
  40. package/dist/fiber-reconciler.js +28 -7
  41. package/dist/fiber-reconciler.js.map +1 -1
  42. package/dist/fiber-work-loop.d.ts.map +1 -1
  43. package/dist/fiber-work-loop.js +4 -3
  44. package/dist/fiber-work-loop.js.map +1 -1
  45. package/dist/fiber.d.ts +5 -0
  46. package/dist/fiber.d.ts.map +1 -1
  47. package/dist/fiber.js +9 -0
  48. package/dist/fiber.js.map +1 -1
  49. package/dist/hooks-entry.d.ts +3 -0
  50. package/dist/hooks-entry.d.ts.map +1 -0
  51. package/dist/hooks-entry.js +2 -0
  52. package/dist/hooks-entry.js.map +1 -0
  53. package/dist/hooks.d.ts +39 -5
  54. package/dist/hooks.d.ts.map +1 -1
  55. package/dist/hooks.js +373 -326
  56. package/dist/hooks.js.map +1 -1
  57. package/dist/host-reconciler.d.ts +3 -0
  58. package/dist/host-reconciler.d.ts.map +1 -1
  59. package/dist/host-reconciler.js +1183 -68
  60. package/dist/host-reconciler.js.map +1 -1
  61. package/dist/hydration.d.ts +1 -1
  62. package/dist/hydration.d.ts.map +1 -1
  63. package/dist/hydration.js.map +1 -1
  64. package/dist/index.d.ts +2 -1
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +2 -1
  67. package/dist/index.js.map +1 -1
  68. package/dist/react-default.d.ts +4 -4
  69. package/dist/react-default.d.ts.map +1 -1
  70. package/dist/react-default.js +2 -1
  71. package/dist/react-default.js.map +1 -1
  72. package/dist/reconciler.d.ts.map +1 -1
  73. package/dist/reconciler.js +38 -22
  74. package/dist/reconciler.js.map +1 -1
  75. package/dist/root.d.ts.map +1 -1
  76. package/dist/root.js +48 -13
  77. package/dist/root.js.map +1 -1
  78. package/dist/server-render.d.ts +6 -0
  79. package/dist/server-render.d.ts.map +1 -0
  80. package/dist/server-render.js +307 -0
  81. package/dist/server-render.js.map +1 -0
  82. package/package.json +6 -2
  83. package/src/class-component.ts +313 -51
  84. package/src/context.ts +108 -9
  85. package/src/dom-children.ts +155 -1
  86. package/src/dom-host-rules.ts +115 -0
  87. package/src/dom-props.ts +297 -46
  88. package/src/element.ts +141 -31
  89. package/src/event-listeners.ts +6 -6
  90. package/src/event-types.ts +10 -0
  91. package/src/events.ts +32 -10
  92. package/src/fiber-commit.ts +16 -1
  93. package/src/fiber-reconciler.ts +39 -6
  94. package/src/fiber-work-loop.ts +4 -3
  95. package/src/fiber.ts +14 -0
  96. package/src/hooks-entry.ts +24 -0
  97. package/src/hooks.ts +482 -479
  98. package/src/host-reconciler.ts +1662 -83
  99. package/src/hydration.ts +1 -1
  100. package/src/index.ts +1 -1
  101. package/src/react-default.ts +1 -1
  102. package/src/reconciler.ts +61 -22
  103. package/src/root.ts +55 -12
  104. package/src/server-render.ts +478 -0
package/src/element.ts CHANGED
@@ -1,16 +1,18 @@
1
- export const REACT_COMPAT_ELEMENT_TYPE = Symbol.for("modular.react.element");
1
+ export const REACT_COMPAT_ELEMENT_TYPE = Symbol.for("react.transitional.element");
2
2
  export const ERROR_BOUNDARY_TYPE = Symbol.for("modular.react.error_boundary");
3
- export const FORWARD_REF_TYPE = Symbol.for("modular.react.forward_ref");
4
- export const MEMO_TYPE = Symbol.for("modular.react.memo");
5
- export const LAZY_TYPE = Symbol.for("modular.react.lazy");
6
- export const STRICT_MODE_TYPE = Symbol.for("modular.react.strict_mode");
7
- export const PORTAL_TYPE = Symbol.for("modular.react.portal");
8
- const REACT_COMPAT_PROVIDER_TYPE = Symbol.for("modular.react.provider");
9
- export const Fragment = Symbol.for("modular.react.fragment");
10
- export const Suspense = Symbol.for("modular.react.suspense");
11
- export const SuspenseList = Symbol.for("modular.react.suspense_list");
12
- export const Activity = Symbol.for("modular.react.activity");
13
- export const Profiler = Symbol.for("modular.react.profiler");
3
+ export const FORWARD_REF_TYPE = Symbol.for("react.forward_ref");
4
+ export const MEMO_TYPE = Symbol.for("react.memo");
5
+ export const LAZY_TYPE = Symbol.for("react.lazy");
6
+ export const STRICT_MODE_TYPE = Symbol.for("react.strict_mode");
7
+ export const PORTAL_TYPE = Symbol.for("react.portal");
8
+ const REACT_COMPAT_PROVIDER_TYPE = Symbol.for("react.context");
9
+ export const Fragment = Symbol.for("react.fragment");
10
+ export const Suspense = Symbol.for("react.suspense");
11
+ export const SuspenseList = Symbol.for("react.suspense_list");
12
+ export const Activity = Symbol.for("react.activity");
13
+ export const Profiler = Symbol.for("react.profiler");
14
+ export const HOST_OWN_PROPS_META = Symbol.for("modular.react.host_own_props_meta");
15
+ const hasOwnProperty = Object.prototype.hasOwnProperty;
14
16
 
15
17
  export interface ReactCompatProviderType {
16
18
  $$typeof: symbol;
@@ -66,20 +68,38 @@ export interface ReactCompatPortal {
66
68
 
67
69
  export function createElement<P extends Record<string, unknown>>(
68
70
  type: ElementType<P>,
69
- config: (P & { key?: unknown; ref?: unknown }) | null,
71
+ config: (P & ReactReservedProps) | null,
70
72
  ...children: ReactCompatNode[]
71
73
  ): ReactCompatElement<P> {
72
- const normalizedType = normalizeElementType(type);
73
- const props = applyDefaultProps(normalizedType, { ...config }) as P & {
74
+ if (typeof type === "string") {
75
+ const key = config?.key === undefined ? null : String(config.key);
76
+ const ref = config?.ref ?? null;
77
+ const props = copyElementProps(config) as P & { children?: ReactCompatNode };
78
+
79
+ if (children.length === 1) {
80
+ props.children = children[0];
81
+ } else if (children.length > 1) {
82
+ props.children = children;
83
+ }
84
+
85
+ setHostOwnPropsMeta(props);
86
+
87
+ return {
88
+ $$typeof: REACT_COMPAT_ELEMENT_TYPE,
89
+ type,
90
+ key,
91
+ ref,
92
+ props,
93
+ };
94
+ }
95
+
96
+ const normalizedType =
97
+ typeof type === "object" && type !== null ? normalizeElementType(type) : type;
98
+ const key = config?.key === undefined ? null : String(config.key);
99
+ const ref = config?.ref ?? null;
100
+ const props = applyDefaultProps(normalizedType, copyElementProps(config)) as P & {
74
101
  children?: ReactCompatNode;
75
- key?: unknown;
76
- ref?: unknown;
77
102
  };
78
- const key = props.key === undefined ? null : String(props.key);
79
- const ref = props.ref ?? null;
80
-
81
- delete props.key;
82
- delete props.ref;
83
103
 
84
104
  if (children.length === 1) {
85
105
  props.children = children[0];
@@ -87,6 +107,10 @@ export function createElement<P extends Record<string, unknown>>(
87
107
  props.children = children;
88
108
  }
89
109
 
110
+ if (typeof normalizedType === "string") {
111
+ setHostOwnPropsMeta(props);
112
+ }
113
+
90
114
  return {
91
115
  $$typeof: REACT_COMPAT_ELEMENT_TYPE,
92
116
  type: normalizedType as ElementType<P>,
@@ -183,15 +207,12 @@ export function cloneElement<P extends Record<string, unknown>>(
183
207
  props: Partial<P> | null,
184
208
  ...children: ReactCompatNode[]
185
209
  ): ReactCompatElement<P> {
186
- const nextProps = applyDefaultProps(element.type, {
187
- ...element.props,
188
- ...props,
189
- }) as P & { key?: unknown; ref?: unknown };
190
- const key = nextProps.key === undefined ? element.key : String(nextProps.key);
191
- const ref = nextProps.ref === undefined ? element.ref : nextProps.ref;
192
-
193
- delete nextProps.key;
194
- delete nextProps.ref;
210
+ const key = props === null || props.key === undefined ? element.key : String(props.key);
211
+ const ref = props === null || props.ref === undefined ? element.ref : props.ref;
212
+ const nextProps = applyDefaultProps(
213
+ element.type,
214
+ copyElementProps(props, element.props),
215
+ ) as P & { children?: ReactCompatNode };
195
216
 
196
217
  if (children.length === 1) {
197
218
  (nextProps as P & { children?: ReactCompatNode }).children = children[0];
@@ -208,6 +229,29 @@ export function cloneElement<P extends Record<string, unknown>>(
208
229
  };
209
230
  }
210
231
 
232
+ function copyElementProps(
233
+ source: Record<string, unknown> | null | undefined,
234
+ base?: Record<string, unknown>,
235
+ ): Record<string, unknown> {
236
+ const props: Record<string, unknown> = base === undefined ? {} : { ...base };
237
+
238
+ if (source === null || source === undefined) {
239
+ return props;
240
+ }
241
+
242
+ for (const name in source) {
243
+ if (!hasOwnProperty.call(source, name)) {
244
+ continue;
245
+ }
246
+
247
+ if (name !== "key" && name !== "ref" && name !== "__self" && name !== "__source") {
248
+ props[name] = source[name];
249
+ }
250
+ }
251
+
252
+ return props;
253
+ }
254
+
211
255
  function normalizeElementType<P>(type: ElementType<P>): ElementType<P> {
212
256
  return isReactCompatContextProviderShorthand(type) ? (type.Provider as ElementType<P>) : type;
213
257
  }
@@ -216,6 +260,10 @@ function applyDefaultProps(
216
260
  type: unknown,
217
261
  props: Record<string, unknown>,
218
262
  ): Record<string, unknown> {
263
+ if (typeof type !== "function" && (typeof type !== "object" || type === null)) {
264
+ return props;
265
+ }
266
+
219
267
  const defaultProps = (type as { defaultProps?: Record<string, unknown> } | undefined)
220
268
  ?.defaultProps;
221
269
 
@@ -232,6 +280,13 @@ function applyDefaultProps(
232
280
  return props;
233
281
  }
234
282
 
283
+ interface ReactReservedProps {
284
+ key?: unknown;
285
+ ref?: unknown;
286
+ __self?: unknown;
287
+ __source?: unknown;
288
+ }
289
+
235
290
  function isReactCompatContextProviderShorthand(
236
291
  value: unknown,
237
292
  ): value is ReactCompatContextProviderShorthand {
@@ -248,6 +303,61 @@ function isReactCompatContextProviderShorthand(
248
303
  );
249
304
  }
250
305
 
306
+ function setHostOwnPropsMeta(props: Record<string, unknown>): void {
307
+ const dataKey = props["data-key"];
308
+
309
+ if (typeof dataKey !== "number" || !Number.isSafeInteger(dataKey) || dataKey < 0) {
310
+ return;
311
+ }
312
+
313
+ let selectedState = 0;
314
+
315
+ for (const name in props) {
316
+ if (!hasOwnProperty.call(props, name) || name === "children") {
317
+ continue;
318
+ }
319
+
320
+ if (name === "data-key") {
321
+ continue;
322
+ }
323
+
324
+ if (name === "className") {
325
+ const value = props[name];
326
+
327
+ if (value === undefined) {
328
+ continue;
329
+ }
330
+
331
+ if (value !== "selected") {
332
+ return;
333
+ }
334
+
335
+ selectedState |= 1;
336
+ continue;
337
+ }
338
+
339
+ if (name === "data-selected") {
340
+ const value = props[name];
341
+
342
+ if (value === undefined) {
343
+ continue;
344
+ }
345
+
346
+ if (value !== "true") {
347
+ return;
348
+ }
349
+
350
+ selectedState |= 2;
351
+ continue;
352
+ }
353
+
354
+ return;
355
+ }
356
+
357
+ (props as { [HOST_OWN_PROPS_META]?: number })[HOST_OWN_PROPS_META] =
358
+ dataKey * 4 + selectedState;
359
+ }
360
+
251
361
  export const isValidElement = isReactCompatElement;
252
362
 
253
363
  export const Children = {
@@ -2,26 +2,26 @@ import type { SyntheticEvent } from "./event-types.js";
2
2
 
3
3
  export interface AppliedProps {
4
4
  props: Record<string, unknown>;
5
- listeners: Map<string, AppliedEventListener>;
5
+ listeners?: Map<string, AppliedEventListener>;
6
6
  }
7
7
 
8
8
  export interface AppliedEventListener {
9
9
  handler: (event: SyntheticEvent) => void;
10
10
  }
11
11
 
12
- const appliedProps = new WeakMap<HTMLElement, AppliedProps>();
12
+ const appliedProps = new WeakMap<Element, AppliedProps>();
13
13
 
14
- export function getAppliedProps(element: HTMLElement): AppliedProps | undefined {
14
+ export function getAppliedProps(element: Element): AppliedProps | undefined {
15
15
  return appliedProps.get(element);
16
16
  }
17
17
 
18
- export function setAppliedProps(element: HTMLElement, props: AppliedProps): void {
18
+ export function setAppliedProps(element: Element, props: AppliedProps): void {
19
19
  appliedProps.set(element, props);
20
20
  }
21
21
 
22
22
  export function getAppliedEventHandler(
23
- element: HTMLElement,
23
+ element: Element,
24
24
  name: string,
25
25
  ): ((event: SyntheticEvent) => void) | undefined {
26
- return appliedProps.get(element)?.listeners.get(name)?.handler;
26
+ return appliedProps.get(element)?.listeners?.get(name)?.handler;
27
27
  }
@@ -9,6 +9,16 @@ export interface SyntheticEvent {
9
9
  type: string;
10
10
  target: EventTarget | null;
11
11
  currentTarget: EventTarget | null;
12
+ clientX?: number;
13
+ clientY?: number;
14
+ pageX?: number;
15
+ pageY?: number;
16
+ screenX?: number;
17
+ screenY?: number;
18
+ relatedTarget?: EventTarget | null;
19
+ touches?: TouchList;
20
+ changedTouches?: TouchList;
21
+ key?: string;
12
22
  persist(): void;
13
23
  preventDefault(): void;
14
24
  stopPropagation(): void;
package/src/events.ts CHANGED
@@ -193,7 +193,7 @@ function dispatchDelegatedEvent(
193
193
  };
194
194
 
195
195
  for (let index = path.length - 1; index >= 0; index -= 1) {
196
- const target = path[index] as HTMLElement;
196
+ const target = path[index]!;
197
197
  dispatchEventPropNames(propNames, "capture", event, target, state);
198
198
 
199
199
  if (state.propagationStopped) {
@@ -203,7 +203,7 @@ function dispatchDelegatedEvent(
203
203
 
204
204
  if (eventName === "mouseover") {
205
205
  for (let index = path.length - 1; index >= 0; index -= 1) {
206
- const target = path[index] as HTMLElement;
206
+ const target = path[index]!;
207
207
  dispatchMouseTransitionEvent("onMouseEnter", event, target, state);
208
208
 
209
209
  if (state.propagationStopped) {
@@ -224,7 +224,7 @@ function dispatchDelegatedEvent(
224
224
 
225
225
  if (eventName === "pointerover") {
226
226
  for (let index = path.length - 1; index >= 0; index -= 1) {
227
- const target = path[index] as HTMLElement;
227
+ const target = path[index]!;
228
228
  dispatchPointerTransitionEvent("onPointerEnter", event, target, state);
229
229
 
230
230
  if (state.propagationStopped) {
@@ -255,7 +255,7 @@ function dispatchDelegatedEvent(
255
255
  function dispatchPointerTransitionEvent(
256
256
  propName: "onPointerEnter" | "onPointerLeave",
257
257
  event: Event,
258
- target: HTMLElement,
258
+ target: Element,
259
259
  state: { defaultPrevented: boolean; propagationStopped: boolean },
260
260
  ): void {
261
261
  if (isInternalMouseTransition(event, target)) {
@@ -273,7 +273,7 @@ function dispatchEventPropNames(
273
273
  propNames: readonly string[],
274
274
  phase: "capture" | "bubble",
275
275
  event: Event,
276
- target: HTMLElement,
276
+ target: Element,
277
277
  state: { defaultPrevented: boolean; propagationStopped: boolean },
278
278
  ): void {
279
279
  for (const propName of propNames) {
@@ -293,7 +293,7 @@ function dispatchEventPropNames(
293
293
  function dispatchMouseTransitionEvent(
294
294
  propName: "onMouseEnter" | "onMouseLeave",
295
295
  event: Event,
296
- target: HTMLElement,
296
+ target: Element,
297
297
  state: { defaultPrevented: boolean; propagationStopped: boolean },
298
298
  ): void {
299
299
  if (isInternalMouseTransition(event, target)) {
@@ -307,7 +307,7 @@ function dispatchMouseTransitionEvent(
307
307
  }
308
308
  }
309
309
 
310
- function isInternalMouseTransition(event: Event, target: HTMLElement): boolean {
310
+ function isInternalMouseTransition(event: Event, target: Element): boolean {
311
311
  const relatedTarget =
312
312
  event instanceof MouseEvent && event.relatedTarget instanceof Node
313
313
  ? event.relatedTarget
@@ -316,12 +316,12 @@ function isInternalMouseTransition(event: Event, target: HTMLElement): boolean {
316
316
  return relatedTarget !== null && target.contains(relatedTarget);
317
317
  }
318
318
 
319
- function getEventPath(root: Element, event: Event): HTMLElement[] {
320
- const path: HTMLElement[] = [];
319
+ function getEventPath(root: Element, event: Event): Element[] {
320
+ const path: Element[] = [];
321
321
  let cursor = event.target instanceof Node ? event.target : null;
322
322
 
323
323
  while (cursor !== null) {
324
- if (cursor instanceof HTMLElement) {
324
+ if (cursor instanceof Element) {
325
325
  path.push(cursor);
326
326
  }
327
327
 
@@ -349,6 +349,10 @@ function createSyntheticEvent(
349
349
  },
350
350
  syntheticType = nativeEvent.type,
351
351
  ): SyntheticEvent {
352
+ const mouseEvent = nativeEvent instanceof MouseEvent ? nativeEvent : undefined;
353
+ const touchEvent = nativeEvent instanceof TouchEvent ? nativeEvent : undefined;
354
+ const keyboardEvent = nativeEvent instanceof KeyboardEvent ? nativeEvent : undefined;
355
+
352
356
  return {
353
357
  bubbles: nativeEvent.bubbles,
354
358
  cancelable: nativeEvent.cancelable,
@@ -362,6 +366,24 @@ function createSyntheticEvent(
362
366
  type: syntheticType,
363
367
  target: nativeEvent.target,
364
368
  currentTarget,
369
+ ...(mouseEvent === undefined
370
+ ? {}
371
+ : {
372
+ clientX: mouseEvent.clientX,
373
+ clientY: mouseEvent.clientY,
374
+ pageX: mouseEvent.pageX,
375
+ pageY: mouseEvent.pageY,
376
+ screenX: mouseEvent.screenX,
377
+ screenY: mouseEvent.screenY,
378
+ relatedTarget: mouseEvent.relatedTarget,
379
+ }),
380
+ ...(touchEvent === undefined
381
+ ? {}
382
+ : {
383
+ touches: touchEvent.touches,
384
+ changedTouches: touchEvent.changedTouches,
385
+ }),
386
+ ...(keyboardEvent === undefined ? {} : { key: keyboardEvent.key }),
365
387
  persist() {},
366
388
  preventDefault() {
367
389
  state.defaultPrevented = true;
@@ -1,6 +1,7 @@
1
1
  import type { Fiber, FiberRoot } from "./fiber.js";
2
2
  import { commitHostFiberRoot } from "./fiber-host.js";
3
3
  import { markRootFinished } from "./fiber-lanes.js";
4
+ import { runWithHostCommit } from "./hooks.js";
4
5
  import type { RenderOptions } from "./hydration.js";
5
6
 
6
7
  interface RefRecord {
@@ -18,7 +19,15 @@ export function commitFiberRoot(
18
19
  return;
19
20
  }
20
21
 
21
- cleanupDeletedRefs(root.current, finishedWork);
22
+ if (
23
+ root.refCleanupKnown !== true ||
24
+ root.current.hasRefSubtree ||
25
+ finishedWork.hasRefSubtree
26
+ ) {
27
+ runWithHostCommit(() => {
28
+ cleanupDeletedRefs(root.current, finishedWork);
29
+ });
30
+ }
22
31
  commitHostFiberRoot(root, finishedWork, options);
23
32
  root.current = finishedWork;
24
33
  root.current.stateNode = root;
@@ -29,6 +38,12 @@ export function commitFiberRoot(
29
38
  root.workInProgressRootRenderLanes = 0;
30
39
  }
31
40
 
41
+ export function detachFiberRefs(fiber: Fiber): void {
42
+ for (const record of collectRefRecords(fiber)) {
43
+ detachRef(record.ref);
44
+ }
45
+ }
46
+
32
47
  function cleanupDeletedRefs(previous: Fiber, next: Fiber): void {
33
48
  const nextRefs = new Set<unknown>();
34
49
 
@@ -14,6 +14,7 @@ import {
14
14
  type ReactCompatNode,
15
15
  } from "./element.js";
16
16
  import {
17
+ consumerContext,
17
18
  isReactCompatConsumer,
18
19
  isReactCompatProvider,
19
20
  popContextProvider,
@@ -27,12 +28,20 @@ import { DidCapture } from "./fiber-flags.js";
27
28
  import { mergeLanes, NoLanes } from "./fiber-lanes.js";
28
29
  import { isThenable } from "./thenable.js";
29
30
  import {
30
- applyDerivedStateFromProps,
31
31
  isClassComponentType,
32
+ resolveDerivedStateFromProps,
32
33
  type ClassComponentInstance,
33
34
  type ClassComponentType,
34
35
  } from "./class-component.js";
35
36
  import { areMemoPropsEqual } from "./prop-comparison.js";
37
+ import {
38
+ createHostElement,
39
+ hostElementMatches,
40
+ isHostElement,
41
+ namespaceForHostChildren,
42
+ namespaceForHostElement,
43
+ type HostNamespace,
44
+ } from "./dom-host-rules.js";
36
45
 
37
46
  interface ContextProviderFiberState {
38
47
  provider: ReactCompatProvider<unknown>;
@@ -159,7 +168,7 @@ export function beginWork(unit: Fiber): Fiber | undefined {
159
168
  return reconcileChildFibers(
160
169
  unit,
161
170
  unit.alternate?.child,
162
- render(useContext(unit.type.context)),
171
+ render(useContext(consumerContext(unit.type))),
163
172
  );
164
173
  }
165
174
 
@@ -288,13 +297,16 @@ export function completeWork(unit: Fiber): void {
288
297
 
289
298
  if (unit.tag === "host-component") {
290
299
  const current = unit.alternate;
300
+ const parentNamespace = parentHostNamespace(unit);
301
+ const elementNamespace = namespaceForHostElement(parentNamespace, String(unit.type));
291
302
 
292
303
  unit.stateNode =
293
304
  current?.tag === "host-component" &&
294
305
  current.type === unit.type &&
295
- current.stateNode instanceof HTMLElement
306
+ isHostElement(current.stateNode) &&
307
+ hostElementMatches(current.stateNode, String(unit.type), elementNamespace)
296
308
  ? current.stateNode
297
- : document.createElement(String(unit.type));
309
+ : createHostElement(document, String(unit.type), parentNamespace);
298
310
  return;
299
311
  }
300
312
 
@@ -308,6 +320,27 @@ export function completeWork(unit: Fiber): void {
308
320
  }
309
321
  }
310
322
 
323
+ function parentHostNamespace(unit: Fiber): HostNamespace {
324
+ const ancestors: string[] = [];
325
+ let current = unit.return;
326
+
327
+ while (current !== undefined) {
328
+ if (current.tag === "host-component" && typeof current.type === "string") {
329
+ ancestors.push(current.type);
330
+ }
331
+ current = current.return;
332
+ }
333
+
334
+ let namespace: HostNamespace = "html";
335
+ for (let index = ancestors.length - 1; index >= 0; index -= 1) {
336
+ const tagName = ancestors[index] ?? "";
337
+ const elementNamespace = namespaceForHostElement(namespace, tagName);
338
+ namespace = namespaceForHostChildren(elementNamespace, tagName);
339
+ }
340
+
341
+ return namespace;
342
+ }
343
+
311
344
  export function cleanupUnfinishedWork(unit: Fiber | undefined): void {
312
345
  if (unit === undefined) {
313
346
  return;
@@ -520,8 +553,7 @@ function beginClassComponent(
520
553
  : undefined;
521
554
  const instance = currentInstance ?? new type(nextProps);
522
555
  const previousState = instance.state ?? {};
523
- applyDerivedStateFromProps(type, instance, nextProps, previousState);
524
- const nextState = instance.state ?? {};
556
+ const nextState = resolveDerivedStateFromProps(type, nextProps, previousState);
525
557
 
526
558
  unit.stateNode = instance;
527
559
 
@@ -535,6 +567,7 @@ function beginClassComponent(
535
567
  }
536
568
 
537
569
  instance.props = nextProps;
570
+ instance.state = nextState;
538
571
  return reconcileChildFibers(unit, unit.alternate?.child, instance.render());
539
572
  }
540
573
 
@@ -177,9 +177,10 @@ export function performSyncWorkOnRoot(
177
177
  fallbackFinishedWork.lanes = lanes;
178
178
  fallbackFinishedWork.memoizedProps = { children: element };
179
179
  const committedWork = commit();
180
- const finishedWork = committedWork ?? fallbackFinishedWork;
181
- root.current = finishedWork;
182
- root.current.stateNode = root;
180
+ if (committedWork === undefined) {
181
+ root.current = fallbackFinishedWork;
182
+ root.current.stateNode = root;
183
+ }
183
184
  root.finishedWork = undefined;
184
185
  root.workInProgress = undefined;
185
186
  root.workInProgressRootRenderLanes = 0;
package/src/fiber.ts CHANGED
@@ -34,10 +34,14 @@ export interface Fiber {
34
34
  stateNode: unknown;
35
35
  flags: Flags;
36
36
  subtreeFlags: Flags;
37
+ childListChanged: boolean;
38
+ subtreeChildListChanged: boolean;
37
39
  deletions: Fiber[] | undefined;
38
40
  lanes: Lanes;
39
41
  childLanes: Lanes;
40
42
  hydrateExisting: boolean;
43
+ hasRefSubtree: boolean;
44
+ hostChildListChanged: boolean;
41
45
  }
42
46
 
43
47
  export interface FiberRoot {
@@ -55,6 +59,7 @@ export interface FiberRoot {
55
59
  workInProgressRootRenderLanes: Lanes;
56
60
  workInProgressElement: unknown;
57
61
  hydrationState: FiberHydrationState | undefined;
62
+ refCleanupKnown: boolean;
58
63
  }
59
64
 
60
65
  export interface FiberHydrationState {
@@ -84,10 +89,14 @@ export function createFiber(
84
89
  stateNode: undefined,
85
90
  flags: NoFlags,
86
91
  subtreeFlags: NoFlags,
92
+ childListChanged: false,
93
+ subtreeChildListChanged: false,
87
94
  deletions: undefined,
88
95
  lanes: NoLanes,
89
96
  childLanes: NoLanes,
90
97
  hydrateExisting: false,
98
+ hasRefSubtree: false,
99
+ hostChildListChanged: false,
91
100
  };
92
101
  }
93
102
 
@@ -112,6 +121,7 @@ export function createFiberRoot(container: Element): FiberRoot {
112
121
  workInProgressRootRenderLanes: NoLanes,
113
122
  workInProgressElement: undefined,
114
123
  hydrationState: undefined,
124
+ refCleanupKnown: false,
115
125
  };
116
126
  current.stateNode = root;
117
127
  return root;
@@ -133,6 +143,8 @@ export function createWorkInProgress(
133
143
  workInProgress.pendingProps = pendingProps;
134
144
  workInProgress.flags = NoFlags;
135
145
  workInProgress.subtreeFlags = NoFlags;
146
+ workInProgress.childListChanged = false;
147
+ workInProgress.subtreeChildListChanged = false;
136
148
  workInProgress.deletions = undefined;
137
149
  }
138
150
 
@@ -144,5 +156,7 @@ export function createWorkInProgress(
144
156
  workInProgress.lanes = current.lanes;
145
157
  workInProgress.childLanes = current.childLanes;
146
158
  workInProgress.hydrateExisting = false;
159
+ workInProgress.hasRefSubtree = current.hasRefSubtree;
160
+ workInProgress.hostChildListChanged = current.hostChildListChanged;
147
161
  return workInProgress;
148
162
  }
@@ -0,0 +1,24 @@
1
+ export {
2
+ useCallback,
3
+ useDebugValue,
4
+ useDeferredValue,
5
+ useEffectEvent,
6
+ useEffect,
7
+ useId,
8
+ useImperativeHandle,
9
+ useInsertionEffect,
10
+ useLayoutEffect,
11
+ useMemo,
12
+ useOptimistic,
13
+ useReducer,
14
+ useRef,
15
+ useState,
16
+ useSyncExternalStore,
17
+ use,
18
+ useActionState,
19
+ startTransition,
20
+ unstable_useCacheRefresh,
21
+ useTransition,
22
+ version,
23
+ } from "./hooks.js";
24
+ export type { StartTransition, TransitionScope } from "./hooks.js";