diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 6d8383e749ab1c..c3d9966a68a085 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -15,6 +15,7 @@ - `ColorPalette`: show "Clear" button even when colors array is empty ([#46001](https://github.com/WordPress/gutenberg/pull/46001)). - `InputControl`: Fix internal `Flex` wrapper usage that could add an unintended `height: 100%` ([#46213](https://github.com/WordPress/gutenberg/pull/46213)). +- `Navigator`: Allow calling `goTo` and `goBack` twice in one render cycle ([#46391](https://github.com/WordPress/gutenberg/pull/46391)). ### Enhancements diff --git a/packages/components/src/navigator/navigator-provider/component.tsx b/packages/components/src/navigator/navigator-provider/component.tsx index 57b18f6d92dba0..e80beaec9d14c4 100644 --- a/packages/components/src/navigator/navigator-provider/component.tsx +++ b/packages/components/src/navigator/navigator-provider/component.tsx @@ -43,8 +43,8 @@ function UnconnectedNavigatorProvider( const goTo: NavigatorContextType[ 'goTo' ] = useCallback( ( path, options = {} ) => { - setLocationHistory( [ - ...locationHistory, + setLocationHistory( ( prevLocationHistory ) => [ + ...prevLocationHistory, { ...options, path, @@ -53,21 +53,24 @@ function UnconnectedNavigatorProvider( }, ] ); }, - [ locationHistory ] + [] ); const goBack: NavigatorContextType[ 'goBack' ] = useCallback( () => { - if ( locationHistory.length > 1 ) { - setLocationHistory( [ - ...locationHistory.slice( 0, -2 ), + setLocationHistory( ( prevLocationHistory ) => { + if ( prevLocationHistory.length <= 1 ) { + return prevLocationHistory; + } + return [ + ...prevLocationHistory.slice( 0, -2 ), { - ...locationHistory[ locationHistory.length - 2 ], + ...prevLocationHistory[ prevLocationHistory.length - 2 ], isBack: true, hasRestoredFocus: false, }, - ] ); - } - }, [ locationHistory ] ); + ]; + } ); + }, [] ); const navigatorContextValue: NavigatorContextType = useMemo( () => ( { diff --git a/packages/edit-site/src/components/global-styles/palette.js b/packages/edit-site/src/components/global-styles/palette.js index 4d37b234eb9afe..0b4bbbbbb7f63e 100644 --- a/packages/edit-site/src/components/global-styles/palette.js +++ b/packages/edit-site/src/components/global-styles/palette.js @@ -49,7 +49,7 @@ function Palette( { name } ) { const screenPath = ! name ? '/colors/palette' - : '/blocks/' + name + '/colors/palette'; + : '/blocks/' + encodeURIComponent( name ) + '/colors/palette'; const paletteButtonText = colors.length > 0 ? sprintf( diff --git a/packages/edit-site/src/components/global-styles/screen-block-list.js b/packages/edit-site/src/components/global-styles/screen-block-list.js index a203a99ba276ab..30c03c17bec014 100644 --- a/packages/edit-site/src/components/global-styles/screen-block-list.js +++ b/packages/edit-site/src/components/global-styles/screen-block-list.js @@ -68,7 +68,7 @@ function BlockMenuItem( { block } ) { return ( diff --git a/packages/edit-site/src/components/global-styles/screen-block.js b/packages/edit-site/src/components/global-styles/screen-block.js index b9d2502ef8bc10..57860a8623c6ae 100644 --- a/packages/edit-site/src/components/global-styles/screen-block.js +++ b/packages/edit-site/src/components/global-styles/screen-block.js @@ -20,7 +20,10 @@ function ScreenBlock( { name } ) { - + ); } diff --git a/packages/edit-site/src/components/global-styles/screen-colors.js b/packages/edit-site/src/components/global-styles/screen-colors.js index 87d74604e63e14..c713cb5ee5818f 100644 --- a/packages/edit-site/src/components/global-styles/screen-colors.js +++ b/packages/edit-site/src/components/global-styles/screen-colors.js @@ -174,7 +174,8 @@ function ButtonColorItem( { name, parentMenu } ) { } function ScreenColors( { name } ) { - const parentMenu = name === undefined ? '' : '/blocks/' + name; + const parentMenu = + name === undefined ? '' : '/blocks/' + encodeURIComponent( name ); return ( <> diff --git a/packages/edit-site/src/components/global-styles/ui.js b/packages/edit-site/src/components/global-styles/ui.js index 8f7fa28e93eee6..532a211597a81f 100644 --- a/packages/edit-site/src/components/global-styles/ui.js +++ b/packages/edit-site/src/components/global-styles/ui.js @@ -43,7 +43,8 @@ function GlobalStylesNavigationScreen( { className, ...props } ) { } function ContextScreens( { name } ) { - const parentMenu = name === undefined ? '' : '/blocks/' + name; + const parentMenu = + name === undefined ? '' : '/blocks/' + encodeURIComponent( name ); return ( <> @@ -124,14 +125,27 @@ function ContextScreens( { name } ) { function GlobalStylesStyleBook( { onClose } ) { const navigator = useNavigator(); + const { path } = navigator.location; return ( - navigator.location.path.startsWith( '/blocks/' + blockName ) - } - onSelect={ ( blockName ) => - navigator.goTo( '/blocks/' + blockName ) + // Match '/blocks/core%2Fbutton' and + // '/blocks/core%2Fbutton/typography', but not + // '/blocks/core%2Fbuttons'. + path === `/blocks/${ encodeURIComponent( blockName ) }` || + path.startsWith( + `/blocks/${ encodeURIComponent( blockName ) }/` + ) } + onSelect={ ( blockName ) => { + // Clear navigator history by going back to the root. + const depth = path.match( /\//g ).length; + for ( let i = 0; i < depth; i++ ) { + navigator.goBack(); + } + // Now go to the selected block. + navigator.goTo( '/blocks/' + encodeURIComponent( blockName ) ); + } } onClose={ onClose } /> ); @@ -159,7 +173,7 @@ function GlobalStylesUI( { isStyleBookOpened, onCloseStyleBook } ) { { blocks.map( ( block ) => ( diff --git a/test/e2e/specs/site-editor/style-book.spec.js b/test/e2e/specs/site-editor/style-book.spec.js index 779e54322a9102..4f3d092a5c8d93 100644 --- a/test/e2e/specs/site-editor/style-book.spec.js +++ b/test/e2e/specs/site-editor/style-book.spec.js @@ -98,6 +98,24 @@ test.describe( 'Style Book', () => { ).toBeVisible(); } ); + test( 'should clear Global Styles navigator history when example is clicked', async ( { + page, + } ) => { + await page.click( 'role=button[name="Blocks styles"]' ); + await page.click( 'role=button[name="Heading block styles"]' ); + await page.click( 'role=button[name="Typography styles"]' ); + + await page.click( + 'role=button[name="Open Quote styles in Styles panel"i]' + ); + + await page.click( 'role=button[name="Navigate to the previous view"]' ); + + await expect( + page.locator( 'role=button[name="Navigate to the previous view"]' ) + ).not.toBeVisible(); + } ); + test( 'should disappear when closed', async ( { page } ) => { await page.click( 'role=region[name="Style Book"i] >> role=button[name="Close Style Book"i]'