From 58362df3d20b4ad3b2c7c9e7eae7e7999702c85f Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Tue, 22 Oct 2024 11:39:11 +0100 Subject: [PATCH] Site Editor: Remove synchronization of canvas mode into store (#66213) Co-authored-by: youknowriad Co-authored-by: ramonjd Co-authored-by: ntsekouras --- .../block-editor/use-editor-iframe-props.js | 40 +++---- .../block-editor/use-site-editor-settings.js | 19 ++-- .../edit-site/src/components/editor/index.js | 41 ++++--- .../editor/use-adapt-editor-to-canvas.js | 53 ++++++++++ .../components/global-styles-sidebar/index.js | 81 +++++++------- .../components/keyboard-shortcuts/global.js | 8 +- .../edit-site/src/components/layout/index.js | 39 +++---- .../src/components/resizable-frame/index.js | 29 +++-- .../src/components/save-panel/index.js | 60 +++++------ .../index.js | 76 ++++++++----- .../use-sync-canvas-mode-with-url.js | 73 ------------- .../src/hooks/commands/use-common-commands.js | 100 +++++++++++------- .../hooks/commands/use-edit-mode-commands.js | 32 +++--- .../hooks/commands/use-set-command-context.js | 16 ++- .../edit-site/src/store/private-actions.js | 79 -------------- .../edit-site/src/store/private-selectors.js | 11 -- packages/edit-site/src/store/reducer.js | 18 ---- packages/router/src/history.ts | 36 ++++++- 18 files changed, 387 insertions(+), 424 deletions(-) create mode 100644 packages/edit-site/src/components/editor/use-adapt-editor-to-canvas.js delete mode 100644 packages/edit-site/src/components/sync-state-with-url/use-sync-canvas-mode-with-url.js diff --git a/packages/edit-site/src/components/block-editor/use-editor-iframe-props.js b/packages/edit-site/src/components/block-editor/use-editor-iframe-props.js index 3b5c9f7fe65726..46719a00c16aad 100644 --- a/packages/edit-site/src/components/block-editor/use-editor-iframe-props.js +++ b/packages/edit-site/src/components/block-editor/use-editor-iframe-props.js @@ -6,37 +6,37 @@ import clsx from 'clsx'; /** * WordPress dependencies */ -import { useSelect, useDispatch } from '@wordpress/data'; +import { useSelect } from '@wordpress/data'; import { ENTER, SPACE } from '@wordpress/keycodes'; import { useState, useEffect } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { store as editorStore } from '@wordpress/editor'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; /** * Internal dependencies */ import { unlock } from '../../lock-unlock'; -import { store as editSiteStore } from '../../store'; -export default function useEditorIframeProps() { - const { canvasMode, currentPostIsTrashed } = useSelect( ( select ) => { - const { getCanvasMode } = unlock( select( editSiteStore ) ); +const { useLocation, useHistory } = unlock( routerPrivateApis ); - return { - canvasMode: getCanvasMode(), - currentPostIsTrashed: - select( editorStore ).getCurrentPostAttribute( 'status' ) === - 'trash', - }; +export default function useEditorIframeProps() { + const { params } = useLocation(); + const history = useHistory(); + const { canvas = 'view' } = params; + const currentPostIsTrashed = useSelect( ( select ) => { + return ( + select( editorStore ).getCurrentPostAttribute( 'status' ) === + 'trash' + ); }, [] ); - const { setCanvasMode } = unlock( useDispatch( editSiteStore ) ); const [ isFocused, setIsFocused ] = useState( false ); useEffect( () => { - if ( canvasMode === 'edit' ) { + if ( canvas === 'edit' ) { setIsFocused( false ); } - }, [ canvasMode ] ); + }, [ canvas ] ); // In view mode, make the canvas iframe be perceived and behave as a button // to switch to edit mode, with a meaningful label and no title attribute. @@ -55,11 +55,15 @@ export default function useEditorIframeProps() { ! currentPostIsTrashed ) { event.preventDefault(); - setCanvasMode( 'edit' ); + history.push( { ...params, canvas: 'edit' }, undefined, { + transition: 'canvas-mode-edit-transition', + } ); } }, onClick: () => { - setCanvasMode( 'edit' ); + history.push( { ...params, canvas: 'edit' }, undefined, { + transition: 'canvas-mode-edit-transition', + } ); }, onClickCapture: ( event ) => { if ( currentPostIsTrashed ) { @@ -72,8 +76,8 @@ export default function useEditorIframeProps() { return { className: clsx( 'edit-site-visual-editor__editor-canvas', { - 'is-focused': isFocused && canvasMode === 'view', + 'is-focused': isFocused && canvas === 'view', } ), - ...( canvasMode === 'view' ? viewModeIframeProps : {} ), + ...( canvas === 'view' ? viewModeIframeProps : {} ), }; } diff --git a/packages/edit-site/src/components/block-editor/use-site-editor-settings.js b/packages/edit-site/src/components/block-editor/use-site-editor-settings.js index e4d70402efa8be..dcdfb157b235b6 100644 --- a/packages/edit-site/src/components/block-editor/use-site-editor-settings.js +++ b/packages/edit-site/src/components/block-editor/use-site-editor-settings.js @@ -38,22 +38,25 @@ function useNavigateToPreviousEntityRecord() { } export function useSpecificEditorSettings() { + const { params } = useLocation(); + const { canvas = 'view' } = params; const onNavigateToEntityRecord = useNavigateToEntityRecord(); - const { canvasMode, settings, shouldUseTemplateAsDefaultRenderingMode } = - useSelect( ( select ) => { - const { getEditedPostContext, getCanvasMode, getSettings } = unlock( + const { settings, shouldUseTemplateAsDefaultRenderingMode } = useSelect( + ( select ) => { + const { getEditedPostContext, getSettings } = unlock( select( editSiteStore ) ); const _context = getEditedPostContext(); return { - canvasMode: getCanvasMode(), settings: getSettings(), // TODO: The `postType` check should be removed when the default rendering mode per post type is merged. // @see https://github.com/WordPress/gutenberg/pull/62304/ shouldUseTemplateAsDefaultRenderingMode: _context?.postId && _context?.postType !== 'post', }; - }, [] ); + }, + [] + ); const defaultRenderingMode = shouldUseTemplateAsDefaultRenderingMode ? 'template-locked' : 'post-only'; @@ -65,15 +68,15 @@ export function useSpecificEditorSettings() { richEditingEnabled: true, supportsTemplateMode: true, - focusMode: canvasMode !== 'view', + focusMode: canvas !== 'view', defaultRenderingMode, onNavigateToEntityRecord, onNavigateToPreviousEntityRecord, - __unstableIsPreviewMode: canvasMode === 'view', + __unstableIsPreviewMode: canvas === 'view', }; }, [ settings, - canvasMode, + canvas, defaultRenderingMode, onNavigateToEntityRecord, onNavigateToPreviousEntityRecord, diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index c2a7730c0fee56..9058a163707997 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -48,6 +48,7 @@ import SiteIcon from '../site-icon'; import useEditorIframeProps from '../block-editor/use-editor-iframe-props'; import useEditorTitle from './use-editor-title'; import { useIsSiteEditorLoading } from '../layout/hooks'; +import { useAdaptEditorToCanvas } from './use-adapt-editor-to-canvas'; const { Editor, BackButton } = unlock( editorPrivateApis ); const { useHistory, useLocation } = unlock( routerPrivateApis ); @@ -80,13 +81,14 @@ const siteIconVariants = { export default function EditSiteEditor( { isPostsList = false } ) { const disableMotion = useReducedMotion(); const { params } = useLocation(); + const { canvas = 'view' } = params; const isLoading = useIsSiteEditorLoading(); + useAdaptEditorToCanvas( canvas ); const { editedPostType, editedPostId, contextPostType, contextPostId, - canvasMode, isEditingPage, supportsGlobalStyles, showIconLabels, @@ -97,7 +99,6 @@ export default function EditSiteEditor( { isPostsList = false } ) { const { getEditorCanvasContainerView, getEditedPostContext, - getCanvasMode, isPage, getEditedPostType, getEditedPostId, @@ -114,7 +115,6 @@ export default function EditSiteEditor( { isPostsList = false } ) { editedPostId: getEditedPostId(), contextPostType: _context?.postId ? _context.postType : undefined, contextPostId: _context?.postId ? _context.postId : undefined, - canvasMode: getCanvasMode(), isEditingPage: isPage(), supportsGlobalStyles: getCurrentTheme()?.is_block_theme, showIconLabels: get( 'core', 'showIconLabels' ), @@ -129,7 +129,7 @@ export default function EditSiteEditor( { isPostsList = false } ) { const _isPreviewingTheme = isPreviewingTheme(); const hasDefaultEditorCanvasView = ! useHasEditorCanvasContainer(); const iframeProps = useEditorIframeProps(); - const isEditMode = canvasMode === 'edit'; + const isEditMode = canvas === 'edit'; const postWithTemplate = !! contextPostId; const loadingProgressId = useInstanceId( CanvasLoader, @@ -144,16 +144,15 @@ export default function EditSiteEditor( { isPostsList = false } ) { // Forming a "block formatting context" to prevent margin collapsing. // @see https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Block_formatting_context css: - canvasMode === 'view' + canvas === 'view' ? `body{min-height: 100vh; ${ currentPostIsTrashed ? '' : 'cursor: pointer;' }}` : undefined, }, ], - [ settings.styles, canvasMode, currentPostIsTrashed ] + [ settings.styles, canvas, currentPostIsTrashed ] ); - const { setCanvasMode } = unlock( useDispatch( editSiteStore ) ); const { __unstableSetEditorMode, resetZoomLevel } = unlock( useDispatch( blockEditorStore ) ); @@ -264,7 +263,6 @@ export default function EditSiteEditor( { isPostsList = false } ) { showTooltip tooltipPosition="middle right" onClick={ () => { - setCanvasMode( 'view' ); __unstableSetEditorMode( 'edit' ); @@ -276,10 +274,29 @@ export default function EditSiteEditor( { isPostsList = false } ) { isPostsList && params?.focusMode ) { - history.push( { - page: 'gutenberg-posts-dashboard', - postType: 'post', - } ); + history.push( + { + page: 'gutenberg-posts-dashboard', + postType: 'post', + }, + undefined, + { + transition: + 'canvas-mode-view-transition', + } + ); + } else { + history.push( + { + ...params, + canvas: undefined, + }, + undefined, + { + transition: + 'canvas-mode-view-transition', + } + ); } } } > diff --git a/packages/edit-site/src/components/editor/use-adapt-editor-to-canvas.js b/packages/edit-site/src/components/editor/use-adapt-editor-to-canvas.js new file mode 100644 index 00000000000000..a09adfb7a49d53 --- /dev/null +++ b/packages/edit-site/src/components/editor/use-adapt-editor-to-canvas.js @@ -0,0 +1,53 @@ +/** + * WordPress dependencies + */ +import { useDispatch, useSelect, useRegistry } from '@wordpress/data'; +import { store as blockEditorStore } from '@wordpress/block-editor'; +import { store as editorStore } from '@wordpress/editor'; +import { useLayoutEffect } from '@wordpress/element'; +import { store as preferencesStore } from '@wordpress/preferences'; + +export function useAdaptEditorToCanvas( canvas ) { + const { clearSelectedBlock } = useDispatch( blockEditorStore ); + const { + setDeviceType, + closePublishSidebar, + setIsListViewOpened, + setIsInserterOpened, + } = useDispatch( editorStore ); + const { get: getPreference } = useSelect( preferencesStore ); + const registry = useRegistry(); + useLayoutEffect( () => { + const isMediumOrBigger = + window.matchMedia( '(min-width: 782px)' ).matches; + registry.batch( () => { + clearSelectedBlock(); + setDeviceType( 'Desktop' ); + closePublishSidebar(); + setIsInserterOpened( false ); + + // Check if the block list view should be open by default. + // If `distractionFree` mode is enabled, the block list view should not be open. + // This behavior is disabled for small viewports. + if ( + isMediumOrBigger && + canvas === 'edit' && + getPreference( 'core', 'showListViewByDefault' ) && + ! getPreference( 'core', 'distractionFree' ) + ) { + setIsListViewOpened( true ); + } else { + setIsListViewOpened( false ); + } + } ); + }, [ + canvas, + registry, + clearSelectedBlock, + setDeviceType, + closePublishSidebar, + setIsInserterOpened, + setIsListViewOpened, + getPreference, + ] ); +} diff --git a/packages/edit-site/src/components/global-styles-sidebar/index.js b/packages/edit-site/src/components/global-styles-sidebar/index.js index 2194f2edbc0f29..2b9a2669a96fe6 100644 --- a/packages/edit-site/src/components/global-styles-sidebar/index.js +++ b/packages/edit-site/src/components/global-styles-sidebar/index.js @@ -11,6 +11,7 @@ import { store as editorStore, privateApis as editorPrivateApis, } from '@wordpress/editor'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; /** * Internal dependencies @@ -23,8 +24,11 @@ import { store as coreStore } from '@wordpress/core-data'; import DefaultSidebar from './default-sidebar'; const { interfaceStore } = unlock( editorPrivateApis ); +const { useLocation } = unlock( routerPrivateApis ); export default function GlobalStylesSidebar() { + const { params } = useLocation(); + const { canvas = 'view' } = params; const { shouldClearCanvasContainerView, isStyleBookOpened, @@ -32,43 +36,48 @@ export default function GlobalStylesSidebar() { hasRevisions, isRevisionsOpened, isRevisionsStyleBookOpened, - } = useSelect( ( select ) => { - const { getActiveComplementaryArea } = select( interfaceStore ); - const { getEditorCanvasContainerView, getCanvasMode } = unlock( - select( editSiteStore ) - ); - const canvasContainerView = getEditorCanvasContainerView(); - const _isVisualEditorMode = - 'visual' === select( editorStore ).getEditorMode(); - const _isEditCanvasMode = 'edit' === getCanvasMode(); - const _showListViewByDefault = select( preferencesStore ).get( - 'core', - 'showListViewByDefault' - ); - const { getEntityRecord, __experimentalGetCurrentGlobalStylesId } = - select( coreStore ); + } = useSelect( + ( select ) => { + const { getActiveComplementaryArea } = select( interfaceStore ); + const { getEditorCanvasContainerView } = unlock( + select( editSiteStore ) + ); + const canvasContainerView = getEditorCanvasContainerView(); + const _isVisualEditorMode = + 'visual' === select( editorStore ).getEditorMode(); + const _isEditCanvasMode = 'edit' === canvas; + const _showListViewByDefault = select( preferencesStore ).get( + 'core', + 'showListViewByDefault' + ); + const { getEntityRecord, __experimentalGetCurrentGlobalStylesId } = + select( coreStore ); - const globalStylesId = __experimentalGetCurrentGlobalStylesId(); - const globalStyles = globalStylesId - ? getEntityRecord( 'root', 'globalStyles', globalStylesId ) - : undefined; + const globalStylesId = __experimentalGetCurrentGlobalStylesId(); + const globalStyles = globalStylesId + ? getEntityRecord( 'root', 'globalStyles', globalStylesId ) + : undefined; - return { - isStyleBookOpened: 'style-book' === canvasContainerView, - shouldClearCanvasContainerView: - 'edit-site/global-styles' !== - getActiveComplementaryArea( 'core' ) || - ! _isVisualEditorMode || - ! _isEditCanvasMode, - showListViewByDefault: _showListViewByDefault, - hasRevisions: - !! globalStyles?._links?.[ 'version-history' ]?.[ 0 ]?.count, - isRevisionsStyleBookOpened: - 'global-styles-revisions:style-book' === canvasContainerView, - isRevisionsOpened: - 'global-styles-revisions' === canvasContainerView, - }; - }, [] ); + return { + isStyleBookOpened: 'style-book' === canvasContainerView, + shouldClearCanvasContainerView: + 'edit-site/global-styles' !== + getActiveComplementaryArea( 'core' ) || + ! _isVisualEditorMode || + ! _isEditCanvasMode, + showListViewByDefault: _showListViewByDefault, + hasRevisions: + !! globalStyles?._links?.[ 'version-history' ]?.[ 0 ] + ?.count, + isRevisionsStyleBookOpened: + 'global-styles-revisions:style-book' === + canvasContainerView, + isRevisionsOpened: + 'global-styles-revisions' === canvasContainerView, + }; + }, + [ canvas ] + ); const { setEditorCanvasContainerView } = unlock( useDispatch( editSiteStore ) ); @@ -77,7 +86,7 @@ export default function GlobalStylesSidebar() { if ( shouldClearCanvasContainerView ) { setEditorCanvasContainerView( undefined ); } - }, [ shouldClearCanvasContainerView ] ); + }, [ shouldClearCanvasContainerView, setEditorCanvasContainerView ] ); const { setIsListViewOpened } = useDispatch( editorStore ); diff --git a/packages/edit-site/src/components/keyboard-shortcuts/global.js b/packages/edit-site/src/components/keyboard-shortcuts/global.js index 2e71cf88202069..8ab9723e42ea65 100644 --- a/packages/edit-site/src/components/keyboard-shortcuts/global.js +++ b/packages/edit-site/src/components/keyboard-shortcuts/global.js @@ -5,6 +5,7 @@ import { useShortcut } from '@wordpress/keyboard-shortcuts'; import { useDispatch, useSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; import { store as editorStore } from '@wordpress/editor'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; /** * Internal dependencies @@ -12,12 +13,14 @@ import { store as editorStore } from '@wordpress/editor'; import { store as editSiteStore } from '../../store'; import { unlock } from '../../lock-unlock'; +const { useHistory } = unlock( routerPrivateApis ); + function KeyboardShortcutsGlobal() { const { __experimentalGetDirtyEntityRecords, isSavingEntityRecord } = useSelect( coreStore ); const { hasNonPostEntityChanges } = useSelect( editorStore ); - const { getCanvasMode } = unlock( useSelect( editSiteStore ) ); const { setIsSaveViewOpened } = useDispatch( editSiteStore ); + const history = useHistory(); useShortcut( 'core/edit-site/save', ( event ) => { event.preventDefault(); @@ -28,7 +31,8 @@ function KeyboardShortcutsGlobal() { isSavingEntityRecord( record.kind, record.name, record.key ) ); const _hasNonPostEntityChanges = hasNonPostEntityChanges(); - const isViewMode = getCanvasMode() === 'view'; + const isViewMode = + history.getLocationWithParams().params.canvas === 'view'; if ( ( ! hasDirtyEntities || ! _hasNonPostEntityChanges || isSaving ) && ! isViewMode diff --git a/packages/edit-site/src/components/layout/index.js b/packages/edit-site/src/components/layout/index.js index 8c150039c6df81..3b9769d470f518 100644 --- a/packages/edit-site/src/components/layout/index.js +++ b/packages/edit-site/src/components/layout/index.js @@ -6,7 +6,6 @@ import clsx from 'clsx'; /** * WordPress dependencies */ -import { useSelect } from '@wordpress/data'; import { __unstableMotion as motion, __unstableAnimatePresence as AnimatePresence, @@ -27,12 +26,12 @@ import { privateApis as editorPrivateApis, } from '@wordpress/editor'; import { privateApis as coreCommandsPrivateApis } from '@wordpress/core-commands'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; /** * Internal dependencies */ import ErrorBoundary from '../error-boundary'; -import { store as editSiteStore } from '../../store'; import { default as SiteHub, SiteHubMobile } from '../site-hub'; import ResizableFrame from '../resizable-frame'; import { unlock } from '../../lock-unlock'; @@ -43,25 +42,20 @@ import useMovingAnimation from './animation'; import SidebarContent from '../sidebar'; import SaveHub from '../save-hub'; import SavePanel from '../save-panel'; -import useSyncCanvasModeWithURL from '../sync-state-with-url/use-sync-canvas-mode-with-url'; const { useCommands } = unlock( coreCommandsPrivateApis ); const { useGlobalStyle } = unlock( blockEditorPrivateApis ); const { NavigableRegion } = unlock( editorPrivateApis ); +const { useLocation } = unlock( routerPrivateApis ); const ANIMATION_DURATION = 0.3; export default function Layout( { route } ) { - useSyncCanvasModeWithURL(); + const { params } = useLocation(); + const { canvas = 'view' } = params; useCommands(); const isMobileViewport = useViewportMatch( 'medium', '<' ); const toggleRef = useRef(); - const { canvasMode } = useSelect( ( select ) => { - const { getCanvasMode } = unlock( select( editSiteStore ) ); - return { - canvasMode: getCanvasMode(), - }; - }, [] ); const navigateRegionsProps = useNavigateRegions(); const disableMotion = useReducedMotion(); const [ canvasResizer, canvasSize ] = useResizeObserver(); @@ -70,26 +64,19 @@ export default function Layout( { route } ) { useState( false ); const { name: routeKey, areas, widths } = route; const animationRef = useMovingAnimation( { - triggerAnimationOnChange: canvasMode, + triggerAnimationOnChange: routeKey + '-' + canvas, } ); const [ backgroundColor ] = useGlobalStyle( 'color.background' ); const [ gradientValue ] = useGlobalStyle( 'color.gradient' ); - const previousCanvaMode = usePrevious( canvasMode ); + const previousCanvaMode = usePrevious( canvas ); useEffect( () => { if ( previousCanvaMode === 'edit' ) { toggleRef.current?.focus(); } // Should not depend on the previous canvas mode value but the next. // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ canvasMode ] ); - - // Synchronizing the URL with the store value of canvasMode happens in an effect - // This condition ensures the component is only rendered after the synchronization happens - // which prevents any animations due to potential canvasMode value change. - if ( canvasMode === 'init' ) { - return null; - } + }, [ canvas ] ); return ( <> @@ -103,7 +90,7 @@ export default function Layout( { route } ) { 'edit-site-layout', navigateRegionsProps.className, { - 'is-full-canvas': canvasMode === 'edit', + 'is-full-canvas': canvas === 'edit', } ) } > @@ -118,7 +105,7 @@ export default function Layout( { route } ) { className="edit-site-layout__sidebar-region" > - { canvasMode === 'view' && ( + { canvas === 'view' && ( - { canvasMode !== 'edit' && ( + { canvas !== 'edit' && ( unlock( select( editSiteStore ) ).getCanvasMode(), - [] - ); - const { setCanvasMode } = unlock( useDispatch( editSiteStore ) ); + const FRAME_TRANSITION = { type: 'tween', duration: isResizing ? 0 : 0.5 }; const frameRef = useRef( null ); const resizableHandleHelpId = useInstanceId( @@ -158,7 +158,16 @@ function ResizableFrame( { setFrameSize( INITIAL_FRAME_SIZE ); } else { // Trigger full screen if the frame is resized far enough to the left. - setCanvasMode( 'edit' ); + history.push( + { + ...params, + canvas: 'edit', + }, + undefined, + { + transition: 'canvas-mode-edit-transition', + } + ); } }; @@ -237,7 +246,7 @@ function ResizableFrame( { } } } whileHover={ - canvasMode === 'view' + canvas === 'view' ? { scale: 1.005, transition: { @@ -275,7 +284,7 @@ function ResizableFrame( { onMouseOver={ () => setShouldShowHandle( true ) } onMouseOut={ () => setShouldShowHandle( false ) } handleComponent={ { - [ isRTL() ? 'right' : 'left' ]: canvasMode === 'view' && ( + [ isRTL() ? 'right' : 'left' ]: canvas === 'view' && ( <> { /* Disable reason: role="separator" does in fact support aria-valuenow */ } diff --git a/packages/edit-site/src/components/save-panel/index.js b/packages/edit-site/src/components/save-panel/index.js index 9b00a39fd78948..d7817d5b3c1bb2 100644 --- a/packages/edit-site/src/components/save-panel/index.js +++ b/packages/edit-site/src/components/save-panel/index.js @@ -15,6 +15,8 @@ import { import { useDispatch, useSelect } from '@wordpress/data'; import { __, sprintf } from '@wordpress/i18n'; import { store as coreStore } from '@wordpress/core-data'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; +import { useEffect } from '@wordpress/element'; /** * Internal dependencies @@ -27,6 +29,7 @@ import { isPreviewingTheme } from '../../utils/is-previewing-theme'; const { EntitiesSavedStatesExtensible, NavigableRegion } = unlock( privateApis ); +const { useLocation } = unlock( routerPrivateApis ); const EntitiesSavedStatesForPreview = ( { onClose } ) => { const isDirtyProps = useEntitiesSavedStatesIsDirty(); @@ -87,41 +90,36 @@ const _EntitiesSavedStates = ( { onClose, renderDialog = undefined } ) => { }; export default function SavePanel() { - const { isSaveViewOpen, canvasMode, isDirty, isSaving } = useSelect( - ( select ) => { - const { - __experimentalGetDirtyEntityRecords, - isSavingEntityRecord, - isResolving, - } = select( coreStore ); - const dirtyEntityRecords = __experimentalGetDirtyEntityRecords(); - const isActivatingTheme = isResolving( 'activateTheme' ); - const { isSaveViewOpened, getCanvasMode } = unlock( - select( editSiteStore ) - ); + const { params } = useLocation(); + const { canvas = 'view' } = params; + const { isSaveViewOpen, isDirty, isSaving } = useSelect( ( select ) => { + const { + __experimentalGetDirtyEntityRecords, + isSavingEntityRecord, + isResolving, + } = select( coreStore ); + const dirtyEntityRecords = __experimentalGetDirtyEntityRecords(); + const isActivatingTheme = isResolving( 'activateTheme' ); + const { isSaveViewOpened } = unlock( select( editSiteStore ) ); - // The currently selected entity to display. - // Typically template or template part in the site editor. - return { - isSaveViewOpen: isSaveViewOpened(), - canvasMode: getCanvasMode(), - isDirty: dirtyEntityRecords.length > 0, - isSaving: - dirtyEntityRecords.some( ( record ) => - isSavingEntityRecord( - record.kind, - record.name, - record.key - ) - ) || isActivatingTheme, - }; - }, - [] - ); + // The currently selected entity to display. + // Typically template or template part in the site editor. + return { + isSaveViewOpen: isSaveViewOpened(), + isDirty: dirtyEntityRecords.length > 0, + isSaving: + dirtyEntityRecords.some( ( record ) => + isSavingEntityRecord( record.kind, record.name, record.key ) + ) || isActivatingTheme, + }; + }, [] ); const { setIsSaveViewOpened } = useDispatch( editSiteStore ); const onClose = () => setIsSaveViewOpened( false ); + useEffect( () => { + setIsSaveViewOpened( false ); + }, [ canvas, setIsSaveViewOpened ] ); - if ( canvasMode === 'view' ) { + if ( canvas === 'view' ) { return isSaveViewOpen ? ( !! select( @@ -48,7 +51,16 @@ export function SidebarNavigationItemGlobalStyles( props ) { { ...props } onClick={ () => { // Switch to edit mode. - setCanvasMode( 'edit' ); + history.push( + { + ...params, + canvas: 'edit', + }, + undefined, + { + transition: 'canvas-mode-edit-transition', + } + ); // Open global styles sidebar. openGeneralSidebar( 'edit-site/global-styles' ); } } @@ -57,45 +69,51 @@ export function SidebarNavigationItemGlobalStyles( props ) { } export default function SidebarNavigationScreenGlobalStyles( { backPath } ) { + const history = useHistory(); + const { params } = useLocation(); + const { canvas = 'view' } = params; const { revisions, isLoading: isLoadingRevisions } = useGlobalStylesRevisions(); const { openGeneralSidebar } = useDispatch( editSiteStore ); const { setIsListViewOpened } = useDispatch( editorStore ); const isMobileViewport = useViewportMatch( 'medium', '<' ); - const { setCanvasMode, setEditorCanvasContainerView } = unlock( + const { setEditorCanvasContainerView } = unlock( useDispatch( editSiteStore ) ); - const { isViewMode, isStyleBookOpened, revisionsCount } = useSelect( - ( select ) => { - const { getCanvasMode, getEditorCanvasContainerView } = unlock( - select( editSiteStore ) - ); - const { getEntityRecord, __experimentalGetCurrentGlobalStylesId } = - select( coreStore ); - const globalStylesId = __experimentalGetCurrentGlobalStylesId(); - const globalStyles = globalStylesId - ? getEntityRecord( 'root', 'globalStyles', globalStylesId ) - : undefined; - return { - isViewMode: 'view' === getCanvasMode(), - isStyleBookOpened: - 'style-book' === getEditorCanvasContainerView(), - revisionsCount: - globalStyles?._links?.[ 'version-history' ]?.[ 0 ]?.count ?? - 0, - }; - }, - [] - ); + const { isStyleBookOpened, revisionsCount } = useSelect( ( select ) => { + const { getEditorCanvasContainerView } = unlock( + select( editSiteStore ) + ); + const { getEntityRecord, __experimentalGetCurrentGlobalStylesId } = + select( coreStore ); + const globalStylesId = __experimentalGetCurrentGlobalStylesId(); + const globalStyles = globalStylesId + ? getEntityRecord( 'root', 'globalStyles', globalStylesId ) + : undefined; + return { + isStyleBookOpened: 'style-book' === getEditorCanvasContainerView(), + revisionsCount: + globalStyles?._links?.[ 'version-history' ]?.[ 0 ]?.count ?? 0, + }; + }, [] ); const { set: setPreference } = useDispatch( preferencesStore ); const openGlobalStyles = useCallback( async () => { + history.push( + { + ...params, + canvas: 'edit', + }, + undefined, + { + transition: 'canvas-mode-edit-transition', + } + ); return Promise.all( [ setPreference( 'core', 'distractionFree', false ), - setCanvasMode( 'edit' ), openGeneralSidebar( 'edit-site/global-styles' ), ] ); - }, [ setCanvasMode, openGeneralSidebar, setPreference ] ); + }, [ history, params, openGeneralSidebar, setPreference ] ); const openStyleBook = useCallback( async () => { await openGlobalStyles(); @@ -166,7 +184,7 @@ export default function SidebarNavigationScreenGlobalStyles( { backPath } ) { } /> - { isStyleBookOpened && ! isMobileViewport && isViewMode && ( + { isStyleBookOpened && ! isMobileViewport && canvas === 'view' && ( false } diff --git a/packages/edit-site/src/components/sync-state-with-url/use-sync-canvas-mode-with-url.js b/packages/edit-site/src/components/sync-state-with-url/use-sync-canvas-mode-with-url.js deleted file mode 100644 index d9295f83ee2452..00000000000000 --- a/packages/edit-site/src/components/sync-state-with-url/use-sync-canvas-mode-with-url.js +++ /dev/null @@ -1,73 +0,0 @@ -/** - * WordPress dependencies - */ -import { useEffect, useRef } from '@wordpress/element'; -import { useSelect, useDispatch } from '@wordpress/data'; -import { privateApis as routerPrivateApis } from '@wordpress/router'; - -/** - * Internal dependencies - */ -import { store as editSiteStore } from '../../store'; -import { unlock } from '../../lock-unlock'; - -const { useLocation, useHistory } = unlock( routerPrivateApis ); - -export default function useSyncCanvasModeWithURL() { - const history = useHistory(); - const { params } = useLocation(); - const canvasMode = useSelect( - ( select ) => unlock( select( editSiteStore ) ).getCanvasMode(), - [] - ); - const { setCanvasMode } = unlock( useDispatch( editSiteStore ) ); - const currentCanvasModeRef = useRef( canvasMode ); - const { canvas: canvasInUrl } = params; - const currentCanvasInUrlRef = useRef( canvasInUrl ); - const currentUrlParamsRef = useRef( params ); - useEffect( () => { - currentUrlParamsRef.current = params; - }, [ params ] ); - - useEffect( () => { - currentCanvasModeRef.current = canvasMode; - if ( canvasMode === 'init' ) { - return; - } - - if ( - canvasMode === 'edit' && - currentCanvasInUrlRef.current !== canvasMode - ) { - history.push( { - ...currentUrlParamsRef.current, - canvas: 'edit', - } ); - } - - if ( - canvasMode === 'view' && - currentCanvasInUrlRef.current !== undefined - ) { - history.push( { - ...currentUrlParamsRef.current, - canvas: undefined, - } ); - } - }, [ canvasMode, history ] ); - - useEffect( () => { - currentCanvasInUrlRef.current = canvasInUrl; - if ( - canvasInUrl !== 'edit' && - currentCanvasModeRef.current !== 'view' - ) { - setCanvasMode( 'view' ); - } else if ( - canvasInUrl === 'edit' && - currentCanvasModeRef.current !== 'edit' - ) { - setCanvasMode( 'edit' ); - } - }, [ canvasInUrl, setCanvasMode ] ); -} diff --git a/packages/edit-site/src/hooks/commands/use-common-commands.js b/packages/edit-site/src/hooks/commands/use-common-commands.js index ca6e2d1c6b45dd..536817e88d3a47 100644 --- a/packages/edit-site/src/hooks/commands/use-common-commands.js +++ b/packages/edit-site/src/hooks/commands/use-common-commands.js @@ -29,13 +29,10 @@ const { useGlobalStylesReset } = unlock( blockEditorPrivateApis ); const { useHistory, useLocation } = unlock( routerPrivateApis ); function useGlobalStylesOpenStylesCommands() { - const { openGeneralSidebar, setCanvasMode } = unlock( - useDispatch( editSiteStore ) - ); + const { openGeneralSidebar } = unlock( useDispatch( editSiteStore ) ); const { params } = useLocation(); - const { getCanvasMode } = unlock( useSelect( editSiteStore ) ); + const { canvas = 'view' } = params; const history = useHistory(); - const isBlockBasedTheme = useSelect( ( select ) => { return select( coreStore ).getCurrentTheme().is_block_theme; }, [] ); @@ -57,22 +54,21 @@ function useGlobalStylesOpenStylesCommands() { canvas: 'edit', } ); } - if ( params.postId && getCanvasMode() !== 'edit' ) { - setCanvasMode( 'edit' ); + if ( params.postId && canvas !== 'edit' ) { + history.push( + { ...params, canvas: 'edit' }, + undefined, + { + transition: 'canvas-mode-edit-transition', + } + ); } openGeneralSidebar( 'edit-site/global-styles' ); }, icon: styles, }, ]; - }, [ - history, - openGeneralSidebar, - setCanvasMode, - getCanvasMode, - isBlockBasedTheme, - params.postId, - ] ); + }, [ history, openGeneralSidebar, params, canvas, isBlockBasedTheme ] ); return { isLoading: false, @@ -81,11 +77,9 @@ function useGlobalStylesOpenStylesCommands() { } function useGlobalStylesToggleWelcomeGuideCommands() { - const { openGeneralSidebar, setCanvasMode } = unlock( - useDispatch( editSiteStore ) - ); + const { openGeneralSidebar } = unlock( useDispatch( editSiteStore ) ); const { params } = useLocation(); - const { getCanvasMode } = unlock( useSelect( editSiteStore ) ); + const { canvas = 'view' } = params; const { set } = useDispatch( preferencesStore ); const history = useHistory(); @@ -110,8 +104,17 @@ function useGlobalStylesToggleWelcomeGuideCommands() { canvas: 'edit', } ); } - if ( params.postId && getCanvasMode() !== 'edit' ) { - setCanvasMode( 'edit' ); + if ( params.postId && canvas !== 'edit' ) { + history.push( + { + ...params, + canvas: 'edit', + }, + undefined, + { + transition: 'canvas-mode-edit-transition', + } + ); } openGeneralSidebar( 'edit-site/global-styles' ); set( 'core/edit-site', 'welcomeGuideStyles', true ); @@ -127,11 +130,10 @@ function useGlobalStylesToggleWelcomeGuideCommands() { }, [ history, openGeneralSidebar, - setCanvasMode, - getCanvasMode, + canvas, isBlockBasedTheme, set, - params.postId, + params, ] ); return { @@ -167,9 +169,11 @@ function useGlobalStylesResetCommands() { } function useGlobalStylesOpenCssCommands() { - const { openGeneralSidebar, setEditorCanvasContainerView, setCanvasMode } = - unlock( useDispatch( editSiteStore ) ); + const { openGeneralSidebar, setEditorCanvasContainerView } = unlock( + useDispatch( editSiteStore ) + ); const { params } = useLocation(); + const { canvas = 'view' } = params; const history = useHistory(); const { canEditCSS } = useSelect( ( select ) => { const { getEntityRecord, __experimentalGetCurrentGlobalStylesId } = @@ -184,7 +188,6 @@ function useGlobalStylesOpenCssCommands() { canEditCSS: !! globalStyles?._links?.[ 'wp:action-edit-css' ], }; }, [] ); - const { getCanvasMode } = unlock( useSelect( editSiteStore ) ); const commands = useMemo( () => { if ( ! canEditCSS ) { @@ -204,8 +207,17 @@ function useGlobalStylesOpenCssCommands() { canvas: 'edit', } ); } - if ( params.postId && getCanvasMode() !== 'edit' ) { - setCanvasMode( 'edit' ); + if ( params.postId && canvas !== 'edit' ) { + history.push( + { + ...params, + canvas: 'edit', + }, + undefined, + { + transition: 'canvas-mode-edit-transition', + } + ); } openGeneralSidebar( 'edit-site/global-styles' ); setEditorCanvasContainerView( 'global-styles-css' ); @@ -217,9 +229,8 @@ function useGlobalStylesOpenCssCommands() { openGeneralSidebar, setEditorCanvasContainerView, canEditCSS, - getCanvasMode, - setCanvasMode, - params.postId, + canvas, + params, ] ); return { isLoading: false, @@ -228,10 +239,11 @@ function useGlobalStylesOpenCssCommands() { } function useGlobalStylesOpenRevisionsCommands() { - const { openGeneralSidebar, setEditorCanvasContainerView, setCanvasMode } = - unlock( useDispatch( editSiteStore ) ); - const { getCanvasMode } = unlock( useSelect( editSiteStore ) ); + const { openGeneralSidebar, setEditorCanvasContainerView } = unlock( + useDispatch( editSiteStore ) + ); const { params } = useLocation(); + const { canvas = 'view' } = params; const history = useHistory(); const hasRevisions = useSelect( ( select ) => { const { getEntityRecord, __experimentalGetCurrentGlobalStylesId } = @@ -261,8 +273,17 @@ function useGlobalStylesOpenRevisionsCommands() { canvas: 'edit', } ); } - if ( params.postId && getCanvasMode() !== 'edit' ) { - setCanvasMode( 'edit' ); + if ( params.postId && canvas !== 'edit' ) { + history.push( + { + ...params, + canvas: 'edit', + }, + undefined, + { + transition: 'canvas-mode-edit-transition', + } + ); } openGeneralSidebar( 'edit-site/global-styles' ); setEditorCanvasContainerView( 'global-styles-revisions' ); @@ -274,9 +295,8 @@ function useGlobalStylesOpenRevisionsCommands() { history, openGeneralSidebar, setEditorCanvasContainerView, - getCanvasMode, - setCanvasMode, - params.postId, + canvas, + params, ] ); return { diff --git a/packages/edit-site/src/hooks/commands/use-edit-mode-commands.js b/packages/edit-site/src/hooks/commands/use-edit-mode-commands.js index d0064a947001a2..97283044193892 100644 --- a/packages/edit-site/src/hooks/commands/use-edit-mode-commands.js +++ b/packages/edit-site/src/hooks/commands/use-edit-mode-commands.js @@ -20,26 +20,22 @@ import { unlock } from '../../lock-unlock'; import { TEMPLATE_POST_TYPE } from '../../utils/constants'; import { useLink } from '../../components/routes/link'; -const { useHistory } = unlock( routerPrivateApis ); +const { useHistory, useLocation } = unlock( routerPrivateApis ); function usePageContentFocusCommands() { const { record: template } = useEditedEntityRecord(); - const { isPage, canvasMode, templateId, currentPostType } = useSelect( - ( select ) => { - const { isPage: _isPage, getCanvasMode } = unlock( - select( editSiteStore ) - ); - const { getCurrentPostType, getCurrentTemplateId } = - select( editorStore ); - return { - isPage: _isPage(), - canvasMode: getCanvasMode(), - templateId: getCurrentTemplateId(), - currentPostType: getCurrentPostType(), - }; - }, - [] - ); + const { params } = useLocation(); + const { canvas = 'view' } = params; + const { isPage, templateId, currentPostType } = useSelect( ( select ) => { + const { isPage: _isPage } = unlock( select( editSiteStore ) ); + const { getCurrentPostType, getCurrentTemplateId } = + select( editorStore ); + return { + isPage: _isPage(), + templateId: getCurrentTemplateId(), + currentPostType: getCurrentPostType(), + }; + }, [] ); const { onClick: editTemplate } = useLink( { postType: 'wp_template', @@ -48,7 +44,7 @@ function usePageContentFocusCommands() { const { setRenderingMode } = useDispatch( editorStore ); - if ( ! isPage || canvasMode !== 'edit' ) { + if ( ! isPage || canvas !== 'edit' ) { return { isLoading: false, commands: [] }; } diff --git a/packages/edit-site/src/hooks/commands/use-set-command-context.js b/packages/edit-site/src/hooks/commands/use-set-command-context.js index 30f7f7ce258c61..e27c4ca91582fd 100644 --- a/packages/edit-site/src/hooks/commands/use-set-command-context.js +++ b/packages/edit-site/src/hooks/commands/use-set-command-context.js @@ -4,34 +4,32 @@ import { useSelect } from '@wordpress/data'; import { privateApis as commandsPrivateApis } from '@wordpress/commands'; import { store as blockEditorStore } from '@wordpress/block-editor'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; /** * Internal dependencies */ -import { store as editSiteStore } from '../../store'; import { unlock } from '../../lock-unlock'; import { useHasEditorCanvasContainer } from '../../components/editor-canvas-container'; const { useCommandContext } = unlock( commandsPrivateApis ); +const { useLocation } = unlock( routerPrivateApis ); /** * React hook used to set the correct command context based on the current state. */ export default function useSetCommandContext() { - const { hasBlockSelected, canvasMode } = useSelect( ( select ) => { - const { getCanvasMode } = unlock( select( editSiteStore ) ); - const { getBlockSelectionStart } = select( blockEditorStore ); - return { - canvasMode: getCanvasMode(), - hasBlockSelected: getBlockSelectionStart(), - }; + const { params } = useLocation(); + const { canvas = 'view' } = params; + const hasBlockSelected = useSelect( ( select ) => { + return select( blockEditorStore ).getBlockSelectionStart(); }, [] ); const hasEditorCanvasContainer = useHasEditorCanvasContainer(); // Sets the right context for the command palette let commandContext = 'site-editor'; - if ( canvasMode === 'edit' ) { + if ( canvas === 'edit' ) { commandContext = 'entity-edit'; } if ( hasBlockSelected ) { diff --git a/packages/edit-site/src/store/private-actions.js b/packages/edit-site/src/store/private-actions.js index 1c5924a292765b..1db3873acedda2 100644 --- a/packages/edit-site/src/store/private-actions.js +++ b/packages/edit-site/src/store/private-actions.js @@ -1,82 +1,3 @@ -/** - * WordPress dependencies - */ -import { store as blockEditorStore } from '@wordpress/block-editor'; -import { store as preferencesStore } from '@wordpress/preferences'; -import { store as editorStore } from '@wordpress/editor'; - -/** - * Action that switches the canvas mode. - * - * @param {?string} mode Canvas mode. - */ -export const setCanvasMode = - ( mode ) => - ( { registry, dispatch } ) => { - const isMediumOrBigger = - window.matchMedia( '(min-width: 782px)' ).matches; - const switchCanvasMode = () => { - registry.batch( () => { - registry.dispatch( blockEditorStore ).clearSelectedBlock(); - registry.dispatch( editorStore ).setDeviceType( 'Desktop' ); - const isPublishSidebarOpened = registry - .select( editorStore ) - .isPublishSidebarOpened(); - dispatch( { - type: 'SET_CANVAS_MODE', - mode, - } ); - const isEditMode = mode === 'edit'; - if ( isPublishSidebarOpened && ! isEditMode ) { - registry.dispatch( editorStore ).closePublishSidebar(); - } - - // Check if the block list view should be open by default. - // If `distractionFree` mode is enabled, the block list view should not be open. - // This behavior is disabled for small viewports. - if ( - isMediumOrBigger && - isEditMode && - registry - .select( preferencesStore ) - .get( 'core', 'showListViewByDefault' ) && - ! registry - .select( preferencesStore ) - .get( 'core', 'distractionFree' ) - ) { - registry - .dispatch( editorStore ) - .setIsListViewOpened( true ); - } else { - registry - .dispatch( editorStore ) - .setIsListViewOpened( false ); - } - registry.dispatch( editorStore ).setIsInserterOpened( false ); - } ); - }; - - /* - * Skip transition in mobile, otherwise it crashes the browser. - * See: https://github.com/WordPress/gutenberg/pull/63002. - */ - if ( ! isMediumOrBigger || ! document.startViewTransition ) { - switchCanvasMode(); - } else { - document.documentElement.classList.add( - `canvas-mode-${ mode }-transition` - ); - const transition = document.startViewTransition( () => - switchCanvasMode() - ); - transition.finished.finally( () => { - document.documentElement.classList.remove( - `canvas-mode-${ mode }-transition` - ); - } ); - } - }; - /** * Action that switches the editor canvas container view. * diff --git a/packages/edit-site/src/store/private-selectors.js b/packages/edit-site/src/store/private-selectors.js index d0f1d3f4196008..b7c14534419582 100644 --- a/packages/edit-site/src/store/private-selectors.js +++ b/packages/edit-site/src/store/private-selectors.js @@ -1,14 +1,3 @@ -/** - * Returns the current canvas mode. - * - * @param {Object} state Global application state. - * - * @return {string} Canvas mode. - */ -export function getCanvasMode( state ) { - return state.canvasMode; -} - /** * Returns the editor canvas container view. * diff --git a/packages/edit-site/src/store/reducer.js b/packages/edit-site/src/store/reducer.js index 951f004adc9af5..3ce067c25c1954 100644 --- a/packages/edit-site/src/store/reducer.js +++ b/packages/edit-site/src/store/reducer.js @@ -60,27 +60,10 @@ export function saveViewPanel( state = false, action ) { switch ( action.type ) { case 'SET_IS_SAVE_VIEW_OPENED': return action.isOpen; - case 'SET_CANVAS_MODE': - return false; } return state; } -/** - * Reducer used to track the site editor canvas mode (edit or view). - * - * @param {Object} state Current state. - * @param {Object} action Dispatched action. - */ -function canvasMode( state = 'init', action ) { - switch ( action.type ) { - case 'SET_CANVAS_MODE': - return action.mode; - } - - return state; -} - /** * Reducer used to track the site editor canvas container view. * Default is `undefined`, denoting the default, visual block editor. @@ -111,7 +94,6 @@ export default combineReducers( { settings, editedPost, saveViewPanel, - canvasMode, editorCanvasContainerView, routes, } ); diff --git a/packages/router/src/history.ts b/packages/router/src/history.ts index e046522a751894..6cbef108eec206 100644 --- a/packages/router/src/history.ts +++ b/packages/router/src/history.ts @@ -12,6 +12,10 @@ export interface EnhancedHistory extends BrowserHistory { getLocationWithParams: () => Location; } +interface PushOptions { + transition?: string; +} + const history = createBrowserHistory(); const originalHistoryPush = history.push; @@ -32,9 +36,35 @@ function preserveThemePreview( params: Record< string, any > ) { return { ...params, wp_theme_preview: currentThemePreview }; } -function push( params: Record< string, any >, state: Record< string, any > ) { - const search = buildQueryString( preserveThemePreview( params ) ); - return originalHistoryPush.call( history, { search }, state ); +function push( + params: Record< string, any >, + state: Record< string, any >, + options: PushOptions = {} +) { + const performPush = () => { + const search = buildQueryString( preserveThemePreview( params ) ); + return originalHistoryPush.call( history, { search }, state ); + }; + + /* + * Skip transition in mobile, otherwise it crashes the browser. + * See: https://github.com/WordPress/gutenberg/pull/63002. + */ + const isMediumOrBigger = window.matchMedia( '(min-width: 782px)' ).matches; + if ( + ! isMediumOrBigger || + // @ts-expect-error + ! document.startViewTransition || + ! options.transition + ) { + return performPush(); + } + document.documentElement.classList.add( options.transition ); + // @ts-expect-error + const transition = document.startViewTransition( () => performPush() ); + transition.finished.finally( () => { + document.documentElement.classList.remove( options.transition ?? '' ); + } ); } function replace(