bippy 0.7.3-dev.e2b879b → 0.7.3-dev.e6929e3

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/src/core.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  // React must remain a type-only import because this module loads immediately after the DevTools hook.
2
2
  import type * as React from "react";
3
+ import { callListener } from "./call-listener.js";
3
4
 
4
5
  import type {
5
6
  Fiber,
@@ -167,16 +168,20 @@ const shouldFilterFiber = (fiber: Fiber): boolean => {
167
168
  // https://github.com/bvaughn/react-devtools-experimental/issues/197
168
169
  return true;
169
170
 
170
- case workTags.Fragment:
171
+ case workTags.HostPortal:
171
172
  case workTags.HostText:
172
173
  case workTags.LegacyHiddenComponent:
173
174
  case workTags.OffscreenComponent:
175
+ case workTags.Throw:
174
176
  return true;
175
177
 
176
178
  case workTags.HostRoot:
177
179
  // It is never valid to filter the root element.
178
180
  return false;
179
181
 
182
+ case workTags.Fragment:
183
+ return fiber.key === null;
184
+
180
185
  default: {
181
186
  const symbolOrNumber =
182
187
  typeof fiber.type === "object" && fiber.type !== null ? fiber.type.$$typeof : fiber.type;
@@ -184,7 +189,8 @@ const shouldFilterFiber = (fiber: Fiber): boolean => {
184
189
  if (typeof symbolOrNumber === "symbol") {
185
190
  return (
186
191
  symbolOrNumber.description === ReactSymbols.CONCURRENT_MODE_SYMBOL_DESCRIPTION ||
187
- symbolOrNumber.description === ReactSymbols.DEPRECATED_ASYNC_MODE_SYMBOL_DESCRIPTION
192
+ symbolOrNumber.description === ReactSymbols.DEPRECATED_ASYNC_MODE_SYMBOL_DESCRIPTION ||
193
+ symbolOrNumber.description === ReactSymbols.STRICT_MODE_SYMBOL_DESCRIPTION
188
194
  );
189
195
  }
190
196
 
@@ -192,6 +198,8 @@ const shouldFilterFiber = (fiber: Fiber): boolean => {
192
198
  case ReactSymbols.CONCURRENT_MODE_NUMBER:
193
199
  case ReactSymbols.CONCURRENT_MODE_SYMBOL_STRING:
194
200
  case ReactSymbols.DEPRECATED_ASYNC_MODE_SYMBOL_STRING:
201
+ case ReactSymbols.STRICT_MODE_NUMBER:
202
+ case ReactSymbols.STRICT_MODE_SYMBOL_STRING:
195
203
  return true;
196
204
 
197
205
  default:
@@ -458,131 +466,91 @@ const releaseFiberId = (fiber: Fiber): void => {
458
466
  }
459
467
  };
460
468
 
461
- const mountFiberRecursively = (
469
+ const getRenderedChild = (fiber: Fiber, skipPrimaryWrapper: boolean): Fiber | null => {
470
+ const workTags = getReactWorkTagsForFiber(fiber);
471
+ if (fiber.tag !== workTags.SuspenseComponent) return fiber.child;
472
+ if (fiber.memoizedState !== null) return fiber.child?.sibling?.child ?? null;
473
+ return skipPrimaryWrapper && workTags.OffscreenComponent !== -1
474
+ ? (fiber.child?.child ?? null)
475
+ : fiber.child;
476
+ };
477
+
478
+ const mountFiberTree = (
462
479
  onRender: RenderHandler,
463
480
  firstChild: Fiber,
464
481
  traverseSiblings: boolean,
465
482
  ): void => {
483
+ const pendingSiblings: Fiber[] = [];
466
484
  let fiber: Fiber | null = firstChild;
467
-
468
- while (fiber !== null) {
485
+ while (fiber) {
469
486
  getFiberId(fiber);
470
- const shouldIncludeInTree = !shouldFilterFiber(fiber);
471
- if (shouldIncludeInTree && didFiberRender(fiber)) {
472
- onRender(fiber, "mount");
473
- }
474
-
475
- if (fiber.tag === getReactWorkTagsForFiber(fiber).SuspenseComponent) {
476
- const isTimedOut = fiber.memoizedState !== null;
477
- if (isTimedOut) {
478
- // Special case: if Suspense mounts in a timed-out state,
479
- // get the fallback child from the inner fragment and mount
480
- // it as if it was our own child. Updates handle this too.
481
- const primaryChildFragment = fiber.child;
482
- const fallbackChildFragment = primaryChildFragment ? primaryChildFragment.sibling : null;
483
- if (fallbackChildFragment) {
484
- const fallbackChild = fallbackChildFragment.child;
485
- if (fallbackChild !== null) {
486
- mountFiberRecursively(onRender, fallbackChild, true);
487
- }
488
- }
489
- } else {
490
- const primaryChild = fiber.child?.child ?? null;
491
- if (primaryChild !== null) {
492
- mountFiberRecursively(onRender, primaryChild, true);
493
- }
494
- }
495
- } else if (fiber.child !== null) {
496
- mountFiberRecursively(onRender, fiber.child, true);
497
- }
498
- fiber = traverseSiblings ? fiber.sibling : null;
487
+ if (!shouldFilterFiber(fiber) && didFiberRender(fiber)) onRender(fiber, "mount");
488
+ if (traverseSiblings && fiber.sibling) pendingSiblings.push(fiber.sibling);
489
+ fiber = getRenderedChild(fiber, true) ?? pendingSiblings.pop() ?? null;
490
+ traverseSiblings = true;
499
491
  }
500
492
  };
501
493
 
502
- const updateFiberRecursively = (
494
+ interface FiberUpdate {
495
+ fiber: Fiber;
496
+ previousFiber: Fiber | null;
497
+ traverseSiblings: boolean;
498
+ }
499
+
500
+ const updateFiberTree = (
503
501
  onRender: RenderHandler,
504
502
  nextFiber: Fiber,
505
503
  prevFiber: Fiber | null,
506
504
  ): void => {
507
- getFiberId(nextFiber);
508
- if (!prevFiber) return;
509
- getFiberId(prevFiber);
510
-
511
- const isSuspense = nextFiber.tag === getReactWorkTagsForFiber(nextFiber).SuspenseComponent;
512
-
513
- const shouldIncludeInTree = !shouldFilterFiber(nextFiber);
514
- if (shouldIncludeInTree && didFiberRender(nextFiber)) {
515
- onRender(nextFiber, "update");
516
- }
517
-
518
- // The behavior of timed-out Suspense trees is unique.
519
- // Rather than unmount the timed out content (and possibly lose important state),
520
- // React re-parents this content within a hidden Fragment while the fallback is showing.
521
- // This behavior doesn't need to be observable in the DevTools though.
522
- // It might even result in a bad user experience for e.g. node selection in the Elements panel.
523
- // The easiest fix is to strip out the intermediate Fragment fibers,
524
- // so the Elements panel and Profiler don't need to special case them.
525
- // Suspense components only have a non-null memoizedState if they're timed-out.
526
- const prevDidTimeout = isSuspense && prevFiber.memoizedState !== null;
527
- const nextDidTimeOut = isSuspense && nextFiber.memoizedState !== null;
528
-
529
- // The logic below is inspired by the code paths in updateSuspenseComponent()
530
- // inside ReactFiberBeginWork in the React source code.
531
- if (prevDidTimeout && nextDidTimeOut) {
532
- // Fallback -> Fallback:
533
- // 1. Reconcile fallback set.
534
- const nextFallbackChildSet = nextFiber.child?.sibling ?? null;
535
- // Note: We can't use nextFiber.child.sibling.alternate
536
- // because the set is special and alternate may not exist.
537
- const prevFallbackChildSet = prevFiber.child?.sibling ?? null;
538
-
539
- if (nextFallbackChildSet !== null && prevFallbackChildSet !== null) {
540
- updateFiberRecursively(onRender, nextFallbackChildSet, prevFallbackChildSet);
505
+ if (!prevFiber) {
506
+ getFiberId(nextFiber);
507
+ return;
508
+ }
509
+ const pendingUpdates: FiberUpdate[] = [
510
+ { fiber: nextFiber, previousFiber: prevFiber, traverseSiblings: false },
511
+ ];
512
+ let update: FiberUpdate | undefined;
513
+ while ((update = pendingUpdates.pop())) {
514
+ const { fiber, previousFiber, traverseSiblings } = update;
515
+ if (traverseSiblings && fiber.sibling) {
516
+ pendingUpdates.push({
517
+ fiber: fiber.sibling,
518
+ previousFiber: fiber.sibling.alternate,
519
+ traverseSiblings: true,
520
+ });
541
521
  }
542
- } else if (prevDidTimeout && !nextDidTimeOut) {
543
- // Fallback -> Primary:
544
- // 1. Unmount fallback set
545
- // Note: don't emulate fallback unmount because React actually did it.
546
- // 2. Mount primary set
547
- const nextPrimaryChildSet = nextFiber.child;
548
-
549
- if (nextPrimaryChildSet !== null) {
550
- mountFiberRecursively(onRender, nextPrimaryChildSet, true);
522
+ if (!previousFiber) {
523
+ mountFiberTree(onRender, fiber, false);
524
+ continue;
551
525
  }
552
- } else if (!prevDidTimeout && nextDidTimeOut) {
553
- // Primary -> Fallback:
554
- // 1. Hide primary set
555
- // This is not a real unmount, so it won't get reported by React.
556
- // We need to manually walk the previous tree and record unmounts.
557
- unmountFiberChildrenRecursively(onRender, prevFiber);
558
-
559
- // 2. Mount fallback set
560
- const nextFallbackChildSet = nextFiber.child?.sibling ?? null;
561
-
562
- if (nextFallbackChildSet !== null) {
563
- mountFiberRecursively(onRender, nextFallbackChildSet, true);
564
- }
565
- } else if (nextFiber.child !== prevFiber.child) {
566
- // Common case: Primary -> Primary.
567
- // This is the same code path as for non-Suspense fibers.
568
-
569
- // If the first child is different, we need to traverse them.
570
- // Each next child will be either a new child (mount) or an alternate (update).
571
- let nextChild = nextFiber.child;
572
-
573
- while (nextChild) {
574
- // We already know children will be referentially different because
575
- // they are either new mounts or alternates of previous children.
576
- // Schedule updates and mounts depending on whether alternates exist.
577
- // We don't track deletions here because they are reported separately.
578
- if (nextChild.alternate) {
579
- updateFiberRecursively(onRender, nextChild, nextChild.alternate);
580
- } else {
581
- mountFiberRecursively(onRender, nextChild, false);
526
+ getFiberId(fiber);
527
+ getFiberId(previousFiber);
528
+ if (!shouldFilterFiber(fiber) && didFiberRender(fiber)) onRender(fiber, "update");
529
+ const isSuspense = fiber.tag === getReactWorkTagsForFiber(fiber).SuspenseComponent;
530
+ const wasTimedOut = isSuspense && previousFiber.memoizedState !== null;
531
+ const isTimedOut = isSuspense && fiber.memoizedState !== null;
532
+ if (wasTimedOut && isTimedOut) {
533
+ const nextFallback = fiber.child?.sibling;
534
+ const previousFallback = previousFiber.child?.sibling;
535
+ if (nextFallback && previousFallback) {
536
+ pendingUpdates.push({
537
+ fiber: nextFallback,
538
+ previousFiber: previousFallback,
539
+ traverseSiblings: false,
540
+ });
582
541
  }
583
-
584
- // Try the next child.
585
- nextChild = nextChild.sibling;
542
+ } else if (wasTimedOut && !isTimedOut) {
543
+ if (fiber.child) mountFiberTree(onRender, fiber.child, true);
544
+ } else if (!wasTimedOut && isTimedOut) {
545
+ unmountFiberChildren(onRender, previousFiber);
546
+ const fallback = fiber.child?.sibling;
547
+ if (fallback) mountFiberTree(onRender, fallback, true);
548
+ } else if (fiber.child && fiber.child !== previousFiber.child) {
549
+ pendingUpdates.push({
550
+ fiber: fiber.child,
551
+ previousFiber: fiber.child.alternate,
552
+ traverseSiblings: true,
553
+ });
586
554
  }
587
555
  }
588
556
  };
@@ -595,30 +563,18 @@ const unmountFiber = (onRender: RenderHandler, fiber: Fiber): void => {
595
563
  }
596
564
  };
597
565
 
598
- const unmountFiberChildrenRecursively = (onRender: RenderHandler, fiber: Fiber): void => {
599
- // We might meet a nested Suspense on our way.
600
- const isTimedOutSuspense =
601
- fiber.tag === getReactWorkTagsForFiber(fiber).SuspenseComponent && fiber.memoizedState !== null;
602
- let child = fiber.child;
603
-
604
- if (isTimedOutSuspense) {
605
- // If it's showing fallback tree, let's traverse it instead.
606
- const primaryChildFragment = fiber.child;
607
- const fallbackChildFragment = primaryChildFragment?.sibling ?? null;
608
-
609
- // Skip over to the real Fiber child.
610
- child = fallbackChildFragment?.child ?? null;
611
- }
612
-
613
- while (child !== null) {
614
- // Record simulated unmounts children-first.
615
- // We skip nodes without return because those are real unmounts.
566
+ const unmountFiberChildren = (onRender: RenderHandler, fiber: Fiber): void => {
567
+ const pendingSiblings: Fiber[] = [];
568
+ let child = getRenderedChild(fiber, false);
569
+ while (child) {
570
+ if (child.sibling) pendingSiblings.push(child.sibling);
616
571
  if (child.return !== null) {
617
572
  unmountFiber(onRender, child);
618
- unmountFiberChildrenRecursively(onRender, child);
573
+ child = getRenderedChild(child, false);
574
+ } else {
575
+ child = null;
619
576
  }
620
-
621
- child = child.sibling;
577
+ child ??= pendingSiblings.pop() ?? null;
622
578
  }
623
579
  };
624
580
 
@@ -668,14 +624,14 @@ export const traverseRenderedFibers = (root: Fiber | FiberRoot, onRender: Render
668
624
  const isMounted = isRootFiberMounted(fiber);
669
625
 
670
626
  if (!wasMounted && isMounted) {
671
- mountFiberRecursively(onRender, fiber, false);
627
+ mountFiberTree(onRender, fiber, false);
672
628
  } else if (wasMounted && isMounted) {
673
- updateFiberRecursively(onRender, fiber, fiber.alternate);
629
+ updateFiberTree(onRender, fiber, fiber.alternate);
674
630
  } else if (wasMounted && !isMounted) {
675
631
  unmountFiber(onRender, fiber);
676
632
  }
677
633
  } else {
678
- mountFiberRecursively(onRender, fiber, true);
634
+ mountFiberTree(onRender, fiber, true);
679
635
  }
680
636
 
681
637
  rootInstance.prevFiber = fiber;
@@ -735,7 +691,7 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
735
691
  didError,
736
692
  ) => {
737
693
  if (prevOnCommitFiberRoot) {
738
- prevOnCommitFiberRoot.call(rdtHook, rendererID, root, priority, didError);
694
+ callListener(prevOnCommitFiberRoot, rdtHook, rendererID, root, priority, didError);
739
695
  }
740
696
  if (hookDispatchers.get(rdtHook)?.onCommitFiberRoot !== dispatchCommitFiberRoot) return;
741
697
  setReactWorkTagsForFiber(root.current, rdtHook.renderers.get(rendererID));
@@ -752,7 +708,7 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
752
708
  }
753
709
  for (const { options, target } of instrumentationSubscriptions) {
754
710
  if (target === hookTargets.get(rdtHook) && options.onCommitFiberRoot) {
755
- options.onCommitFiberRoot(rendererID, root, priority, didError);
711
+ callListener(options.onCommitFiberRoot, options, rendererID, root, priority, didError);
756
712
  }
757
713
  }
758
714
  };
@@ -771,7 +727,7 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
771
727
  ) => {
772
728
  setReactWorkTagsForFiber(fiber, rdtHook.renderers.get(rendererID));
773
729
  if (prevOnCommitFiberUnmount) {
774
- prevOnCommitFiberUnmount.call(rdtHook, rendererID, fiber);
730
+ callListener(prevOnCommitFiberUnmount, rdtHook, rendererID, fiber);
775
731
  }
776
732
  if (hookDispatchers.get(rdtHook)?.onCommitFiberUnmount !== dispatchCommitFiberUnmount) {
777
733
  return;
@@ -779,7 +735,7 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
779
735
  try {
780
736
  for (const { options, target } of instrumentationSubscriptions) {
781
737
  if (target === hookTargets.get(rdtHook) && options.onCommitFiberUnmount) {
782
- options.onCommitFiberUnmount(rendererID, fiber);
738
+ callListener(options.onCommitFiberUnmount, options, rendererID, fiber);
783
739
  }
784
740
  }
785
741
  } finally {
@@ -800,14 +756,14 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
800
756
  root,
801
757
  ) => {
802
758
  if (prevOnPostCommitFiberRoot) {
803
- prevOnPostCommitFiberRoot.call(rdtHook, rendererID, root);
759
+ callListener(prevOnPostCommitFiberRoot, rdtHook, rendererID, root);
804
760
  }
805
761
  if (hookDispatchers.get(rdtHook)?.onPostCommitFiberRoot !== dispatchPostCommitFiberRoot) {
806
762
  return;
807
763
  }
808
764
  for (const { options, target } of instrumentationSubscriptions) {
809
765
  if (target === hookTargets.get(rdtHook) && options.onPostCommitFiberRoot) {
810
- options.onPostCommitFiberRoot(rendererID, root);
766
+ callListener(options.onPostCommitFiberRoot, options, rendererID, root);
811
767
  }
812
768
  }
813
769
  };
@@ -826,12 +782,12 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
826
782
  children,
827
783
  ) => {
828
784
  if (prevOnScheduleFiberRoot) {
829
- prevOnScheduleFiberRoot.call(rdtHook, rendererID, root, children);
785
+ callListener(prevOnScheduleFiberRoot, rdtHook, rendererID, root, children);
830
786
  }
831
787
  if (hookDispatchers.get(rdtHook)?.onScheduleFiberRoot !== dispatchScheduleFiberRoot) return;
832
788
  for (const { options, target } of instrumentationSubscriptions) {
833
789
  if (target === hookTargets.get(rdtHook) && options.onScheduleFiberRoot) {
834
- options.onScheduleFiberRoot(rendererID, root, children);
790
+ callListener(options.onScheduleFiberRoot, options, rendererID, root, children);
835
791
  }
836
792
  }
837
793
  };
package/src/rdt-hook.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  // This module must load before React so renderers can inject into the hook.
2
2
 
3
+ import { callListener } from "./call-listener.js";
3
4
  import type { FiberRoot, ReactDevToolsGlobalHook, ReactRenderer } from "./react-internals/index.js";
4
5
 
5
6
  export interface Unsubscribe extends Disposable {
@@ -117,7 +118,7 @@ export const removeActiveListener = (
117
118
 
118
119
  const notifyActiveListeners = (target: ReactDevToolsTarget): void => {
119
120
  for (const listener of _onActiveListeners) {
120
- if (activeListenerTargets.get(listener)?.has(target)) listener();
121
+ if (activeListenerTargets.get(listener)?.has(target)) callListener(listener, undefined);
121
122
  }
122
123
  };
123
124
 
@@ -126,7 +127,7 @@ const notifyRendererInjectListeners = (
126
127
  renderer: ReactRenderer,
127
128
  ): void => {
128
129
  for (const subscription of rendererInjectSubscriptions) {
129
- if (subscription.target === target) subscription.listener(renderer);
130
+ if (subscription.target === target) callListener(subscription.listener, subscription, renderer);
130
131
  }
131
132
  };
132
133
 
@@ -135,7 +136,7 @@ const notifyRDTHookReplaceListeners = (
135
136
  target: ReactDevToolsTarget,
136
137
  ): void => {
137
138
  for (const listener of rdtHookReplaceListeners) {
138
- listener(rdtHook, target);
139
+ callListener(listener, undefined, rdtHook, target);
139
140
  }
140
141
  };
141
142
 
@@ -326,7 +327,7 @@ export const patchRDTHook = (
326
327
  };
327
328
  }
328
329
  if (!didNotifyActiveListeners && (renderers.size || rdtHook._instrumentationIsActive)) {
329
- onActive?.();
330
+ if (onActive) callListener(onActive, undefined);
330
331
  }
331
332
  };
332
333
 
@@ -25,6 +25,9 @@ export const ReactSymbols = {
25
25
  DEPRECATED_ASYNC_MODE_SYMBOL_STRING: "Symbol(react.async_mode)",
26
26
  ELEMENT_SYMBOL_STRING: "Symbol(react.transitional.element)",
27
27
  LEGACY_ELEMENT_SYMBOL_STRING: "Symbol(react.element)",
28
+ STRICT_MODE_NUMBER: 60108,
29
+ STRICT_MODE_SYMBOL_DESCRIPTION: "react.strict_mode",
30
+ STRICT_MODE_SYMBOL_STRING: "Symbol(react.strict_mode)",
28
31
  } as const;
29
32
 
30
33
  export interface ReactWorkTagMap {
@@ -18,8 +18,24 @@ export type {
18
18
  } from "./generated/react-work-tags.js";
19
19
  export * from "./types.js";
20
20
 
21
+ interface InheritedWorkTags {
22
+ workTags: Readonly<ReactWorkTagMap>;
23
+ generation: number;
24
+ }
25
+
21
26
  const defaultReactWorkTags = getReactWorkTags();
22
27
  const fiberReactWorkTags = new WeakMap<Fiber, Readonly<ReactWorkTagMap>>();
28
+ const inheritedFiberWorkTags = new WeakMap<Fiber, InheritedWorkTags>();
29
+ let workTagGeneration = 0;
30
+
31
+ const getCachedWorkTags = (fiber: Fiber): Readonly<ReactWorkTagMap> | undefined => {
32
+ const assignedWorkTags = fiberReactWorkTags.get(fiber);
33
+ if (assignedWorkTags) return assignedWorkTags;
34
+ const inheritedWorkTags = inheritedFiberWorkTags.get(fiber);
35
+ return inheritedWorkTags?.generation === workTagGeneration
36
+ ? inheritedWorkTags.workTags
37
+ : undefined;
38
+ };
23
39
 
24
40
  // React's experimental channel historically reported "0.0.0-experimental-<sha>"
25
41
  // as the runtime version; those builds use modern work tags, not the 16.x rows
@@ -39,30 +55,36 @@ export const getReactWorkTagsForRenderer = (
39
55
 
40
56
  export const setReactWorkTagsForFiber = (fiber: Fiber, renderer?: ReactRenderer): void => {
41
57
  const workTags = getReactWorkTagsForRenderer(renderer);
58
+ if (
59
+ getCachedWorkTags(fiber) !== workTags ||
60
+ (fiber.alternate && getCachedWorkTags(fiber.alternate) !== workTags)
61
+ ) {
62
+ workTagGeneration++;
63
+ }
42
64
  fiberReactWorkTags.set(fiber, workTags);
43
65
  if (fiber.alternate) fiberReactWorkTags.set(fiber.alternate, workTags);
44
66
  };
45
67
 
46
68
  export const getReactWorkTagsForFiber = (fiber: Fiber): Readonly<ReactWorkTagMap> => {
47
- const cachedWorkTags = fiberReactWorkTags.get(fiber);
48
- if (cachedWorkTags) return cachedWorkTags;
49
-
50
- const traversedFibers: Fiber[] = [fiber];
51
- let rootFiber = fiber;
52
- let workTags = defaultReactWorkTags;
53
- while (rootFiber.return) {
54
- rootFiber = rootFiber.return;
55
- const ancestorWorkTags = fiberReactWorkTags.get(rootFiber);
56
- if (ancestorWorkTags) {
57
- workTags = ancestorWorkTags;
69
+ let workTags = getCachedWorkTags(fiber);
70
+ if (workTags) return workTags;
71
+ const traversedFibers: Fiber[] = [];
72
+ let ancestor = fiber;
73
+ while (!workTags) {
74
+ traversedFibers.push(ancestor);
75
+ const parent = ancestor.return;
76
+ if (!parent) {
77
+ workTags = inheritedFiberWorkTags.get(ancestor)?.workTags ?? defaultReactWorkTags;
58
78
  break;
59
79
  }
60
- traversedFibers.push(rootFiber);
80
+ ancestor = parent;
81
+ workTags = getCachedWorkTags(ancestor);
61
82
  }
83
+ const inheritedWorkTags = { workTags, generation: workTagGeneration };
62
84
  for (const traversedFiber of traversedFibers) {
63
- fiberReactWorkTags.set(traversedFiber, workTags);
85
+ inheritedFiberWorkTags.set(traversedFiber, inheritedWorkTags);
64
86
  if (traversedFiber.alternate) {
65
- fiberReactWorkTags.set(traversedFiber.alternate, workTags);
87
+ inheritedFiberWorkTags.set(traversedFiber.alternate, inheritedWorkTags);
66
88
  }
67
89
  }
68
90
  return workTags;