diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index 2c7502ca3b665..ab678fa23f5f1 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -91,7 +91,15 @@ function render_block_core_post_template( $attributes, $content, $block ) { $classnames .= ' ' . sanitize_title( 'columns-' . $attributes['layout']['columnCount'] ); } - $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => trim( $classnames ) ) ); + $wrapper_attributes = get_block_wrapper_attributes( + $enhanced_pagination + ? array( + 'class' => trim( $classnames ), + 'data-wp-class--fade-out' => 'selectors.core.query.fadeOutPostTemplate', + 'data-wp-class--fade-in' => 'selectors.core.query.fadeInPostTemplate', + ) + : array( 'class' => trim( $classnames ) ) + ); $content = ''; while ( $query->have_posts() ) { diff --git a/packages/block-library/src/post-template/style.scss b/packages/block-library/src/post-template/style.scss index 00305a1712336..a664e4e1d9c14 100644 --- a/packages/block-library/src/post-template/style.scss +++ b/packages/block-library/src/post-template/style.scss @@ -29,6 +29,32 @@ } } } + + &.fade-out { + animation: wp-block-post-template__fade-out 150ms ease-in forwards; + } + + &.fade-in { + animation: wp-block-post-template__fade-in 150ms ease-out forwards; + } + + @keyframes wp-block-post-template__fade-out { + 0% { + opacity: 1; + } + 100% { + opacity: 0.3; + } + } + + @keyframes wp-block-post-template__fade-in { + 0% { + opacity: 0.3; + } + 100% { + opacity: 1; + } + } } @media ( max-width: $break-small ) { diff --git a/packages/block-library/src/query/view.js b/packages/block-library/src/query/view.js index 3e50d521ea6ef..204b8c7996df4 100644 --- a/packages/block-library/src/query/view.js +++ b/packages/block-library/src/query/view.js @@ -18,6 +18,19 @@ const isValidEvent = ( event ) => ! event.shiftKey && ! event.defaultPrevented; +const animationEnd = ( animationName, dom ) => + new Promise( ( resolve ) => { + const handler = ( event ) => { + if ( event.animationName === animationName ) { + dom.removeEventListener( 'animationend', handler ); + dom.removeEventListener( 'animationcancel', handler ); + resolve(); + } + }; + dom.addEventListener( 'animationend', handler ); + dom.addEventListener( 'animationcancel', handler ); + } ); + store( { selectors: { core: { @@ -26,6 +39,10 @@ store( { context.core.query.animation === 'start', finishAnimation: ( { context } ) => context.core.query.animation === 'finish', + fadeOutPostTemplate: ( { context } ) => + context.core.query.postTemplateAnimation === 'fade-out', + fadeInPostTemplate: ( { context } ) => + context.core.query.postTemplateAnimation === 'fade-in', }, }, }, @@ -36,8 +53,8 @@ store( { if ( isValidLink( ref ) && isValidEvent( event ) ) { event.preventDefault(); - const id = ref.closest( '[data-wp-navigation-id]' ) - .dataset.wpNavigationId; + const region = ref.closest( '[data-wp-navigation-id]' ); + const id = region.dataset.wpNavigationId; // Don't announce the navigation immediately, wait 300 ms. const timeout = setTimeout( () => { @@ -46,7 +63,17 @@ store( { context.core.query.animation = 'start'; }, 400 ); - await navigate( ref.href ); + const beforeRender = async () => { + context.core.query.postTemplateAnimation = + 'fade-out'; + await animationEnd( + 'wp-block-post-template__fade-out', + region + ); + }; + + await navigate( ref.href, { beforeRender } ); + context.core.query.postTemplateAnimation = 'fade-in'; // Dismiss loading message if it hasn't been added yet. clearTimeout( timeout ); diff --git a/packages/interactivity/CHANGELOG.md b/packages/interactivity/CHANGELOG.md index 736c8660cb210..cba733cc93d8f 100644 --- a/packages/interactivity/CHANGELOG.md +++ b/packages/interactivity/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Enhancements + +- Add `beforeRender` option to `navigate()`: an async function that runs right before the HTML is updated. ([#54746](https://github.com/WordPress/gutenberg/pull/54746)) + ## 2.3.0 (2023-09-20) ### Enhancements diff --git a/packages/interactivity/src/router.js b/packages/interactivity/src/router.js index ee9755126994e..4d0a130bc9973 100644 --- a/packages/interactivity/src/router.js +++ b/packages/interactivity/src/router.js @@ -101,6 +101,7 @@ export const navigate = async ( href, options = {} ) => { if ( navigatingTo !== href ) return; if ( page ) { + if ( options.beforeRender ) await options.beforeRender(); renderRegions( page ); window.history[ options.replace ? 'replaceState' : 'pushState' ]( {},