CYS: Refactor routing approach (#48312)

* CYS: Refactor routing approach

* Add changefile(s) from automation for the following project(s): woocommerce

* remove focus logic

* remove routekey prop

* pass onNavigateBackClick callback as prop

* create dedicated CSS class

* lint css

---------

Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Luigi Teschio 2024-06-11 15:26:04 +02:00 committed by GitHub
parent 4921018e5a
commit af2946aa34
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 341 additions and 175 deletions

View File

@ -0,0 +1,42 @@
@mixin custom-scrollbars-on-hover($handle-color, $handle-color-hover) {
// WebKit
&::-webkit-scrollbar {
width: 12px;
height: 12px;
}
&::-webkit-scrollbar-track {
background-color: transparent;
}
&::-webkit-scrollbar-thumb {
background-color: $handle-color;
border-radius: 8px;
border: 3px solid transparent;
background-clip: padding-box;
}
&:hover::-webkit-scrollbar-thumb, // This needs specificity.
&:focus::-webkit-scrollbar-thumb,
&:focus-within::-webkit-scrollbar-thumb {
background-color: $handle-color-hover;
}
// Firefox 109+ and Chrome 111+
scrollbar-width: thin;
scrollbar-gutter: stable both-edges;
scrollbar-color: $handle-color transparent; // Syntax, "dark", "light", or "#handle-color #track-color"
&:hover,
&:focus,
&:focus-within {
scrollbar-color: $handle-color-hover transparent;
}
// Needed to fix a Safari rendering issue.
will-change: transform;
// Always show scrollbar on Mobile devices.
@media (hover: none) {
& {
scrollbar-color: $handle-color-hover transparent;
}
}
}

View File

@ -0,0 +1,53 @@
/**
* External dependencies
*/
import { createContext, useCallback, useState } from '@wordpress/element';
import clsx from 'clsx';
/**
* Internal dependencies
*/
import './style.scss';
export enum SidebarNavigationAnimationDirection {
Forward = 'forward',
Back = 'back',
}
type SidebarNavigationContextType = {
navigate: ( direction: SidebarNavigationAnimationDirection ) => void;
};
export const SidebarNavigationContext =
createContext< SidebarNavigationContextType >( {
navigate: () => void 0,
} );
export function SidebarContent( { children }: { children: JSX.Element } ) {
const [ navState, setNavState ] = useState< {
direction: SidebarNavigationAnimationDirection | null;
} >( {
direction: null,
} );
const navigate = useCallback(
( direction: SidebarNavigationAnimationDirection ) => {
setNavState( { direction } );
},
[]
);
const wrapperCls = clsx(
'woocommerce-customize-store-edit-site-sidebar__screen-wrapper',
{
'slide-from-left': navState.direction === 'back',
'slide-from-right': navState.direction === 'forward',
}
);
return (
<SidebarNavigationContext.Provider value={ { navigate } }>
<div className={ wrapperCls }>{ children }</div>
</SidebarNavigationContext.Provider>
);
}

View File

@ -0,0 +1,49 @@
@import "../_mixins.scss";
.woocommerce-customize-store-edit-site-sidebar__screen-wrapper {
height: 100%;
overflow-x: auto;
@include custom-scrollbars-on-hover(transparent, $gray-700);
// This matches the logo padding
padding: 0 $grid-unit-15;
// Animation
animation-duration: 0.14s;
animation-timing-function: ease-in-out;
will-change: transform, opacity;
@media (prefers-reduced-motion: reduce) {
animation-duration: 0s;
}
&.slide-from-left {
animation-name: slide-from-left;
}
&.slide-from-right {
animation-name: slide-from-right;
}
}
@keyframes slide-from-right {
from {
transform: translateX(50px);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
@keyframes slide-from-left {
from {
transform: translateX(-50px);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}

View File

@ -4,153 +4,114 @@
/**
* External dependencies
*/
import { memo, useRef, useEffect } from '@wordpress/element';
import {
// @ts-ignore No types for this exist yet.
__experimentalNavigatorProvider as NavigatorProvider,
// @ts-ignore No types for this exist yet.
__experimentalNavigatorScreen as NavigatorScreen,
// @ts-ignore No types for this exist yet.
__experimentalUseNavigator as useNavigator,
} from '@wordpress/components';
import { memo, useCallback, useContext } from '@wordpress/element';
/**
* Internal dependencies
*/
import { SidebarNavigationScreenMain } from './sidebar-navigation-screen-main';
import { SidebarNavigationScreenColorPalette } from './sidebar-navigation-screen-color-palette';
import { SidebarNavigationScreenTypography } from './sidebar-navigation-screen-typography';
import { SidebarNavigationScreenFooter } from './sidebar-navigation-screen-footer';
import { SidebarNavigationScreenHeader } from './sidebar-navigation-screen-header';
import { SidebarNavigationScreenHomepage } from './sidebar-navigation-screen-homepage';
import { SidebarNavigationScreenFooter } from './sidebar-navigation-screen-footer';
import { SidebarNavigationScreenMain } from './sidebar-navigation-screen-main';
import { SidebarNavigationScreenTypography } from './sidebar-navigation-screen-typography';
// import { SidebarNavigationScreenPages } from './sidebar-navigation-screen-pages';
import { SidebarNavigationScreenLogo } from './sidebar-navigation-screen-logo';
import { getNewPath, navigateTo, useQuery } from '@woocommerce/navigation';
import { SaveHub } from './save-hub';
import {
addHistoryListener,
getQuery,
updateQueryString,
useQuery,
} from '@woocommerce/navigation';
// In some cases, the assembler is loaded in an iframe, so we have to re-apply the filter.
import '~/customize-store/design-with-ai/entrepreneur-flow';
import {
SidebarContent,
SidebarNavigationAnimationDirection,
SidebarNavigationContext,
} from '../components/sidebar';
import { SidebarNavigationScreenLogo } from './sidebar-navigation-screen-logo';
function isSubset(
subset: {
[ key: string ]: string | undefined;
},
superset: {
[ key: string ]: string | undefined;
const getComponentByPathParams = (
params: string,
onNavigateBackClick: () => void
) => {
if ( params === '/customize-store/assembler-hub' ) {
return <SidebarNavigationScreenMain />;
}
) {
return Object.entries( subset ).every( ( [ key, value ] ) => {
return superset[ key ] === value;
} );
}
function useSyncPathWithURL() {
const urlParams = useQuery();
const {
location: navigatorLocation,
params: navigatorParams,
goTo,
} = useNavigator();
const isMounting = useRef( true );
if ( params === '/customize-store/assembler-hub/color-palette' ) {
return (
<SidebarNavigationScreenColorPalette
onNavigateBackClick={ onNavigateBackClick }
/>
);
}
useEffect(
() => {
// The navigatorParams are only initially filled properly after the
// navigator screens mounts. so we don't do the query string update initially.
// however we also do want to add an event listener for popstate so that we can
// update the navigator when the user navigates using the browser back button
if ( isMounting.current ) {
isMounting.current = false;
addHistoryListener( ( event: PopStateEvent ) => {
if ( event.type === 'popstate' ) {
goTo( ( getQuery() as Record< string, string > ).path );
}
} );
return;
}
if ( params === '/customize-store/assembler-hub/logo' ) {
return (
<SidebarNavigationScreenLogo
onNavigateBackClick={ onNavigateBackClick }
/>
);
}
function updateUrlParams( newUrlParams: {
[ key: string ]: string | undefined;
} ) {
if ( isSubset( newUrlParams, urlParams ) ) {
return;
}
const updatedParams = {
...urlParams,
...newUrlParams,
};
updateQueryString( {}, updatedParams.path );
}
if ( params === '/customize-store/assembler-hub/typography' ) {
return (
<SidebarNavigationScreenTypography
onNavigateBackClick={ onNavigateBackClick }
/>
);
}
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 ]
);
}
if ( params === '/customize-store/assembler-hub/header' ) {
return (
<SidebarNavigationScreenHeader
onNavigateBackClick={ onNavigateBackClick }
/>
);
}
if ( params === '/customize-store/assembler-hub/homepage' ) {
return (
<SidebarNavigationScreenHomepage
onNavigateBackClick={ onNavigateBackClick }
/>
);
}
if ( params === '/customize-store/assembler-hub/footer' ) {
return (
<SidebarNavigationScreenFooter
onNavigateBackClick={ onNavigateBackClick }
/>
);
}
return <SidebarNavigationScreenMain />;
};
function SidebarScreens() {
useSyncPathWithURL();
return (
<>
<NavigatorScreen path="/customize-store/assembler-hub">
<SidebarNavigationScreenMain />
</NavigatorScreen>
<NavigatorScreen path="/customize-store/assembler-hub/color-palette">
<SidebarNavigationScreenColorPalette />
</NavigatorScreen>
<NavigatorScreen path="/customize-store/assembler-hub/typography">
<SidebarNavigationScreenTypography />
</NavigatorScreen>
<NavigatorScreen path="/customize-store/assembler-hub/header">
<SidebarNavigationScreenHeader />
</NavigatorScreen>
<NavigatorScreen path="/customize-store/assembler-hub/homepage">
<SidebarNavigationScreenHomepage />
</NavigatorScreen>
<NavigatorScreen path="/customize-store/assembler-hub/footer">
<SidebarNavigationScreenFooter />
</NavigatorScreen>
{ /* TODO: Implement pages sidebar in Phrase 2 */ }
{ /* <NavigatorScreen path="/customize-store/assembler-hub/pages">
<SidebarNavigationScreenPages />
</NavigatorScreen> */ }
<NavigatorScreen path="/customize-store/assembler-hub/logo">
<SidebarNavigationScreenLogo />
</NavigatorScreen>
</>
);
const params = useQuery().path;
const { navigate } = useContext( SidebarNavigationContext );
const onNavigateBackClick = useCallback( () => {
const assemblerUrl = getNewPath(
{ customizing: true },
'/customize-store/assembler-hub',
{}
);
navigateTo( { url: assemblerUrl } );
navigate( SidebarNavigationAnimationDirection.Back );
}, [ navigate ] );
return <>{ getComponentByPathParams( params, onNavigateBackClick ) }</>;
}
function Sidebar() {
const urlParams = getQuery() as Record< string, string >;
const initialPath = useRef(
urlParams.path ?? '/customize-store/assembler-hub'
);
return (
<>
<NavigatorProvider
className="edit-site-sidebar__content"
initialPath={ initialPath.current }
>
<SidebarContent>
<SidebarScreens />
<SaveHub />
</NavigatorProvider>
</SidebarContent>
<SaveHub />
</>
);
}

View File

@ -55,7 +55,11 @@ const SidebarNavigationScreenColorPaletteContent = () => {
);
};
export const SidebarNavigationScreenColorPalette = () => {
export const SidebarNavigationScreenColorPalette = ( {
onNavigateBackClick,
}: {
onNavigateBackClick: () => void;
} ) => {
const {
context: { flowType },
} = useContext( CustomizeStoreContext );
@ -78,6 +82,7 @@ export const SidebarNavigationScreenColorPalette = () => {
return (
<SidebarNavigationScreen
title={ title }
onNavigateBackClick={ onNavigateBackClick }
description={ createInterpolateElement( description, {
EditorLink: (
<Link

View File

@ -40,7 +40,11 @@ const SUPPORTED_FOOTER_PATTERNS = [
'woocommerce-blocks/footer-large',
];
export const SidebarNavigationScreenFooter = () => {
export const SidebarNavigationScreenFooter = ( {
onNavigateBackClick,
}: {
onNavigateBackClick: () => void;
} ) => {
const { scroll } = useEditorScroll( {
editorSelector: '.woocommerce-customize-store__block-editor iframe',
scrollDirection: 'bottom',
@ -57,7 +61,7 @@ export const SidebarNavigationScreenFooter = () => {
const [ mainTemplateBlocks ] = useEditorBlocks(
'wp_template',
currentTemplate.id
currentTemplate?.id ?? ''
);
const [ blocks, , onChange ] = useEditorBlocks(
@ -142,7 +146,10 @@ export const SidebarNavigationScreenFooter = () => {
return (
<SidebarNavigationScreen
title={ title }
onNavigateBackClick={ resetHighlightedBlockClientId }
onNavigateBackClick={ () => {
resetHighlightedBlockClientId();
onNavigateBackClick();
} }
description={ createInterpolateElement( description, {
EditorLink: (
<Link

View File

@ -40,8 +40,11 @@ const SUPPORTED_HEADER_PATTERNS = [
'woocommerce-blocks/header-minimal',
'woocommerce-blocks/header-large',
];
export const SidebarNavigationScreenHeader = () => {
export const SidebarNavigationScreenHeader = ( {
onNavigateBackClick,
}: {
onNavigateBackClick: () => void;
} ) => {
const { scroll } = useEditorScroll( {
editorSelector: '.woocommerce-customize-store__block-editor iframe',
scrollDirection: 'top',
@ -58,7 +61,7 @@ export const SidebarNavigationScreenHeader = () => {
const [ mainTemplateBlocks ] = useEditorBlocks(
'wp_template',
currentTemplate.id
currentTemplate?.id ?? ''
);
const [ blocks, , onChange ] = useEditorBlocks(
@ -128,7 +131,10 @@ export const SidebarNavigationScreenHeader = () => {
return (
<SidebarNavigationScreen
title={ title }
onNavigateBackClick={ resetHighlightedBlockClientId }
onNavigateBackClick={ () => {
resetHighlightedBlockClientId();
onNavigateBackClick();
} }
description={ createInterpolateElement(
__(
"Select a new header from the options below. Your header includes your site's navigation and will be added to every page. You can continue customizing this via the <EditorLink>Editor</EditorLink>.",

View File

@ -55,7 +55,11 @@ import { isIframe, sendMessageToParent } from '~/customize-store/utils';
const { GlobalStylesContext } = unlock( blockEditorPrivateApis );
export const SidebarNavigationScreenHomepage = () => {
export const SidebarNavigationScreenHomepage = ( {
onNavigateBackClick,
}: {
onNavigateBackClick: () => void;
} ) => {
const { scroll } = useEditorScroll( {
editorSelector: '.woocommerce-customize-store__block-editor iframe',
scrollDirection: 'top',
@ -276,6 +280,7 @@ export const SidebarNavigationScreenHomepage = () => {
return (
<SidebarNavigationScreen
title={ title }
onNavigateBackClick={ onNavigateBackClick }
description={ createInterpolateElement( sidebarMessage, {
EditorLink: (
<Link

View File

@ -370,7 +370,11 @@ const LogoEdit = ( {
);
};
export const SidebarNavigationScreenLogo = () => {
export const SidebarNavigationScreenLogo = ( {
onNavigateBackClick,
}: {
onNavigateBackClick: () => void;
} ) => {
// Get the current logo block client ID and attributes. These are used for the logo settings.
const { logoBlockIds } = useContext( LogoBlockContext );
const { attributes, isAttributesLoading } = useLogoAttributes();
@ -440,6 +444,7 @@ export const SidebarNavigationScreenLogo = () => {
"Ensure your store is on-brand by adding your logo. For best results, upload a SVG or PNG that's a minimum of 300px wide.",
'woocommerce'
) }
onNavigateBackClick={ onNavigateBackClick }
content={
<div className="woocommerce-customize-store__sidebar-logo-content">
<div className="woocommerce-customize-store__sidebar-group-header woocommerce-customize-store__logo-header-container">

View File

@ -33,12 +33,18 @@ import { ADMIN_URL } from '~/utils/admin-settings';
import { CustomizeStoreContext } from '~/customize-store/assembler-hub';
import { FlowType } from '~/customize-store/types';
import { trackEvent } from '~/customize-store/tracking';
import { getNewPath, navigateTo } from '@woocommerce/navigation';
import {
SidebarNavigationAnimationDirection,
SidebarNavigationContext,
} from '../components/sidebar';
export const SidebarNavigationScreenMain = () => {
const {
context: { flowType },
} = useContext( CustomizeStoreContext );
const aiOnline = flowType === FlowType.AIOnline;
const { navigate } = useContext( SidebarNavigationContext );
return (
<SidebarNavigationScreen
@ -84,6 +90,16 @@ export const SidebarNavigationScreenMain = () => {
withChevron
icon={ siteLogo }
onClick={ () => {
const logoUrl = getNewPath(
{ customizing: true },
'/customize-store/assembler-hub/logo',
{}
);
navigateTo( { url: logoUrl } );
navigate(
SidebarNavigationAnimationDirection.Forward
);
trackEvent(
'customize_your_store_assembler_hub_sidebar_item_click',
{
@ -100,6 +116,16 @@ export const SidebarNavigationScreenMain = () => {
withChevron
icon={ color }
onClick={ () => {
const colorPaletteUrl = getNewPath(
{ customizing: true },
'/customize-store/assembler-hub/color-palette',
{}
);
navigateTo( { url: colorPaletteUrl } );
navigate(
SidebarNavigationAnimationDirection.Forward
);
trackEvent(
'customize_your_store_assembler_hub_sidebar_item_click',
{
@ -124,6 +150,16 @@ export const SidebarNavigationScreenMain = () => {
withChevron
icon={ typography }
onClick={ () => {
const typographyUrl = getNewPath(
{ customizing: true },
'/customize-store/assembler-hub/typography',
{}
);
navigateTo( { url: typographyUrl } );
navigate(
SidebarNavigationAnimationDirection.Forward
);
trackEvent(
'customize_your_store_assembler_hub_sidebar_item_click',
{
@ -149,6 +185,16 @@ export const SidebarNavigationScreenMain = () => {
withChevron
icon={ header }
onClick={ () => {
const headerUrl = getNewPath(
{ customizing: true },
'/customize-store/assembler-hub/header',
{}
);
navigateTo( { url: headerUrl } );
navigate(
SidebarNavigationAnimationDirection.Forward
);
trackEvent(
'customize_your_store_assembler_hub_sidebar_item_click',
{
@ -167,6 +213,16 @@ export const SidebarNavigationScreenMain = () => {
withChevron
icon={ home }
onClick={ () => {
const homepageUrl = getNewPath(
{ customizing: true },
'/customize-store/assembler-hub/homepage',
{}
);
navigateTo( { url: homepageUrl } );
navigate(
SidebarNavigationAnimationDirection.Forward
);
trackEvent(
'customize_your_store_assembler_hub_sidebar_item_click',
{
@ -185,6 +241,16 @@ export const SidebarNavigationScreenMain = () => {
withChevron
icon={ footer }
onClick={ () => {
const footerUrl = getNewPath(
{ customizing: true },
'/customize-store/assembler-hub/footer',
{}
);
navigateTo( { url: footerUrl } );
navigate(
SidebarNavigationAnimationDirection.Forward
);
trackEvent(
'customize_your_store_assembler_hub_sidebar_item_click',
{

View File

@ -25,7 +25,12 @@ import { CustomizeStoreContext } from '..';
import { FlowType } from '~/customize-store/types';
import { isIframe, sendMessageToParent } from '~/customize-store/utils';
import { trackEvent } from '~/customize-store/tracking';
export const SidebarNavigationScreenTypography = () => {
export const SidebarNavigationScreenTypography = ( {
onNavigateBackClick,
}: {
onNavigateBackClick: () => void;
} ) => {
const { context, sendEvent } = useContext( CustomizeStoreContext );
const aiOnline = context.flowType === FlowType.AIOnline;
const isFontLibraryAvailable = context.isFontLibraryAvailable;
@ -91,6 +96,7 @@ export const SidebarNavigationScreenTypography = () => {
return (
<SidebarNavigationScreen
title={ title }
onNavigateBackClick={ onNavigateBackClick }
description={ createInterpolateElement( label, {
EditorLink: (
<Link

View File

@ -1,46 +1,3 @@
@mixin custom-scrollbars-on-hover($handle-color, $handle-color-hover) {
// WebKit
&::-webkit-scrollbar {
width: 12px;
height: 12px;
}
&::-webkit-scrollbar-track {
background-color: transparent;
}
&::-webkit-scrollbar-thumb {
background-color: $handle-color;
border-radius: 8px;
border: 3px solid transparent;
background-clip: padding-box;
}
&:hover::-webkit-scrollbar-thumb, // This needs specificity.
&:focus::-webkit-scrollbar-thumb,
&:focus-within::-webkit-scrollbar-thumb {
background-color: $handle-color-hover;
}
// Firefox 109+ and Chrome 111+
scrollbar-width: thin;
scrollbar-gutter: stable both-edges;
scrollbar-color: $handle-color transparent; // Syntax, "dark", "light", or "#handle-color #track-color"
&:hover,
&:focus,
&:focus-within {
scrollbar-color: $handle-color-hover transparent;
}
// Needed to fix a Safari rendering issue.
will-change: transform;
// Always show scrollbar on Mobile devices.
@media (hover: none) {
& {
scrollbar-color: $handle-color-hover transparent;
}
}
}
@keyframes containerFadeIn {
0%,
80% {

View File

@ -0,0 +1,4 @@
Significance: minor
Type: tweak
CYS: Refactor routing approach. </details> <details> <summary>Changelog Entry Comment</summary>