Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] main from facebook:main #907

Merged
merged 2 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions fixtures/view-transition/src/components/Chrome.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ export default class Chrome extends Component {
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="shortcut icon" href="favicon.ico" />
<link rel="stylesheet" href={assets['main.css']} />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
rel="preconnect"
href="https://fonts.gstatic.com"
crossOrigin=""
/>
<link
href="https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap"
rel="stylesheet"
/>
<title>{this.props.title}</title>
</head>
<body>
Expand Down
8 changes: 8 additions & 0 deletions fixtures/view-transition/src/components/Page.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.roboto-font {
font-family: "Roboto", serif;
font-optical-sizing: auto;
font-weight: 100;
font-style: normal;
font-variation-settings:
"wdth" 100;
}
2 changes: 1 addition & 1 deletion fixtures/view-transition/src/components/Page.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function Component() {
className={
transitions['enter-slide-right'] + ' ' + transitions['exit-slide-left']
}>
<p>Slide In from Left, Slide Out to Right</p>
<p className="roboto-font">Slide In from Left, Slide Out to Right</p>
</ViewTransition>
);
}
Expand Down
35 changes: 34 additions & 1 deletion packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,13 @@ export function hasInstanceAffectedParent(
return oldRect.height !== newRect.height || oldRect.width !== newRect.width;
}

// How long to wait for new fonts to load before just committing anyway.
// This freezes the screen. It needs to be short enough that it doesn't cause too much of
// an issue when it's a new load and slow, yet long enough that you have a chance to load
// it. Otherwise we wait for no reason. The assumption here is that you likely have
// either cached the font or preloaded it earlier.
const SUSPENSEY_FONT_TIMEOUT = 500;

