117
DidCapture,
118
AffectedParentLayout,
119
ViewTransitionNamedStatic,
120
+ PortalStatic,
121
} from './ReactFiberFlags';
122
import {
123
commitStartTime,
1183
}
1184
}
1185
1185
-function hideOrUnhideAllChildren(finishedWork: Fiber, isHidden: boolean) {
1186
- // Only hide or unhide the top-most host nodes.
1187
- let hostSubtreeRoot = null;
1186
+function hideOrUnhideAllChildren(parentFiber: Fiber, isHidden: boolean) {
1187
+ if (!supportsMutation) {
1188
+ return;
1189
+ }
1190
+ // Finds the nearest host component children and updates their visibility
1191
+ // to either hidden or visible.
1192
+ let child = parentFiber.child;
1193
+ while (child !== null) {
1194
+ hideOrUnhideAllChildrenOnFiber(child, isHidden);
1195
+ child = child.sibling;
1196
+ }
1197
+}
1198
1189
- if (supportsMutation) {
1190
- // We only have the top Fiber that was inserted but we need to recurse down its
1191
- // children to find all the terminal nodes.
1192
- let node: Fiber = finishedWork;
1193
- while (true) {
1194
- if (
1195
- node.tag === HostComponent ||
1196
- (supportsResources ? node.tag === HostHoistable : false)
1197
- ) {
1198
- if (hostSubtreeRoot === null) {
1199
- hostSubtreeRoot = node;
1200
- commitShowHideHostInstance(node, isHidden);
1201
- }
1202
- } else if (node.tag === HostText) {
1203
- if (hostSubtreeRoot === null) {
1204
- commitShowHideHostTextInstance(node, isHidden);
1205
- }
1206
- } else if (node.tag === DehydratedFragment) {
1207
- if (hostSubtreeRoot === null) {
1208
- commitShowHideSuspenseBoundary(node, isHidden);
1209
- }
1210
- } else if (
1211
- (node.tag === OffscreenComponent ||
1212
- node.tag === LegacyHiddenComponent) &&
1213
- (node.memoizedState: OffscreenState) !== null &&
1214
- node !== finishedWork
1215
- ) {
1199
+function hideOrUnhideAllChildrenOnFiber(fiber: Fiber, isHidden: boolean) {
1200
+ if (!supportsMutation) {
1201
+ return;
1202
+ }
1203
+ switch (fiber.tag) {
1204
+ case HostComponent:
1205
+ case HostHoistable: {
1206
+ // Found the nearest host component. Hide it.
1207
+ commitShowHideHostInstance(fiber, isHidden);
1208
+ // Typically, only the nearest host nodes need to be hidden, since that
1209
+ // has the effect of also hiding everything inside of them.
1210
+ //
1211
+ // However, there's a special case for portals, because portals do not
1212
+ // exist in the regular host tree hierarchy; we can't assume that just
1213
+ // because a portal's HostComponent parent in the React tree will also be
1214
+ // a parent in the actual host tree.
1215
+ //
1216
+ // So, if any portals exist within the tree, regardless of how deeply
1217
+ // nested they are, we need to repeat this algorithm for its children.
1218
+ hideOrUnhideNearestPortals(fiber, isHidden);
1219
+ return;
1220
+ }
1221
+ case HostText: {
1222
+ commitShowHideHostTextInstance(fiber, isHidden);
1223
+ return;
1224
+ }
1225
+ case DehydratedFragment: {
1226
+ commitShowHideSuspenseBoundary(fiber, isHidden);
1227
+ return;
1228
+ }
1229
+ case OffscreenComponent:
1230
+ case LegacyHiddenComponent: {
1231
+ const offscreenState: OffscreenState | null = fiber.memoizedState;
1232
+ if (offscreenState !== null) {
1233
// Found a nested Offscreen component that is hidden.
1234
// Don't search any deeper. This tree should remain hidden.
1218
- } else if (node.child !== null) {
1219
- node.child.return = node;
1220
- node = node.child;
1221
- continue;
1222
- }
1223
-
1224
- if (node === finishedWork) {
1225
- return;
1235
+ } else {
1236
+ hideOrUnhideAllChildren(fiber, isHidden);
1237
}
1227
- while (node.sibling === null) {
1228
- if (node.return === null || node.return === finishedWork) {
1229
- return;
1230
- }
1231
-
1232
- if (hostSubtreeRoot === node) {
1233
- hostSubtreeRoot = null;
1234
- }
1238
+ return;
1239
+ }
1240
+ default: {
1241
+ hideOrUnhideAllChildren(fiber, isHidden);
1242
+ return;
1243
+ }
1244
+ }
1245
+}
1246
1236
- node = node.return;
1237
- }
1247
+function hideOrUnhideNearestPortals(parentFiber: Fiber, isHidden: boolean) {
1248
+ if (!supportsMutation) {
1249
+ return;
1250
+ }
1251
+ if (parentFiber.subtreeFlags & PortalStatic) {
1252
+ let child = parentFiber.child;
1253
+ while (child !== null) {
1254
+ hideOrUnhideNearestPortalsOnFiber(child, isHidden);
1255
+ child = child.sibling;
1256
+ }
1257
+ }
1258
+}
1259
1239
- if (hostSubtreeRoot === node) {
1240
- hostSubtreeRoot = null;
1260
+function hideOrUnhideNearestPortalsOnFiber(fiber: Fiber, isHidden: boolean) {
1261
+ if (!supportsMutation) {
1262
+ return;
1263
+ }
1264
+ switch (fiber.tag) {
1265
+ case HostPortal: {
1266
+ // Found a portal. Switch back to the normal hide/unhide algorithm to
1267
+ // toggle the visibility of its children.
1268
+ hideOrUnhideAllChildrenOnFiber(fiber, isHidden);
1269
+ return;
1270
+ }
1271
+ case OffscreenComponent: {
1272
+ const offscreenState: OffscreenState | null = fiber.memoizedState;
1273
+ if (offscreenState !== null) {
1274
+ // Found a nested Offscreen component that is hidden. Don't search any
1275
+ // deeper. This tree should remain hidden.
1276
+ } else {
1277
+ hideOrUnhideNearestPortals(fiber, isHidden);
1278
}
1242
-
1243
- node.sibling.return = node.return;
1244
- node = node.sibling;
1279
+ return;
1280
+ }
1281
+ default: {
1282
+ hideOrUnhideNearestPortals(fiber, isHidden);
1283
+ return;
1284
}
1285
}
1286
}
2344
break;
2345
}
2346
case HostPortal: {
2347
+ // For the purposes of visibility toggling, the direct children of a
2348
+ // portal are considered "children" of the nearest hidden
2349
+ // OffscreenComponent, regardless of whether there are any host components
2350
+ // in between them. This is because portals are not part of the regular
2351
+ // host tree hierarchy; we can't assume that just because a portal's
2352
+ // HostComponent parent in the React tree will also be a parent in the
2353
+ // actual host tree. So we must hide all of them.
2354
+ const prevOffscreenDirectParentIsHidden = offscreenDirectParentIsHidden;
2355
+ offscreenDirectParentIsHidden = offscreenSubtreeIsHidden;
2356
const prevMutationContext = pushMutationContext();
2357
if (supportsResources) {
2358
const previousHoistableRoot = currentHoistableRoot;
2374
rootViewTransitionAffected = true;
2375
}
2376
popMutationContext(prevMutationContext);
2377
+ offscreenDirectParentIsHidden = prevOffscreenDirectParentIsHidden;
2378
2379
if (flags & Update) {
2380
if (supportsPersistence) {