Skip to content

Commit

Permalink
Site Editor: Make sidebar back button go *back* instead of *up* if po…
Browse files Browse the repository at this point in the history
…ssible (#52456)

* Navigator: Add replace option to goTo() and goToParent()

* Site Editor: Make sidebar back button go back instead of up if possible
  • Loading branch information
noisysocks authored and tellthemachines committed Jul 14, 2023
1 parent 56a3806 commit bd02332
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 96 deletions.
4 changes: 4 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Enhancements

- `Navigator`: Add `replace` option to `navigator.goTo()` and `navigator.goToParent()` ([#52456](https://github.com/WordPress/gutenberg/pull/52456)).

### Bug Fix

- `UnitControl`: Fix crash when certain units are used ([#52211](https://github.com/WordPress/gutenberg/pull/52211)).
Expand Down
53 changes: 30 additions & 23 deletions packages/components/src/navigator/navigator-provider/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ function UnconnectedNavigatorProvider(
focusTargetSelector,
isBack = false,
skipFocus = false,
replace = false,
...restOptions
} = options;

Expand All @@ -172,34 +173,38 @@ function UnconnectedNavigatorProvider(
skipFocus,
};

if ( prevLocationHistory.length < 1 ) {
return [ newLocation ];
if ( prevLocationHistory.length === 0 ) {
return replace ? [] : [ newLocation ];
}

return [
...prevLocationHistory.slice(
prevLocationHistory.length > MAX_HISTORY_LENGTH - 1
? 1
: 0,
-1
),
// Assign `focusTargetSelector` to the previous location in history
// (the one we just navigated from).
{
...prevLocationHistory[
prevLocationHistory.length - 1
],
focusTargetSelector,
},
newLocation,
];
const newLocationHistory = prevLocationHistory.slice(
prevLocationHistory.length > MAX_HISTORY_LENGTH - 1 ? 1 : 0,
-1
);

if ( ! replace ) {
newLocationHistory.push(
// Assign `focusTargetSelector` to the previous location in history
// (the one we just navigated from).
{
...prevLocationHistory[
prevLocationHistory.length - 1
],
focusTargetSelector,
}
);
}

newLocationHistory.push( newLocation );

return newLocationHistory;
} );
},
[ goBack ]
);

const goToParent: NavigatorContextType[ 'goToParent' ] =
useCallback( () => {
const goToParent: NavigatorContextType[ 'goToParent' ] = useCallback(
( options = {} ) => {
const currentPath =
currentLocationHistory.current[
currentLocationHistory.current.length - 1
Expand All @@ -214,8 +219,10 @@ function UnconnectedNavigatorProvider(
if ( parentPath === undefined ) {
return;
}
goTo( parentPath, { isBack: true } );
}, [ goTo ] );
goTo( parentPath, { ...options, isBack: true } );
},
[ goTo ]
);

const navigatorContextValue: NavigatorContextType = useMemo(
() => ( {
Expand Down
5 changes: 4 additions & 1 deletion packages/components/src/navigator/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ export type NavigateOptions = {
focusTargetSelector?: string;
isBack?: boolean;
skipFocus?: boolean;
replace?: boolean;
};

export type NavigateToParentOptions = Omit< NavigateOptions, 'isBack' >;

export type NavigatorLocation = NavigateOptions & {
isInitial?: boolean;
path?: string;
Expand All @@ -28,7 +31,7 @@ export type Navigator = {
params: MatchParams;
goTo: ( path: string, options?: NavigateOptions ) => void;
goBack: () => void;
goToParent: () => void;
goToParent: ( options?: NavigateToParentOptions ) => void;
};

export type NavigatorContext = Navigator & {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import {
__experimentalHStack as HStack,
__experimentalHeading as Heading,
__experimentalNavigatorToParentButton as NavigatorToParentButton,
__experimentalUseNavigator as useNavigator,
__experimentalVStack as VStack,
} from '@wordpress/components';
Expand Down Expand Up @@ -41,7 +40,7 @@ export default function SidebarNavigationScreen( {
};
}, [] );
const { getTheme } = useSelect( coreStore );
const { goTo } = useNavigator();
const navigator = useNavigator();
const theme = getTheme( currentlyPreviewingTheme() );
const icon = isRTL() ? chevronRight : chevronLeft;

Expand All @@ -58,16 +57,24 @@ export default function SidebarNavigationScreen( {
className="edit-site-sidebar-navigation-screen__title-icon"
>
{ ! isRoot && ! backPath && (
<NavigatorToParentButton
as={ SidebarButton }
icon={ isRTL() ? chevronRight : chevronLeft }
<SidebarButton
onClick={ () => {
if ( navigator.location.isInitial ) {
navigator.goToParent( { replace: true } );
} else {
navigator.goBack();
}
} }
icon={ icon }
label={ __( 'Back' ) }
showTooltip={ false }
/>
) }
{ ! isRoot && backPath && (
<SidebarButton
onClick={ () => goTo( backPath, { isBack: true } ) }
onClick={ () =>
navigator.goTo( backPath, { isBack: true } )
}
icon={ icon }
label={ __( 'Back' ) }
showTooltip={ false }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ export function getPathFromURL( urlParams ) {
return path;
}

function isSubset( subset, superset ) {
return Object.entries( subset ).every( ( [ key, value ] ) => {
return superset[ key ] === value;
} );
}

export default function useSyncPathWithURL() {
const history = useHistory();
const { params: urlParams } = useLocation();
Expand All @@ -44,76 +50,77 @@ export default function useSyncPathWithURL() {
params: navigatorParams,
goTo,
} = useNavigator();
const currentUrlParams = useRef( urlParams );
const currentPath = useRef( navigatorLocation.path );
const isMounting = useRef( true );

useEffect( () => {
// The navigatorParams are only initially filled properly when the
// navigator screens mount. so we ignore the first synchronisation.
if ( isMounting.current ) {
isMounting.current = false;
return;
}

function updateUrlParams( newUrlParams ) {
if (
Object.entries( newUrlParams ).every( ( [ key, value ] ) => {
return currentUrlParams.current[ key ] === value;
} )
) {
useEffect(
() => {
// The navigatorParams are only initially filled properly when the
// navigator screens mount. so we ignore the first synchronisation.
if ( isMounting.current ) {
isMounting.current = false;
return;
}
const updatedParams = {
...currentUrlParams.current,
...newUrlParams,
};
currentUrlParams.current = updatedParams;
history.push( updatedParams );
}

if ( navigatorParams?.postType && navigatorParams?.postId ) {
updateUrlParams( {
postType: navigatorParams?.postType,
postId: navigatorParams?.postId,
path: undefined,
} );
} else if (
navigatorLocation.path.startsWith( '/page/' ) &&
navigatorParams?.postId
) {
updateUrlParams( {
postType: 'page',
postId: navigatorParams?.postId,
path: undefined,
} );
} else if ( navigatorLocation.path === '/patterns' ) {
updateUrlParams( {
postType: undefined,
postId: undefined,
canvas: undefined,
path: navigatorLocation.path,
} );
} else {
updateUrlParams( {
postType: undefined,
postId: undefined,
categoryType: undefined,
categoryId: undefined,
path:
navigatorLocation.path === '/'
? undefined
: navigatorLocation.path,
} );
}
}, [ navigatorLocation?.path, navigatorParams, history ] );
function updateUrlParams( newUrlParams ) {
if ( isSubset( newUrlParams, urlParams ) ) {
return;
}
const updatedParams = {
...urlParams,
...newUrlParams,
};
history.push( updatedParams );
}

useEffect( () => {
currentUrlParams.current = urlParams;
const path = getPathFromURL( urlParams );
if ( currentPath.current !== path ) {
currentPath.current = path;
goTo( path );
}
}, [ urlParams, goTo ] );
if ( navigatorParams?.postType && navigatorParams?.postId ) {
updateUrlParams( {
postType: navigatorParams?.postType,
postId: navigatorParams?.postId,
path: undefined,
} );
} else if (
navigatorLocation.path.startsWith( '/page/' ) &&
navigatorParams?.postId
) {
updateUrlParams( {
postType: 'page',
postId: navigatorParams?.postId,
path: undefined,
} );
} else if ( navigatorLocation.path === '/patterns' ) {
updateUrlParams( {
postType: undefined,
postId: undefined,
canvas: undefined,
path: navigatorLocation.path,
} );
} else {
updateUrlParams( {
postType: undefined,
postId: undefined,
categoryType: undefined,
categoryId: undefined,
path:
navigatorLocation.path === '/'
? undefined
: navigatorLocation.path,
} );
}
},
// Trigger only when navigator changes to prevent infinite loops.
// eslint-disable-next-line react-hooks/exhaustive-deps
[ navigatorLocation?.path, navigatorParams ]
);

useEffect(
() => {
const path = getPathFromURL( urlParams );
if ( navigatorLocation.path !== path ) {
goTo( path );
}
},
// Trigger only when URL changes to prevent infinite loops.
// eslint-disable-next-line react-hooks/exhaustive-deps
[ urlParams ]
);
}

0 comments on commit bd02332

Please sign in to comment.