@reckona/mreact-compat 0.0.159 → 0.0.161

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 (102) hide show
  1. package/dist/class-component.d.ts +5 -0
  2. package/dist/class-component.d.ts.map +1 -1
  3. package/dist/class-component.js +36 -11
  4. package/dist/class-component.js.map +1 -1
  5. package/dist/context.d.ts +4 -0
  6. package/dist/context.d.ts.map +1 -1
  7. package/dist/context.js +4 -0
  8. package/dist/context.js.map +1 -1
  9. package/dist/element.d.ts +28 -0
  10. package/dist/element.d.ts.map +1 -1
  11. package/dist/element.js +21 -1
  12. package/dist/element.js.map +1 -1
  13. package/dist/event-priority.d.ts +1 -0
  14. package/dist/event-priority.d.ts.map +1 -1
  15. package/dist/event-priority.js +1 -0
  16. package/dist/event-priority.js.map +1 -1
  17. package/dist/event-replay.d.ts +6 -0
  18. package/dist/event-replay.d.ts.map +1 -1
  19. package/dist/event-replay.js +4 -0
  20. package/dist/event-replay.js.map +1 -1
  21. package/dist/flight-decoder.d.ts +1 -0
  22. package/dist/flight-decoder.d.ts.map +1 -1
  23. package/dist/flight-decoder.js.map +1 -1
  24. package/dist/flight-protocol.d.ts +2 -0
  25. package/dist/flight-protocol.d.ts.map +1 -1
  26. package/dist/flight-protocol.js +1 -0
  27. package/dist/flight-protocol.js.map +1 -1
  28. package/dist/flight-types.d.ts +21 -0
  29. package/dist/flight-types.d.ts.map +1 -1
  30. package/dist/flight-types.js.map +1 -1
  31. package/dist/flight.d.ts +7 -0
  32. package/dist/flight.d.ts.map +1 -1
  33. package/dist/flight.js +5 -0
  34. package/dist/flight.js.map +1 -1
  35. package/dist/hooks-entry.d.ts +2 -0
  36. package/dist/hooks-entry.d.ts.map +1 -1
  37. package/dist/hooks-entry.js +1 -0
  38. package/dist/hooks-entry.js.map +1 -1
  39. package/dist/hooks.d.ts +36 -0
  40. package/dist/hooks.d.ts.map +1 -1
  41. package/dist/hooks.js +42 -10
  42. package/dist/hooks.js.map +1 -1
  43. package/dist/host-reconciler.js +30 -30
  44. package/dist/host-reconciler.js.map +1 -1
  45. package/dist/hydration.d.ts +2 -0
  46. package/dist/hydration.d.ts.map +1 -1
  47. package/dist/hydration.js +1 -0
  48. package/dist/hydration.js.map +1 -1
  49. package/dist/index.d.ts +3 -0
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +1 -0
  52. package/dist/index.js.map +1 -1
  53. package/dist/internal.d.ts +1 -0
  54. package/dist/internal.d.ts.map +1 -1
  55. package/dist/internal.js +1 -0
  56. package/dist/internal.js.map +1 -1
  57. package/dist/jsx-dev-runtime.d.ts +5 -0
  58. package/dist/jsx-dev-runtime.d.ts.map +1 -1
  59. package/dist/jsx-dev-runtime.js +3 -0
  60. package/dist/jsx-dev-runtime.js.map +1 -1
  61. package/dist/jsx-runtime.d.ts +13 -0
  62. package/dist/jsx-runtime.d.ts.map +1 -1
  63. package/dist/jsx-runtime.js +4 -0
  64. package/dist/jsx-runtime.js.map +1 -1
  65. package/dist/react-default.d.ts +2 -0
  66. package/dist/react-default.d.ts.map +1 -1
  67. package/dist/react-default.js +2 -0
  68. package/dist/react-default.js.map +1 -1
  69. package/dist/root.d.ts +13 -0
  70. package/dist/root.d.ts.map +1 -1
  71. package/dist/root.js +6 -0
  72. package/dist/root.js.map +1 -1
  73. package/dist/scheduler.d.ts +23 -0
  74. package/dist/scheduler.d.ts.map +1 -1
  75. package/dist/scheduler.js +19 -0
  76. package/dist/scheduler.js.map +1 -1
  77. package/dist/server-render.d.ts +1 -0
  78. package/dist/server-render.d.ts.map +1 -1
  79. package/dist/server-render.js +1 -0
  80. package/dist/server-render.js.map +1 -1
  81. package/package.json +3 -3
  82. package/src/class-component.ts +47 -11
  83. package/src/context.ts +4 -0
  84. package/src/element.ts +33 -6
  85. package/src/event-priority.ts +1 -0
  86. package/src/event-replay.ts +6 -0
  87. package/src/flight-decoder.ts +1 -0
  88. package/src/flight-protocol.ts +2 -0
  89. package/src/flight-types.ts +21 -0
  90. package/src/flight.ts +7 -0
  91. package/src/hooks-entry.ts +2 -0
  92. package/src/hooks.ts +55 -15
  93. package/src/host-reconciler.ts +39 -38
  94. package/src/hydration.ts +2 -0
  95. package/src/index.ts +3 -0
  96. package/src/internal.ts +1 -0
  97. package/src/jsx-dev-runtime.ts +5 -0
  98. package/src/jsx-runtime.ts +13 -0
  99. package/src/react-default.ts +2 -0
  100. package/src/root.ts +13 -0
  101. package/src/scheduler.ts +23 -0
  102. package/src/server-render.ts +1 -0