export function startViewTransition(
rootContainer: Container,
mutationCallback: () => void,
Expand All @@ -1220,8 +1227,34 @@ export function startViewTransition(
const ownerWindow = ownerDocument.defaultView;
const pendingNavigation =
ownerWindow.navigation && ownerWindow.navigation.transition;
// $FlowFixMe[prop-missing]
const previousFontLoadingStatus = ownerDocument.fonts.status;
mutationCallback();
// TODO: Wait for fonts.
if (previousFontLoadingStatus === 'loaded') {
// Force layout calculation to trigger font loading.
// eslint-disable-next-line ft-flow/no-unused-expressions
(ownerDocument.documentElement: any).clientHeight;
if (
// $FlowFixMe[prop-missing]
ownerDocument.fonts.status === 'loading'
) {
// The mutation lead to new fonts being loaded. We should wait on them before continuing.
// This avoids waiting for potentially unrelated fonts that were already loading before.
// Either in an earlier transition or as part of a sync optimistic state. This doesn't
// include preloads that happened earlier.
const fontsReady = Promise.race([
// $FlowFixMe[prop-missing]
ownerDocument.fonts.ready,
new Promise(resolve =>
setTimeout(resolve, SUSPENSEY_FONT_TIMEOUT),
),
]).then(layoutCallback, layoutCallback);
const allReady = pendingNavigation
? Promise.allSettled([pendingNavigation.finished, fontsReady])
: fontsReady;
return allReady.then(afterMutationCallback, afterMutationCallback);
}
}
layoutCallback();
if (pendingNavigation) {
return pendingNavigation.finished.then(
Expand Down
4 changes: 0 additions & 4 deletions packages/react-native-renderer/src/ReactFabric.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import {
import {createPortal as createPortalImpl} from 'react-reconciler/src/ReactPortal';
import {setBatchingImplementation} from './legacy-events/ReactGenericBatching';

import {getInspectorDataForInstance} from './ReactNativeFiberInspector';
import {LegacyRoot, ConcurrentRoot} from 'react-reconciler/src/ReactRootTags';
import {
findHostInstance_DEPRECATED,
Expand Down Expand Up @@ -188,9 +187,6 @@ export {
unmountComponentAtNode,
stopSurface,
createPortal,
// This export is typically undefined in production builds.
// See the "enableGetInspectorDataForInstanceInProduction" flag.
getInspectorDataForInstance,
// The public instance has a reference to the internal instance handle.
// This method allows it to acess the most recent shadow node for
// the instance (it's only accessible through it).
Expand Down
132 changes: 61 additions & 71 deletions packages/react-native-renderer/src/ReactNativeFiberInspector.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,47 +21,47 @@ import {
UIManager,
getNodeFromPublicInstance,
} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
import {enableGetInspectorDataForInstanceInProduction} from 'shared/ReactFeatureFlags';
import {getClosestInstanceFromNode} from './ReactNativeComponentTree';
import {
getNodeFromInternalInstanceHandle,
findNodeHandle,
} from './ReactNativePublicCompat';
import {getStackByFiberInDevAndProd} from 'react-reconciler/src/ReactFiberComponentStack';

const emptyObject = {};
let getInspectorDataForInstance: (
closestInstance: Fiber | null,
) => InspectorData;

if (__DEV__) {
Object.freeze(emptyObject);
}
const emptyObject = Object.freeze({});

// $FlowFixMe[missing-local-annot]
function createHierarchy(fiberHierarchy) {
return fiberHierarchy.map(fiber => ({
name: getComponentNameFromType(fiber.type),
getInspectorData: () => {
return {
props: getHostProps(fiber),
measure: callback => {
// If this is Fabric, we'll find a shadow node and use that to measure.
const hostFiber = findCurrentHostFiber(fiber);
const node =
hostFiber != null &&
hostFiber.stateNode !== null &&
hostFiber.stateNode.node;
// $FlowFixMe[missing-local-annot]
const createHierarchy = function (fiberHierarchy) {
return fiberHierarchy.map(fiber => ({
name: getComponentNameFromType(fiber.type),
getInspectorData: () => {
return {
props: getHostProps(fiber),
measure: callback => {
// If this is Fabric, we'll find a shadow node and use that to measure.
const hostFiber = findCurrentHostFiber(fiber);
const node =
hostFiber != null &&
hostFiber.stateNode !== null &&
hostFiber.stateNode.node;

if (node) {
nativeFabricUIManager.measure(node, callback);
} else {
return UIManager.measure(getHostNode(fiber), callback);
}
},
};
},
}));
}
if (node) {
nativeFabricUIManager.measure(node, callback);
} else {
return UIManager.measure(getHostNode(fiber), callback);
}
},
};
},
}));
};

function getHostNode(fiber: Fiber | null) {
if (__DEV__ || enableGetInspectorDataForInstanceInProduction) {
const getHostNode = function (fiber: Fiber | null) {
let hostNode;
// look for children first for the hostNode
// as composite fibers do not have a hostNode
Expand All @@ -75,22 +75,19 @@ function getHostNode(fiber: Fiber | null) {
fiber = fiber.child;
}
return null;
}
}
};

// $FlowFixMe[missing-local-annot]
function getHostProps(fiber) {
const host = findCurrentHostFiber(fiber);
if (host) {
return host.memoizedProps || emptyObject;
}
return emptyObject;
}
const getHostProps = function (fiber: Fiber) {
const host = findCurrentHostFiber(fiber);
if (host) {
return host.memoizedProps || emptyObject;
}
return emptyObject;
};

function getInspectorDataForInstance(
closestInstance: Fiber | null,
): InspectorData {
if (__DEV__ || enableGetInspectorDataForInstanceInProduction) {
getInspectorDataForInstance = function (
closestInstance: Fiber | null,
): InspectorData {
// Handle case where user clicks outside of ReactNative
if (!closestInstance) {
return {
Expand Down Expand Up @@ -125,50 +122,43 @@ function getInspectorDataForInstance(
selectedIndex,
componentStack,
};
}
};

throw new Error(
'getInspectorDataForInstance() is not available in production',
);
}

function getOwnerHierarchy(instance: Fiber) {
const hierarchy: Array<$FlowFixMe> = [];
traverseOwnerTreeUp(hierarchy, instance);
return hierarchy;
}
const getOwnerHierarchy = function (instance: Fiber) {
const hierarchy: Array<$FlowFixMe> = [];
traverseOwnerTreeUp(hierarchy, instance);
return hierarchy;
};

// $FlowFixMe[missing-local-annot]
function lastNonHostInstance(hierarchy) {
for (let i = hierarchy.length - 1; i > 1; i--) {
const instance = hierarchy[i];
// $FlowFixMe[missing-local-annot]
const lastNonHostInstance = function (hierarchy) {
for (let i = hierarchy.length - 1; i > 1; i--) {
const instance = hierarchy[i];

if (instance.tag !== HostComponent) {
return instance;
if (instance.tag !== HostComponent) {
return instance;
}
}
}
return hierarchy[0];
}
return hierarchy[0];
};

function traverseOwnerTreeUp(
hierarchy: Array<$FlowFixMe>,
instance: Fiber,
): void {
if (__DEV__ || enableGetInspectorDataForInstanceInProduction) {
const traverseOwnerTreeUp = function (
hierarchy: Array<$FlowFixMe>,
instance: Fiber,
): void {
hierarchy.unshift(instance);
const owner = instance._debugOwner;
if (owner != null && typeof owner.tag === 'number') {
traverseOwnerTreeUp(hierarchy, (owner: any));
} else {
// TODO: Traverse Server Components owners.
}
}
};
}

function getInspectorDataForViewTag(viewTag: number): InspectorData {
if (__DEV__) {
const closestInstance = getClosestInstanceFromNode(viewTag);

return getInspectorDataForInstance(closestInstance);
} else {
throw new Error(
Expand Down
4 changes: 0 additions & 4 deletions packages/react-native-renderer/src/ReactNativeRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import {
// Modules provided by RN:
import {UIManager} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';

import {getInspectorDataForInstance} from './ReactNativeFiberInspector';
import {LegacyRoot} from 'react-reconciler/src/ReactRootTags';
import {
findHostInstance_DEPRECATED,
Expand Down Expand Up @@ -206,9 +205,6 @@ export {
unmountComponentAtNodeAndRemoveContainer,
createPortal,
batchedUpdates as unstable_batchedUpdates,
// This export is typically undefined in production builds.
// See the "enableGetInspectorDataForInstanceInProduction" flag.
getInspectorDataForInstance,
// DEV-only:
isChildPublicInstance,
};
Expand Down
2 changes: 0 additions & 2 deletions packages/shared/ReactFeatureFlags.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,4 @@ export const enableAsyncDebugInfo = __EXPERIMENTAL__;
export const enableUpdaterTracking = __PROFILE__;

// Internal only.
export const enableGetInspectorDataForInstanceInProduction = false;

export const enableDO_NOT_USE_disableStrictPassiveEffect = false;
1 change: 0 additions & 1 deletion packages/shared/forks/ReactFeatureFlags.native-fb.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ export const enableCreateEventHandleAPI = false;
export const enableDO_NOT_USE_disableStrictPassiveEffect = false;
export const enableMoveBefore = true;
export const enableFizzExternalRuntime = true;
export const enableGetInspectorDataForInstanceInProduction = true;
export const enableHalt = false;
export const enableInfiniteRenderLoopDetection = false;
export const enableLegacyCache = false;
Expand Down
1 change: 0 additions & 1 deletion packages/shared/forks/ReactFeatureFlags.native-oss.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export const enableDO_NOT_USE_disableStrictPassiveEffect = false;
export const enableFabricCompleteRootInCommitPhase = false;
export const enableMoveBefore = true;
export const enableFizzExternalRuntime = true;
export const enableGetInspectorDataForInstanceInProduction = false;
export const enableHalt = false;
export const enableHiddenSubtreeInsertionEffectCleanup = false;
export const enableInfiniteRenderLoopDetection = false;
Expand Down
1 change: 0 additions & 1 deletion packages/shared/forks/ReactFeatureFlags.test-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ export const enableUseEffectEventHook = false;
export const favorSafetyOverHydrationPerf = true;
export const enableLegacyFBSupport = false;
export const enableMoveBefore = false;
export const enableGetInspectorDataForInstanceInProduction = false;
export const enableFabricCompleteRootInCommitPhase = false;
export const enableHiddenSubtreeInsertionEffectCleanup = false;
export const enableHydrationLaneScheduling = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export const enableCreateEventHandleAPI = false;
export const enableDO_NOT_USE_disableStrictPassiveEffect = false;
export const enableMoveBefore = false;
export const enableFizzExternalRuntime = true;
export const enableGetInspectorDataForInstanceInProduction = false;
export const enableHalt = false;
export const enableInfiniteRenderLoopDetection = false;
export const enableHiddenSubtreeInsertionEffectCleanup = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export const enableUseEffectEventHook = false;
export const favorSafetyOverHydrationPerf = true;
export const enableLegacyFBSupport = false;
export const enableMoveBefore = false;
export const enableGetInspectorDataForInstanceInProduction = false;
export const enableRenderableContext = false;
export const enableFabricCompleteRootInCommitPhase = false;
export const enableHiddenSubtreeInsertionEffectCleanup = true;
Expand Down
1 change: 0 additions & 1 deletion packages/shared/forks/ReactFeatureFlags.www.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ export const enableSchedulingProfiler: boolean =
__PROFILE__ && dynamicFeatureFlags.enableSchedulingProfiler;

export const disableLegacyContext = __EXPERIMENTAL__;
export const enableGetInspectorDataForInstanceInProduction = false;

export const enableLegacyCache = true;

Expand Down
Loading