diff --git a/fixtures/view-transition/src/components/Chrome.js b/fixtures/view-transition/src/components/Chrome.js index 0cae4a8dd195..be3f6d1653dd 100644 --- a/fixtures/view-transition/src/components/Chrome.js +++ b/fixtures/view-transition/src/components/Chrome.js @@ -12,6 +12,16 @@ export default class Chrome extends Component { + + + {this.props.title} diff --git a/fixtures/view-transition/src/components/Page.css b/fixtures/view-transition/src/components/Page.css index e69de29bb2d1..5afcc33a8f4b 100644 --- a/fixtures/view-transition/src/components/Page.css +++ b/fixtures/view-transition/src/components/Page.css @@ -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; +} diff --git a/fixtures/view-transition/src/components/Page.js b/fixtures/view-transition/src/components/Page.js index ab40790b1647..4e2e80605561 100644 --- a/fixtures/view-transition/src/components/Page.js +++ b/fixtures/view-transition/src/components/Page.js @@ -29,7 +29,7 @@ function Component() { className={ transitions['enter-slide-right'] + ' ' + transitions['exit-slide-left'] }> -

Slide In from Left, Slide Out to Right

+

Slide In from Left, Slide Out to Right

); } diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index 8b17db1dc38a..c9dbcdb68c50 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -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, @@ -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(