package/src/hooks.ts CHANGED
@@ -92,6 +92,7 @@ interface ExternalStoreCheck {
92
92
  value: unknown;
93
93
  }
94
94
 
95
+ /** Cache scope that stores memoized cache() results and cancellation state. */
95
96
  export interface CacheScope {
96
97
  functionCaches: WeakMap<(...args: never[]) => unknown, CacheTrieNode>;
97
98
  controller: AbortController;
@@ -194,6 +195,7 @@ let strictMemoOwnerId = 0;
194
195
  const strictMemoObjectOwnerIds = new WeakMap<object, number>();
195
196
  const queuedTransitionRerenders = new Map<RootRuntime, TransitionContext>();
196
197
  const queuedEventRerenders = new Set<RootRuntime>();
198
+ /** React version string matched by the compatibility layer. */
197
199
  export const version = "19.2.6";
198
200
 
199
201
  export interface ReactiveTextBinding {
@@ -204,6 +206,7 @@ export interface ReactiveTextBinding {
204
206
  const reactiveTextBindingsByNode = new WeakMap<Text, ReactiveTextBinding>();
205
207
  const hydratedIdsByRuntime = new WeakMap<RootRuntime, Map<string, string>>();
206
208
 
209
+ /** Flushes React-compatible updates produced inside a test interaction. */
207
210
  export function act<T>(callback: () => T): T extends PromiseLike<unknown> ? Promise<void> : void {
208
211
  const previousPriority = currentEventPriority;
209
212
  currentEventPriority = "discrete";
@@ -267,6 +270,7 @@ function flushActWork(): void {
267
270
  flushEffectFlushRerenders();
268
271
  }
269
272
 
273
+ /** Priority category used while batching an event callback. */
270
274
  export type EventPriority = "discrete" | "continuous" | "default";
271
275
  export type RenderPriority = "sync" | "transition" | "continuous";
272
276
 
@@ -406,6 +410,7 @@ export function createRootRuntime(
406
410
  };
407
411
  }
408
412
 
413
+ /** Creates an isolated cache scope for cache() and cacheSignal(). */
409
414
  export function createCacheScope(): CacheScope {
410
415
  return {
411
416
  functionCaches: new WeakMap(),
@@ -414,12 +419,14 @@ export function createCacheScope(): CacheScope {
414
419
  };
415
420
  }
416
421
 
422
+ /** Clears a cache scope and aborts work tied to its previous signal. */
417
423
  export function refreshCacheScope(scope: CacheScope): void {
418
424
  scope.controller.abort();
419
425
  scope.functionCaches = new WeakMap();
420
426
  scope.controller = new AbortController();
421
427
  }
422
428
 
429
+ /** Runs a callback with a cache scope active for nested cache() calls. */
423
430
  export function runWithCacheScope<T>(scope: CacheScope, callback: () => T): T {
424
431
  const previousScope = hookRenderState.currentCacheScope;
425
432
  const previousGlobalScope = getGlobalCacheScope();
@@ -756,6 +763,7 @@ function clonePortalNodes(source: Map<Element, Set<Node>>): Map<Element, Set<Nod
756
763
  return clone;
757
764
  }
758
765
 
766
+ /** Stores component-local state and returns the current value with an updater. */
759
767
  export function useState<T>(
760
768
  initial: T | (() => T),
761
769
  ): [T, (value: T | ((previous: T) => T)) => void] {
@@ -904,6 +912,7 @@ function isReactiveTextBinding(value: unknown): value is ReactiveTextBinding {
904
912
  );
905
913
  }
906
914
 
915
+ /** Stores reducer-managed component state and returns the current state with a dispatch function. */
907
916
  export function useReducer<TState, TAction, TInitial = TState>(
908
917
  reducer: (state: TState, action: TAction) => TState,
909
918
  initialArg: TInitial,
@@ -940,6 +949,7 @@ export function useReducer<TState, TAction, TInitial = TState>(
940
949
  return [state, dispatchRef.current];
941
950
  }
942
951
 
952
+ /** Returns a stable mutable ref object for the component instance. */
943
953
  export function useRef<T>(initial: T): { current: T } {
944
954
  const instance = requireInstance();
945
955
  const index = instance.hookIndex;
@@ -964,6 +974,7 @@ export function useRef<T>(initial: T): { current: T } {
964
974
  return slot.value as { current: T };
965
975
  }
966
976
 
977
+ /** Returns a stable id string that matches server and client rendering. */
967
978
  export function useId(): string {
968
979
  const runtime = requireRuntime();
969
980
  const instance = requireInstance();
@@ -1000,6 +1011,7 @@ export function useId(): string {
1000
1011
  return idRef.current;
1001
1012
  }
1002
1013
 
1014
+ /** Assigns a custom imperative handle to a forwarded ref. */
1003
1015
  export function useImperativeHandle<T>(
1004
1016
  ref: unknown,
1005
1017
  create: () => T,
@@ -1019,6 +1031,7 @@ export function useImperativeHandle<T>(
1019
1031
  : { kind: "imperative-handle", deps });
1020
1032
  }
1021
1033
 
1034
+ /** Memoizes a computed value until its dependency list changes. */
1022
1035
  export function useMemo<T>(factory: () => T, deps?: readonly unknown[]): T {
1023
1036
  const runtime = requireRuntime();
1024
1037
  const instance = requireInstance();
@@ -1159,6 +1172,7 @@ function runWithoutDevToolsHookTracking<T>(callback: () => T): T {
1159
1172
  }
1160
1173
  }
1161
1174
 
1175
+ /** Memoizes a callback reference until its dependency list changes. */
1162
1176
  export function useCallback<T extends (...args: never[]) => unknown>(
1163
1177
  callback: T,
1164
1178
  deps?: readonly unknown[],
@@ -1170,6 +1184,7 @@ export function useCallback<T extends (...args: never[]) => unknown>(
1170
1184
  return value;
1171
1185
  }
1172
1186
 
1187
+ /** Records a value for React DevTools hook inspection. */
1173
1188
  export function useDebugValue(_value: unknown, _format?: (value: unknown) => unknown): void {
1174
1189
  const instance = requireInstance();
1175
1190
  const index = instance.hookIndex;
@@ -1199,6 +1214,7 @@ export function useDebugValue(_value: unknown, _format?: (value: unknown) => unk
1199
1214
  });
1200
1215
  }
1201
1216
 
1217
+ /** Creates a stable event callback that always calls the latest implementation. */
1202
1218
  export function useEffectEvent<TArgs extends unknown[], TResult>(
1203
1219
  callback: (...args: TArgs) => TResult,
1204
1220
  ): (...args: TArgs) => TResult {
@@ -1216,6 +1232,7 @@ export function useEffectEvent<TArgs extends unknown[], TResult>(
1216
1232
  return event;
1217
1233
  }
1218
1234
 
1235
+ /** Runs an effect after the rendered output has been committed. */
1219
1236
  export function useEffect(
1220
1237
  callback: EffectCallback,
1221
1238
  deps?: readonly unknown[],
@@ -1226,6 +1243,7 @@ export function useEffect(
1226
1243
  : { kind: "effect", effectKind: "normal", deps });
1227
1244
  }
1228
1245
 
1246
+ /** Runs an insertion effect before layout effects are flushed. */
1229
1247
  export function useInsertionEffect(
1230
1248
  callback: EffectCallback,
1231
1249
  deps?: readonly unknown[],
@@ -1236,6 +1254,7 @@ export function useInsertionEffect(
1236
1254
  : { kind: "effect", effectKind: "insertion", deps });
1237
1255
  }
1238
1256
 
1257
+ /** Runs a layout effect after DOM mutations and before normal effects. */
1239
1258
  export function useLayoutEffect(
1240
1259
  callback: EffectCallback,
1241
1260
  deps?: readonly unknown[],
@@ -1246,6 +1265,7 @@ export function useLayoutEffect(
1246
1265
  : { kind: "effect", effectKind: "layout", deps });
1247
1266
  }
1248
1267
 
1268
+ /** Subscribes to an external store with snapshot checks for consistent rendering. */
1249
1269
  export function useSyncExternalStore<T>(
1250
1270
  subscribe: (listener: () => void) => () => void,
1251
1271
  getSnapshot: () => T,
@@ -1321,6 +1341,7 @@ export function useSyncExternalStore<T>(
1321
1341
  return slot.value as T;
1322
1342
  }
1323
1343
 
1344
+ /** Tracks state and pending status for an action that receives the previous state. */
1324
1345
  export function useActionState<TState, TPayload>(
1325
1346
  action: (previousState: TState, payload: TPayload) => TState | Promise<TState>,
1326
1347
  initialState: TState,
@@ -1369,6 +1390,7 @@ export function useActionState<TState, TPayload>(
1369
1390
  ];
1370
1391
  }
1371
1392
 
1393
+ /** Returns an optimistic state value and dispatcher layered on top of a base state. */
1372
1394
  export function useOptimistic<TState, TPayload>(
1373
1395
  state: TState,
1374
1396
  update?: (state: TState, payload: TPayload) => TState,
@@ -1419,6 +1441,7 @@ export function useOptimistic<TState, TPayload>(
1419
1441
  return [slot.optimisticState as TState, slot.dispatch as (payload: TPayload) => void];
1420
1442
  }
1421
1443
 
1444
+ /** Reads a context-like value or suspends on a thenable until it resolves. */
1422
1445
  export function use<T>(usable: PromiseLike<T> | unknown): T {
1423
1446
  if (isReactCompatContext(usable)) {
1424
1447
  return useContext(usable) as T;
@@ -1431,6 +1454,7 @@ export function use<T>(usable: PromiseLike<T> | unknown): T {
1431
1454
  return usable as T;
1432
1455
  }
1433
1456
 
1457
+ /** Memoizes a function within the currently active cache scope. */
1434
1458
  export function cache<TArgs extends unknown[], TResult>(
1435
1459
  callback: (...args: TArgs) => TResult,
1436
1460
  ): (...args: TArgs) => TResult {
@@ -1464,15 +1488,18 @@ export function cache<TArgs extends unknown[], TResult>(
1464
1488
  };
1465
1489
  }
1466
1490
 
1491
+ /** Returns the abort signal for the currently active cache scope. */
1467
1492
  export function cacheSignal(): AbortSignal | null {
1468
1493
  return getCurrentCacheScope()?.controller.signal ?? null;
1469
1494
  }
1470
1495
 
1496
+ /** Returns the current owner stack captured for cache diagnostics. */
1471
1497
  export function captureOwnerStack(): string | null {
1472
1498
  const stack = getCurrentCacheScope()?.ownerStack ?? emptyCacheOwnerStack;
1473
1499
  return stack.length === 0 ? null : stack.join("\n");
1474
1500
  }
1475
1501
 
1502
+ /** Returns a callback placeholder for refreshing the current cache boundary. */
1476
1503
  export function unstable_useCacheRefresh(): () => void {
1477
1504
  return useCallback(() => undefined, []);
1478
1505
  }
@@ -1521,9 +1548,12 @@ function readThenable<T>(thenable: PromiseLike<T>): T {
1521
1548
  throw thenable;
1522
1549
  }
1523
1550
 
1551
+ /** Callback body scheduled as transition work. */
1524
1552
  export type TransitionScope = () => void;
1553
+ /** Function that schedules a transition scope. */
1525
1554
  export type StartTransition = (scope: TransitionScope) => void;
1526
1555
 
1556
+ /** Schedules non-urgent updates produced inside a transition scope. */
1527
1557
  export function startTransition(scope: TransitionScope): void {
1528
1558
  const context = {
1529
1559
  syncVersion,
@@ -1533,6 +1563,7 @@ export function startTransition(scope: TransitionScope): void {
1533
1563
  runTransitionScope(scope, context);
1534
1564
  }
1535
1565
 
1566
+ /** Runs a callback while updates are batched at the requested event priority. */
1536
1567
  export function runWithEventPriority<T>(
1537
1568
  priority: EventPriority,
1538
1569
  callback: () => T,
@@ -1583,6 +1614,7 @@ export function runWithHostCommit<T>(callback: () => T): T {
1583
1614
  }
1584
1615
  }
1585
1616
 
1617
+ /** Returns transition pending state and a function that starts transition work. */
1586
1618
  export function useTransition(): [boolean, StartTransition] {
1587
1619
  const instance = requireInstance();
1588
1620
  const [pending, setPending] = runWithoutDevToolsHookTracking(() => useState(false));
@@ -1623,6 +1655,7 @@ export function useTransition(): [boolean, StartTransition] {
1623
1655
  ];
1624
1656
  }
1625
1657
 
1658
+ /** Defers a value update so urgent renders can commit first. */
1626
1659
  export function useDeferredValue<T>(value: T, initialValue?: T): T {
1627
1660
  const [deferredValue, setDeferredValue] = runWithoutDevToolsHookTracking(() =>
1628
1661
  useState(arguments.length > 1 ? (initialValue as T) : value)
@@ -1929,24 +1962,10 @@ function runActionStateDispatch(
1929
1962
  );
1930
1963
  }
1931
1964
 
1932
- function scheduleInstanceUpdate(
1965
+ export function scheduleRuntimeRerender(
1933
1966
  runtime: RootRuntime,
1934
- instance: ComponentInstance,
1935
1967
  options: { deferSync?: boolean } = {},
1936
1968
  ): void {
1937
- if (instance.disposed === true) {
1938
- return;
1939
- }
1940
-
1941
- instance.dirty = true;
1942
- if (
1943
- hookRenderState.currentRuntime === runtime &&
1944
- hookRenderState.currentInstance === instance
1945
- ) {
1946
- runtime.renderPhaseUpdate = true;
1947
- return;
1948
- }
1949
-
1950
1969
  if (transitionDepth === 0) {
1951
1970
  syncVersion += 1;
1952
1971
  if (hookRenderState.hostCommitDepth > 0) {
@@ -1974,6 +1993,27 @@ function scheduleInstanceUpdate(
1974
1993
  }
1975
1994
  }
1976
1995
 
1996
+ function scheduleInstanceUpdate(
1997
+ runtime: RootRuntime,
1998
+ instance: ComponentInstance,
1999
+ options: { deferSync?: boolean } = {},
2000
+ ): void {
2001
+ if (instance.disposed === true) {
2002
+ return;
2003
+ }
2004
+
2005
+ instance.dirty = true;
2006
+ if (
2007
+ hookRenderState.currentRuntime === runtime &&
2008
+ hookRenderState.currentInstance === instance
2009
+ ) {
2010
+ runtime.renderPhaseUpdate = true;
2011
+ return;
2012
+ }
2013
+
2014
+ scheduleRuntimeRerender(runtime, options);
2015
+ }
2016
+
1977
2017
  function flushHostCommitRerenders(): void {
1978
2018
  if (
1979
2019
  hookRenderState.hostCommitDepth > 0 ||
@@ -1207,7 +1207,7 @@ function createHostFiberImpl(
1207
1207
  areMemoPropsEqual(memoType, previousMemoState.props, node.props)
1208
1208
  ) {
1209
1209
  markActiveInstanceKeys(runtime, previousMemoState.instanceKeys);
1210
- fiber.child = current?.child;
1210
+ fiber.child = getSkippedChild(current);
1211
1211
  fiber.memoizedState = previousMemoState;
1212
1212
  return { fiber, consumed: options.previousNodes?.length ?? 0 };
1213
1213
  }
@@ -1317,6 +1317,8 @@ function createHostFiberImpl(
1317
1317
  current?.tag === "class-component" && current.type === classType
1318
1318
  ? (current.stateNode as ClassComponentInstance)
1319
1319
  : undefined;
1320
+ const hasCurrentClassFiber =
1321
+ current?.tag === "class-component" && current.type === classType;
1320
1322
  const rendered = renderClassComponentWithRuntime(
1321
1323
  classType,
1322
1324
  node.props,
@@ -1331,12 +1333,13 @@ function createHostFiberImpl(
1331
1333
  previousClassChildKeys,
1332
1334
  `${path}.class`,
1333
1335
  ),
1336
+ allowSkip: hasCurrentClassFiber,
1334
1337
  },
1335
1338
  );
1336
1339
  applyRef(node.ref, rendered.kind === "skip" ? current?.stateNode : rendered.instance);
1337
1340
 
1338
1341
  if (rendered.kind === "skip") {
1339
- fiber.child = current?.child;
1342
+ fiber.child = getSkippedChild(current);
1340
1343
  return { fiber, consumed: options.previousNodes?.length ?? 0 };
1341
1344
  }
1342
1345
 
@@ -1414,7 +1417,7 @@ function createHostFiberImpl(
1414
1417
  !hasPendingAsyncChild(current?.child)
1415
1418
  ) {
1416
1419
  markActiveInstanceKeys(runtime, previousFunctionState.instanceKeys);
1417
- fiber.child = current?.child;
1420
+ fiber.child = getSkippedChild(current);
1418
1421
  fiber.memoizedState = current?.memoizedState;
1419
1422
  fiber.stateNode = previousFunctionState;
1420
1423
  return { fiber, consumed: options.previousNodes?.length ?? 0 };
@@ -1651,6 +1654,18 @@ function commitHostDirtyFiber(
1651
1654
  if (directTextChild !== undefined) {
1652
1655
  const text = syncDirectHostTextChild(element, directTextChild);
1653
1656
  subscribeReactiveHostTextBinding(props, text);
1657
+ } else if (
1658
+ fiber.hostChildListChanged ||
1659
+ fiber.childListChanged ||
1660
+ fiber.subtreeChildListChanged
1661
+ ) {
1662
+ const childNodes = commitHostChildren(fiber.child, element, eventRoot, `${path}.c`, options);
1663
+ if (
1664
+ !(childNodes.length === 0 && committedPortalContainers.has(element)) &&
1665
+ !shouldPreserveContentEditableChildren(element, props, childNodes)
1666
+ ) {
1667
+ syncChildNodes(element, childNodes);
1668
+ }
1654
1669
  } else if (fiber.subtreeFlags !== NoFlags) {
1655
1670
  commitHostDirtyChildren(fiber.child, element, eventRoot, `${path}.c`, options);
1656
1671
  }
@@ -1793,7 +1808,7 @@ function commitHostAppendSuffix(
1793
1808
  path: string,
1794
1809
  options: RenderOptions,
1795
1810
  ): boolean {
1796
- const append = getPlacementAppendSuffix(fiber.child) ?? getAppendSuffix(fiber.alternate?.child, fiber.child);
1811
+ const append = getAppendSuffix(fiber.alternate?.child, fiber.child);
1797
1812
 
1798
1813
  if (append === undefined) {
1799
1814
  return false;
@@ -1813,39 +1828,6 @@ function commitHostAppendSuffix(
1813
1828
  return true;
1814
1829
  }
1815
1830
 
1816
- function getPlacementAppendSuffix(next: Fiber | undefined): { fiber: Fiber; index: number } | undefined {
1817
- let nextCursor = next;
1818
- let index = 0;
1819
-
1820
- while (nextCursor !== undefined) {
1821
- if ((nextCursor.flags & Placement) !== NoFlags) {
1822
- if (index === 0) {
1823
- return undefined;
1824
- }
1825
-
1826
- let appendCursor: Fiber | undefined = nextCursor;
1827
-
1828
- while (appendCursor !== undefined) {
1829
- if ((appendCursor.flags & Placement) === NoFlags) {
1830
- return undefined;
1831
- }
1832
- appendCursor = appendCursor.sibling;
1833
- }
1834
-
1835
- return { fiber: nextCursor, index };
1836
- }
1837
-
1838
- if (hasHostCommitWork(nextCursor)) {
1839
- return undefined;
1840
- }
1841
-
1842
- nextCursor = nextCursor.sibling;
1843
- index += 1;
1844
- }
1845
-
1846
- return undefined;
1847
- }
1848
-
1849
1831
  function commitHostSingleRemoval(fiber: Fiber, parent: ParentNode): boolean {
1850
1832
  const removed = getSingleRemovedFiber(fiber.alternate?.child, fiber.child);
1851
1833
 
@@ -1959,6 +1941,22 @@ function collectCommittedHostNodes(fiber: Fiber): Node[] {
1959
1941
  return nodes;
1960
1942
  }
1961
1943
 
1944
+ function getSkippedChild(current: Fiber | undefined): Fiber | undefined {
1945
+ const child = current?.child;
1946
+ const alternateChild = current?.alternate?.child;
1947
+
1948
+ if (
1949
+ child !== undefined &&
1950
+ alternateChild !== undefined &&
1951
+ collectCommittedHostNodes(child).length === 0 &&
1952
+ collectCommittedHostNodes(alternateChild).length > 0
1953
+ ) {
1954
+ return alternateChild;
1955
+ }
1956
+
1957
+ return child;
1958
+ }
1959
+
1962
1960
  function finishHostPassthroughFiber(fiber: Fiber): void {
1963
1961
  fiber.memoizedProps = fiber.pendingProps;
1964
1962
  finishCommittedFiber(fiber);
@@ -2000,7 +1998,9 @@ function commitHostFiber(
2000
1998
  fiber.hydrateExisting !== true &&
2001
1999
  fiber.flags === NoFlags &&
2002
2000
  fiber.subtreeFlags === NoFlags &&
2003
- fiber.hostChildListChanged !== true
2001
+ fiber.hostChildListChanged !== true &&
2002
+ fiber.childListChanged !== true &&
2003
+ fiber.subtreeChildListChanged !== true
2004
2004
  ) {
2005
2005
  fiber.memoizedProps = fiber.pendingProps;
2006
2006
  return [element];
@@ -2045,6 +2045,7 @@ function commitHostFiber(
2045
2045
  } else if (
2046
2046
  fiber.hostChildListChanged ||
2047
2047
  fiber.childListChanged ||
2048
+ fiber.subtreeChildListChanged ||
2048
2049
  fiber.hydrateExisting === true ||
2049
2050
  (fiber.subtreeFlags & Placement) !== NoFlags
2050
2051
  ) {
package/src/hydration.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { ReactCompatNode } from "./element.js";
2
2
 
3
+ /** Details passed to recoverable hydration error callbacks. */
3
4
  export interface HydrationRecoverableErrorInfo {
4
5
  kind: "tag" | "text" | "attribute" | "node" | "suspense-server-error";
5
6
  path: string;
@@ -27,6 +28,7 @@ export interface HydrationScope {
27
28
  after: ChildNode | null;
28
29
  }
29
30
 
31
+ /** Applies streamed out-of-order hydration fragments to their placeholders. */
30
32
  export function applyStreamingHydrationFragments(
31
33
  root: ParentNode = document,
32
34
  ): void {
package/src/index.ts CHANGED
@@ -20,12 +20,14 @@ export {
20
20
  lazy,
21
21
  memo,
22
22
  } from "./element.js";
23
+ /** Element and node types exported by the React-compatible root entrypoint. */
23
24
  export type {
24
25
  ErrorBoundaryOptions,
25
26
  ElementType,
26
27
  ReactCompatElement,
27
28
  ReactCompatNode,
28
29
  } from "./element.js";
30
+ /** DOM and form event types exported by the JSX runtime. */
29
31
  export type {
30
32
  FormEvent,
31
33
  FormEventHandler,
@@ -93,4 +95,5 @@ export {
93
95
  } from "./hooks.js";
94
96
  export { renderChildToString, renderToString } from "./server-render.js";
95
97
  export type { StartTransition, TransitionScope } from "./hooks.js";
98
+ /** Default React-compatible namespace export. */
96
99
  export { default } from "./react-default.js";
package/src/internal.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /** Internal cache-scope and event-priority helpers used by compat integrations. */
1
2
  export {
2
3
  createCacheScope,
3
4
  refreshCacheScope,
@@ -13,8 +13,11 @@ import type {
13
13
  JSXIntrinsicElements,
14
14
  } from "./jsx-runtime.js";
15
15
 
16
+ /** Fragment marker used by the development JSX runtime. */
16
17
  export { Fragment };
18
+ /** Metadata key used by compiled JSX for reactive text bindings. */
17
19
  export { REACTIVE_TEXT_BINDING_META };
20
+ /** JSX event and attribute types re-exported by the development JSX runtime. */
18
21
  export type {
19
22
  FormEvent,
20
23
  FormEventHandler,
@@ -25,6 +28,7 @@ export type {
25
28
  JSXIntrinsicElements,
26
29
  } from "./jsx-runtime.js";
27
30
 
31
+ /** JSX namespace exported by the development JSX runtime. */
28
32
  export namespace JSX {
29
33
  export interface Element extends ReactCompatElement {}
30
34
 
@@ -33,6 +37,7 @@ export namespace JSX {
33
37
  export interface IntrinsicElements extends JSXIntrinsicElements {}
34
38
  }
35
39
 
40
+ /** Creates a JSX element with development metadata arguments. */
36
41
  export function jsxDEV<P extends Record<string, unknown>>(
37
42
  type: ElementType<P>,
38
43
  props: (P & { children?: ReactCompatNode; key?: unknown; ref?: unknown }) | null,
@@ -9,9 +9,12 @@ import type {
9
9
  ReactCompatNode,
10
10
  } from "./element.js";
11
11
 
12
+ /** Fragment marker used by the automatic JSX runtime. */
12
13
  export { Fragment };
14
+ /** Metadata key used by compiled JSX for reactive text bindings. */
13
15
  export { REACTIVE_TEXT_BINDING_META };
14
16
 
17
+ /** DOM event type with a narrowed currentTarget. */
15
18
  export type JSXEvent<
16
19
  TCurrentTarget extends EventTarget,
17
20
  TEvent extends Event = Event,
@@ -19,19 +22,23 @@ export type JSXEvent<
19
22
  readonly currentTarget: TCurrentTarget;
20
23
  };
21
24
 
25
+ /** Event handler type used by JSX DOM attributes. */
22
26
  export type JSXEventHandler<
23
27
  TCurrentTarget extends EventTarget,
24
28
  TEvent extends Event = Event,
25
29
  > = (event: JSXEvent<TCurrentTarget, TEvent>) => unknown;
26
30
 
31
+ /** Submit event type used by form-related JSX attributes. */
27
32
  export type FormEvent<TCurrentTarget extends EventTarget = Element> = JSXEvent<
28
33
  TCurrentTarget,
29
34
  SubmitEvent
30
35
  >;
31
36
 
37
+ /** Submit event handler type used by form-related JSX attributes. */
32
38
  export type FormEventHandler<TCurrentTarget extends EventTarget = Element> =
33
39
  JSXEventHandler<TCurrentTarget, SubmitEvent>;
34
40
 
41
+ /** DOM event attributes accepted by JSX elements. */
35
42
  export interface JSXDOMAttributes<TElement extends EventTarget> {
36
43
  children?: ReactCompatNode;
37
44
  onClick?: JSXEventHandler<TElement, MouseEvent>;
@@ -40,16 +47,19 @@ export interface JSXDOMAttributes<TElement extends EventTarget> {
40
47
  onSubmit?: JSXEventHandler<TElement, SubmitEvent>;
41
48
  }
42
49
 
50
+ /** HTML attributes accepted by JSX host elements. */
43
51
  export interface JSXHTMLAttributes<TElement extends HTMLElement>
44
52
  extends JSXDOMAttributes<TElement> {
45
53
  [attributeName: string]: unknown;
46
54
  }
47
55
 
56
+ /** Attributes accepted by every JSX element. */
48
57
  export interface JSXIntrinsicAttributes {
49
58
  key?: unknown;
50
59
  ref?: unknown;
51
60
  }
52
61
 
62
+ /** Built-in JSX element names and their attribute types. */
53
63
  export interface JSXIntrinsicElements {
54
64
  form: JSXHTMLAttributes<HTMLFormElement> & {
55
65
  onSubmit?: JSXEventHandler<HTMLFormElement, SubmitEvent>;
@@ -67,6 +77,7 @@ export interface JSXIntrinsicElements {
67
77
  [elementName: string]: Record<string, unknown>;
68
78
  }
69
79
 
80
+ /** JSX namespace exported by the automatic JSX runtime. */
70
81
  export namespace JSX {
71
82
  export interface Element extends ReactCompatElement {}
72
83
 
@@ -83,6 +94,7 @@ declare global {
83
94
  }
84
95
  }
85
96
 
97
+ /** Creates a single-child JSX element for the automatic JSX runtime. */
86
98
  export function jsx<P extends Record<string, unknown>>(
87
99
  type: ElementType<P>,
88
100
  props: (P & { children?: ReactCompatNode; key?: unknown; ref?: unknown }) | null,
@@ -91,6 +103,7 @@ export function jsx<P extends Record<string, unknown>>(
91
103
  return createElementFromJsx(type, props, key);
92
104
  }
93
105
 
106
+ /** Creates a multi-child JSX element for the automatic JSX runtime. */
94
107
  export function jsxs<P extends Record<string, unknown>>(
95
108
  type: ElementType<P>,
96
109
  props: (P & { children?: ReactCompatNode; key?: unknown; ref?: unknown }) | null,
@@ -68,6 +68,7 @@ import {
68
68
  } from "./hooks.js";
69
69
  import { renderChildToString, renderToString } from "./server-render.js";
70
70
 
71
+ /** Default React-compatible namespace export. */
71
72
  const ReactCompat = {
72
73
  Component,
73
74
  PureComponent,
@@ -131,4 +132,5 @@ const ReactCompat = {
131
132
  version,
132
133
  } as const;
133
134
 
135
+ /** Default React-compatible namespace export. */
134
136
  export default ReactCompat;
package/src/root.ts CHANGED
@@ -41,15 +41,18 @@ import {
41
41
  import type { Fiber, FiberRoot } from "./fiber.js";
42
42
  import { renderIntoContainer } from "./reconciler.js";
43
43
 
44
+ /** Root controller returned by createRoot and hydrateRoot. */
44
45
  export interface Root {
45
46
  render(element: ReactCompatNode): void;
46
47
  unmount(): void;
47
48
  }
48
49
 
50
+ /** Options used when creating a client render root. */
49
51
  export interface RootOptions {
50
52
  identifierPrefix?: string;
51
53
  }
52
54
 
55
+ /** Options used when hydrating server-rendered markup. */
53
56
  export interface HydrateRootOptions {
54
57
  onRecoverableError?: (
55
58
  error: Error,
@@ -60,11 +63,13 @@ export interface HydrateRootOptions {
60
63
  identifierPrefix?: string;
61
64
  }
62
65
 
66
+ /** Controller for deferred or selective streaming hydration. */
63
67
  export interface StreamingHydrationRoot {
64
68
  hydrate(element: ReactCompatNode, options?: HydrateRootOptions): Root;
65
69
  dispose(): void;
66
70
  }
67
71
 
72
+ /** Options for creating a streaming hydration root. */
68
73
  export interface StreamingHydrationRootOptions {
69
74
  manifest?: EventHydrationManifest;
70
75
  manifestRoot?: ParentNode;
@@ -74,12 +79,14 @@ export interface StreamingHydrationRootOptions {
74
79
  selectiveHydration?: SelectiveHydrationOptions;
75
80
  }
76
81
 
82
+ /** Rules that choose which boundary to hydrate after a captured event. */
77
83
  export interface SelectiveHydrationOptions {
78
84
  element?: ReactCompatNode;
79
85
  options?: HydrateRootOptions | ((event: Event) => HydrateRootOptions);
80
86
  boundaries?: Record<string, SelectiveHydrationBoundary>;
81
87
  }
82
88
 
89
+ /** Element and options used to hydrate one selective boundary. */
83
90
  export interface SelectiveHydrationBoundary {
84
91
  element: ReactCompatNode;
85
92
  options?: HydrateRootOptions | ((event: Event) => HydrateRootOptions);
@@ -87,6 +94,7 @@ export interface SelectiveHydrationBoundary {
87
94
 
88
95
  const legacyRoots = new WeakMap<Element, Root>();
89
96
 
97
+ /** Creates a root that renders React-compatible nodes into a DOM container. */
90
98
  export function createRoot(
91
99
  container: Element,
92
100
  options: RootOptions = {},
@@ -236,16 +244,19 @@ function renderHydratingHostFiberIntoContainer(
236
244
  throw new Error("Store unstable.");
237
245
  }
238
246
 
247
+ /** Renders a React-compatible node into a legacy root container. */
239
248
  export function render(element: ReactCompatNode, container: Element): void {
240
249
  const root = legacyRoots.get(container) ?? createRoot(container);
241
250
  legacyRoots.set(container, root);
242
251
  root.render(element);
243
252
  }
244
253
 
254
+ /** Runs updates synchronously and flushes pending reactive work before returning. */
245
255
  export function flushSync<T>(callback: () => T): T {
246
256
  return flushSyncUpdates(callback);
247
257
  }
248
258
 
259
+ /** Hydrates server-rendered markup with a React-compatible element tree. */
249
260
  export function hydrateRoot(
250
261
  container: Element,
251
262
  element: ReactCompatNode,
@@ -355,6 +366,7 @@ function laneForRenderPriority(priority: RenderPriority): Lane {
355
366
  return SyncLane;
356
367
  }
357
368
 
369
+ /** Creates a root that can hydrate streamed or selectively revealed markup. */
358
370
  export function createStreamingHydrationRoot(
359
371
  container: Element,
360
372
  options: StreamingHydrationRootOptions = {},
@@ -434,6 +446,7 @@ export function createStreamingHydrationRoot(
434
446
  };
435
447
  }
436
448
 
449
+ /** Unmounts a legacy root from a container and reports whether anything was removed. */
437
450
  export function unmountComponentAtNode(container: Element): boolean {
438
451
  const root = legacyRoots.get(container);
439
452