diff --git a/packages/edit-site/src/components/app/index.js b/packages/edit-site/src/components/app/index.js
index 7ee4e21e02a3ce..05e6dc8b829785 100644
--- a/packages/edit-site/src/components/app/index.js
+++ b/packages/edit-site/src/components/app/index.js
@@ -1,66 +1,56 @@
/**
* WordPress dependencies
*/
-import { SlotFillProvider } from '@wordpress/components';
-import { UnsavedChangesWarning } from '@wordpress/editor';
-import { store as noticesStore } from '@wordpress/notices';
-import { useDispatch } from '@wordpress/data';
-import { __, sprintf } from '@wordpress/i18n';
-import { PluginArea } from '@wordpress/plugins';
+import { useSelect } from '@wordpress/data';
+import { store as interfaceStore } from '@wordpress/interface';
+import { store as coreStore } from '@wordpress/core-data';
/**
* Internal dependencies
*/
-import { Routes } from '../routes';
+import { store as editSiteStore } from '../../store';
+import { useLocation } from '../routes';
import Editor from '../editor';
import List from '../list';
-import NavigationSidebar from '../navigation-sidebar';
import getIsListPage from '../../utils/get-is-list-page';
export default function EditSiteApp( { reboot } ) {
- const { createErrorNotice } = useDispatch( noticesStore );
+ const { params } = useLocation();
+ const {
+ isInserterOpen,
+ isListViewOpen,
+ sidebarIsOpened,
+ postType,
+ } = useSelect(
+ ( select ) => {
+ const { isInserterOpened, isListViewOpened } = select(
+ editSiteStore
+ );
- function onPluginAreaError( name ) {
- createErrorNotice(
- sprintf(
- /* translators: %s: plugin name */
- __(
- 'The "%s" plugin has encountered an error and cannot be rendered.'
- ),
- name
- )
- );
- }
-
- return (
-
-
+ // The currently selected entity to display. Typically template or template part.
+ return {
+ isInserterOpen: isInserterOpened(),
+ isListViewOpen: isListViewOpened(),
+ sidebarIsOpened: !! select(
+ interfaceStore
+ ).getActiveComplementaryArea( editSiteStore.name ),
+ postType: select( coreStore ).getPostType( params.postType ),
+ };
+ },
+ [ params.postType ]
+ );
-
- { ( { params } ) => {
- const isListPage = getIsListPage( params );
+ const isListPage = getIsListPage( params );
- return (
- <>
- { isListPage ? (
-
- ) : (
-
- ) }
-
- { /* Keep the instance of the sidebar to ensure focus will not be lost
- * when navigating to other pages. */ }
-
- >
- );
- } }
-
-
- );
+ return isListPage
+ ? List.renderLayout( {
+ postType,
+ activeTemplateType: params.postType,
+ } )
+ : Editor.renderLayout( {
+ isInserterOpen,
+ isListViewOpen,
+ sidebarIsOpened,
+ reboot,
+ } );
}
diff --git a/packages/edit-site/src/components/editor/actions.js b/packages/edit-site/src/components/editor/actions.js
new file mode 100644
index 00000000000000..ad845986be61c4
--- /dev/null
+++ b/packages/edit-site/src/components/editor/actions.js
@@ -0,0 +1,44 @@
+/**
+ * WordPress dependencies
+ */
+import { useCallback } from '@wordpress/element';
+import { useSelect, useDispatch } from '@wordpress/data';
+import { Button } from '@wordpress/components';
+import { EntitiesSavedStates } from '@wordpress/editor';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import { store as editSiteStore } from '../../store';
+
+export default function EditorActions() {
+ const isEntitiesSavedStatesOpen = useSelect(
+ ( select ) => select( editSiteStore ).getIsEntitiesSavedStatesOpen(),
+ []
+ );
+ const { setIsEntitiesSavedStatesOpen } = useDispatch( editSiteStore );
+ const openEntitiesSavedStates = useCallback(
+ () => setIsEntitiesSavedStatesOpen( true ),
+ [ setIsEntitiesSavedStatesOpen ]
+ );
+ const closeEntitiesSavedStates = useCallback(
+ () => setIsEntitiesSavedStatesOpen( false ),
+ [ setIsEntitiesSavedStatesOpen ]
+ );
+
+ return isEntitiesSavedStatesOpen ? (
+
+ ) : (
+
+
+ { __( 'Open save panel' ) }
+
+
+ );
+}
diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js
index a092754465fbd7..53ad9fde4535ed 100644
--- a/packages/edit-site/src/components/editor/index.js
+++ b/packages/edit-site/src/components/editor/index.js
@@ -1,75 +1,56 @@
/**
* WordPress dependencies
*/
-import { useEffect, useState, useMemo, useCallback } from '@wordpress/element';
+import { useMemo, useEffect } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
-import { Popover, Button, Notice } from '@wordpress/components';
+import { Notice } from '@wordpress/components';
import { EntityProvider, store as coreStore } from '@wordpress/core-data';
import { BlockContextProvider, BlockBreadcrumb } from '@wordpress/block-editor';
import {
- InterfaceSkeleton,
ComplementaryArea,
store as interfaceStore,
} from '@wordpress/interface';
-import {
- EditorNotices,
- EditorSnackbars,
- EntitiesSavedStates,
-} from '@wordpress/editor';
+import { EditorNotices } from '@wordpress/editor';
import { __ } from '@wordpress/i18n';
-import {
- ShortcutProvider,
- store as keyboardShortcutsStore,
-} from '@wordpress/keyboard-shortcuts';
/**
* Internal dependencies
*/
import Header from '../header';
import { SidebarComplementaryAreaFills } from '../sidebar';
-import NavigationSidebar from '../navigation-sidebar';
import BlockEditor from '../block-editor';
import CodeEditor from '../code-editor';
import KeyboardShortcuts from '../keyboard-shortcuts';
-import URLQueryController from '../url-query-controller';
+import useURLQueryController from './use-url-query-controller';
import InserterSidebar from '../secondary-sidebar/inserter-sidebar';
import ListViewSidebar from '../secondary-sidebar/list-view-sidebar';
import ErrorBoundary from '../error-boundary';
import WelcomeGuide from '../welcome-guide';
import { store as editSiteStore } from '../../store';
import { GlobalStylesRenderer } from './global-styles-renderer';
-import { GlobalStylesProvider } from '../global-styles/global-styles-provider';
import useTitle from '../routes/use-title';
+import Layout from '../layout';
+import EditorActions from './actions';
const interfaceLabels = {
secondarySidebar: __( 'Block Library' ),
drawer: __( 'Navigation Sidebar' ),
};
-
function Editor( { onError } ) {
const {
- isInserterOpen,
- isListViewOpen,
- sidebarIsOpened,
settings,
entityId,
templateType,
page,
template,
templateResolved,
- isNavigationOpen,
- previousShortcut,
- nextShortcut,
editorMode,
} = useSelect( ( select ) => {
const {
- isInserterOpened,
- isListViewOpened,
getSettings,
getEditedPostType,
getEditedPostId,
getPage,
- isNavigationOpened,
getEditorMode,
} = select( editSiteStore );
const { hasFinishedResolution, getEntityRecord } = select( coreStore );
@@ -78,11 +59,6 @@ function Editor( { onError } ) {
// The currently selected entity to display. Typically template or template part.
return {
- isInserterOpen: isInserterOpened(),
- isListViewOpen: isListViewOpened(),
- sidebarIsOpened: !! select(
- interfaceStore
- ).getActiveComplementaryArea( editSiteStore.name ),
settings: getSettings(),
templateType: postType,
page: getPage(),
@@ -97,31 +73,12 @@ function Editor( { onError } ) {
] )
: false,
entityId: postId,
- isNavigationOpen: isNavigationOpened(),
- previousShortcut: select(
- keyboardShortcutsStore
- ).getAllShortcutKeyCombinations( 'core/edit-site/previous-region' ),
- nextShortcut: select(
- keyboardShortcutsStore
- ).getAllShortcutKeyCombinations( 'core/edit-site/next-region' ),
editorMode: getEditorMode(),
};
}, [] );
const { setPage, setIsInserterOpened } = useDispatch( editSiteStore );
const { enableComplementaryArea } = useDispatch( interfaceStore );
- const [
- isEntitiesSavedStatesOpen,
- setIsEntitiesSavedStatesOpen,
- ] = useState( false );
- const openEntitiesSavedStates = useCallback(
- () => setIsEntitiesSavedStatesOpen( true ),
- []
- );
- const closeEntitiesSavedStates = useCallback( () => {
- setIsEntitiesSavedStatesOpen( false );
- }, [] );
-
const blockContext = useMemo(
() => ( {
...page?.context,
@@ -143,14 +100,6 @@ function Editor( { onError } ) {
[ page?.context ]
);
- useEffect( () => {
- if ( isNavigationOpen ) {
- document.body.classList.add( 'is-navigation-sidebar-open' );
- } else {
- document.body.classList.remove( 'is-navigation-sidebar-open' );
- }
- }, [ isNavigationOpen ] );
-
useEffect(
function openGlobalStylesOnLoad() {
const searchParams = new URLSearchParams( window.location.search );
@@ -170,143 +119,86 @@ function Editor( { onError } ) {
templateType !== undefined &&
entityId !== undefined;
- const secondarySidebar = () => {
- if ( isInserterOpen ) {
- return ;
- }
- if ( isListViewOpen ) {
- return ;
- }
- return null;
- };
-
// Only announce the title once the editor is ready to prevent "Replace"
- // action in from double-announcing.
+ // action in useURlQueryController from double-announcing.
useTitle( isReady && __( 'Editor (beta)' ) );
+ useURLQueryController();
+
+ if ( ! isReady ) {
+ return null;
+ }
+
return (
- <>
-
- { isReady && (
-
-
-
-
-
-
-
-
-
-
- )
- }
- drawer={
-
- }
- header={
-
- }
- notices={ }
- content={
- <>
-
- { editorMode === 'visual' &&
- template && (
-
- ) }
- { editorMode === 'text' &&
- template && (
-
- ) }
- { templateResolved &&
- ! template &&
- settings?.siteUrl &&
- entityId && (
-
- { __(
- "You attempted to edit an item that doesn't exist. Perhaps it was deleted?"
- ) }
-
- ) }
-
- >
- }
- actions={
- <>
- { isEntitiesSavedStatesOpen ? (
-
- ) : (
-
-
- { __(
- 'Open save panel'
- ) }
-
-
- ) }
- >
- }
- footer={
-
- }
- shortcuts={ {
- previous: previousShortcut,
- next: nextShortcut,
- } }
- />
-
-
-
-
-
-
-
-
- ) }
- >
+
+
+
+
+
+
+
+
+ { editorMode === 'visual' && template && (
+
+ ) }
+ { editorMode === 'text' && template && }
+ { templateResolved &&
+ ! template &&
+ settings?.siteUrl &&
+ entityId && (
+
+ { __(
+ "You attempted to edit an item that doesn't exist. Perhaps it was deleted?"
+ ) }
+
+ ) }
+
+
+
+
+
);
}
+
+Editor.renderLayout = function renderEditorLayout( {
+ sidebarIsOpened,
+ isInserterOpen,
+ isListViewOpen,
+ reboot,
+} ) {
+ let secondarySidebar = null;
+ if ( isInserterOpen ) {
+ secondarySidebar = ;
+ } else if ( isListViewOpen ) {
+ secondarySidebar = ;
+ }
+
+ return (
+
+ )
+ }
+ secondarySidebar={ secondarySidebar }
+ header={ }
+ content={ }
+ actions={ }
+ footer={ }
+ >
+
+
+ );
+};
+
export default Editor;
diff --git a/packages/edit-site/src/components/url-query-controller/index.js b/packages/edit-site/src/components/editor/use-url-query-controller.js
similarity index 94%
rename from packages/edit-site/src/components/url-query-controller/index.js
rename to packages/edit-site/src/components/editor/use-url-query-controller.js
index 8e4f8b17aef6f1..c513331d2ae9ba 100644
--- a/packages/edit-site/src/components/url-query-controller/index.js
+++ b/packages/edit-site/src/components/editor/use-url-query-controller.js
@@ -10,7 +10,7 @@ import { useDispatch } from '@wordpress/data';
import { useLocation } from '../routes';
import { store as editSiteStore } from '../../store';
-export default function URLQueryController() {
+export default function useURLQueryController() {
const { setTemplate, setTemplatePart, setPage } = useDispatch(
editSiteStore
);
diff --git a/packages/edit-site/src/components/header/index.js b/packages/edit-site/src/components/header/index.js
index 0247f13c11fbca..44cc2eae864c68 100644
--- a/packages/edit-site/src/components/header/index.js
+++ b/packages/edit-site/src/components/header/index.js
@@ -31,10 +31,7 @@ const preventDefault = ( event ) => {
event.preventDefault();
};
-export default function Header( {
- openEntitiesSavedStates,
- isEntitiesSavedStatesOpen,
-} ) {
+export default function Header() {
const inserterButton = useRef();
const {
deviceType,
@@ -173,10 +170,7 @@ export default function Header( {
setDeviceType={ setPreviewDeviceType }
/>
) }
-
+
diff --git a/packages/edit-site/src/components/keyboard-shortcuts/index.js b/packages/edit-site/src/components/keyboard-shortcuts/index.js
index 9b6cb72906e641..4288f2255e2198 100644
--- a/packages/edit-site/src/components/keyboard-shortcuts/index.js
+++ b/packages/edit-site/src/components/keyboard-shortcuts/index.js
@@ -18,7 +18,7 @@ import { store as editSiteStore } from '../../store';
import { SIDEBAR_BLOCK } from '../sidebar/constants';
import { STORE_NAME } from '../../store/constants';
-function KeyboardShortcuts( { openEntitiesSavedStates } ) {
+function KeyboardShortcuts() {
const {
__experimentalGetDirtyEntityRecords,
isSavingEntityRecord,
@@ -36,9 +36,11 @@ function KeyboardShortcuts( { openEntitiesSavedStates } ) {
[]
);
const { redo, undo } = useDispatch( coreStore );
- const { setIsListViewOpened, switchEditorMode } = useDispatch(
- editSiteStore
- );
+ const {
+ setIsListViewOpened,
+ switchEditorMode,
+ setIsEntitiesSavesStateOpen,
+ } = useDispatch( editSiteStore );
const { enableComplementaryArea, disableComplementaryArea } = useDispatch(
interfaceStore
);
@@ -53,7 +55,7 @@ function KeyboardShortcuts( { openEntitiesSavedStates } ) {
);
if ( ! isSaving && isDirty ) {
- openEntitiesSavedStates();
+ setIsEntitiesSavesStateOpen( true );
}
} );
diff --git a/packages/edit-site/src/components/layout/index.js b/packages/edit-site/src/components/layout/index.js
new file mode 100644
index 00000000000000..ccaedce296fc3e
--- /dev/null
+++ b/packages/edit-site/src/components/layout/index.js
@@ -0,0 +1,103 @@
+/**
+ * WordPress dependencies
+ */
+import { useEffect } from '@wordpress/element';
+import { useSelect, useDispatch } from '@wordpress/data';
+import { SlotFillProvider, Popover } from '@wordpress/components';
+import { EntityProvider } from '@wordpress/core-data';
+import { InterfaceSkeleton } from '@wordpress/interface';
+import { EditorSnackbars, UnsavedChangesWarning } from '@wordpress/editor';
+import {
+ ShortcutProvider,
+ store as keyboardShortcutsStore,
+} from '@wordpress/keyboard-shortcuts';
+import { __, sprintf } from '@wordpress/i18n';
+import { store as noticesStore } from '@wordpress/notices';
+import { PluginArea } from '@wordpress/plugins';
+
+/**
+ * Internal dependencies
+ */
+import NavigationSidebar from '../navigation-sidebar';
+import { GlobalStylesProvider } from '../global-styles/global-styles-provider';
+import { store as editSiteStore } from '../../store';
+
+function Layout( {
+ children,
+ isNavigationDefaultOpen,
+ activeTemplateType,
+ ...props
+} ) {
+ const { isNavigationOpen, previousShortcut, nextShortcut } = useSelect(
+ ( select ) => {
+ const { isNavigationOpened } = select( editSiteStore );
+ const { getAllShortcutKeyCombinations } = select(
+ keyboardShortcutsStore
+ );
+
+ // The currently selected entity to display. Typically template or template part.
+ return {
+ isNavigationOpen: isNavigationOpened(),
+ previousShortcut: getAllShortcutKeyCombinations(
+ 'core/edit-site/previous-region'
+ ),
+ nextShortcut: getAllShortcutKeyCombinations(
+ 'core/edit-site/next-region'
+ ),
+ };
+ },
+ []
+ );
+ const { createErrorNotice } = useDispatch( noticesStore );
+
+ useEffect( () => {
+ if ( isNavigationOpen ) {
+ document.body.classList.add( 'is-navigation-sidebar-open' );
+ } else {
+ document.body.classList.remove( 'is-navigation-sidebar-open' );
+ }
+ }, [ isNavigationOpen ] );
+
+ function onPluginAreaError( name ) {
+ createErrorNotice(
+ sprintf(
+ /* translators: %s: plugin name */
+ __(
+ 'The "%s" plugin has encountered an error and cannot be rendered.'
+ ),
+ name
+ )
+ );
+ }
+
+ return (
+
+
+
+
+
+
+ }
+ notices={ }
+ shortcuts={ {
+ previous: previousShortcut,
+ next: nextShortcut,
+ } }
+ { ...props }
+ />
+
+
+ { children }
+
+
+
+
+ );
+}
+
+export default Layout;
diff --git a/packages/edit-site/src/components/list/header.js b/packages/edit-site/src/components/list/header.js
index 4f98ecf7843d5b..bdbde06689c28f 100644
--- a/packages/edit-site/src/components/list/header.js
+++ b/packages/edit-site/src/components/list/header.js
@@ -9,8 +9,12 @@ import { __experimentalHeading as Heading } from '@wordpress/components';
* Internal dependencies
*/
import AddNewTemplate from '../add-new-template';
+import { useLocation } from '../routes';
-export default function Header( { templateType } ) {
+export default function Header() {
+ const {
+ params: { postType: templateType },
+ } = useLocation();
const postType = useSelect(
( select ) => select( coreStore ).getPostType( templateType ),
[ templateType ]
diff --git a/packages/edit-site/src/components/list/index.js b/packages/edit-site/src/components/list/index.js
index 2b56930142ad4a..c758dc40b41c7f 100644
--- a/packages/edit-site/src/components/list/index.js
+++ b/packages/edit-site/src/components/list/index.js
@@ -1,60 +1,26 @@
-/**
- * External dependencies
- */
-import classnames from 'classnames';
-
/**
* WordPress dependencies
*/
-import { store as coreStore } from '@wordpress/core-data';
-import { useSelect } from '@wordpress/data';
-import { InterfaceSkeleton } from '@wordpress/interface';
import { __, sprintf } from '@wordpress/i18n';
-import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts';
-import { EditorSnackbars } from '@wordpress/editor';
/**
* Internal dependencies
*/
-import useRegisterShortcuts from './use-register-shortcuts';
import Header from './header';
-import NavigationSidebar from '../navigation-sidebar';
import Table from './table';
-import { store as editSiteStore } from '../../store';
-import { useLocation } from '../routes';
-import useTitle from '../routes/use-title';
-
-export default function List() {
- const {
- params: { postType: templateType },
- } = useLocation();
+import Layout from '../layout';
+import useRegisterShortcuts from './use-register-shortcuts';
+function List() {
useRegisterShortcuts();
- const { previousShortcut, nextShortcut, isNavigationOpen } = useSelect(
- ( select ) => {
- return {
- previousShortcut: select(
- keyboardShortcutsStore
- ).getAllShortcutKeyCombinations(
- 'core/edit-site/previous-region'
- ),
- nextShortcut: select(
- keyboardShortcutsStore
- ).getAllShortcutKeyCombinations( 'core/edit-site/next-region' ),
- isNavigationOpen: select( editSiteStore ).isNavigationOpened(),
- };
- },
- []
- );
-
- const postType = useSelect(
- ( select ) => select( coreStore ).getPostType( templateType ),
- [ templateType ]
- );
-
- useTitle( postType?.labels?.name );
+ return ;
+}
+List.renderLayout = function renderListLayout( {
+ postType,
+ activeTemplateType,
+} ) {
// `postType` could load in asynchronously. Only provide the detailed region labels if
// the postType has loaded, otherwise `InterfaceSkeleton` will fallback to the defaults.
const itemsListLabel = postType?.labels?.items_list;
@@ -74,22 +40,18 @@ export default function List() {
: undefined;
return (
- }
- drawer={ }
- notices={ }
- content={ }
- shortcuts={ {
- previous: previousShortcut,
- next: nextShortcut,
- } }
+ header={ }
+ content={
}
/>
);
-}
+};
+
+export default List;
diff --git a/packages/edit-site/src/components/list/style.scss b/packages/edit-site/src/components/list/style.scss
index 0ad240e19f768a..c575322fc0c6a2 100644
--- a/packages/edit-site/src/components/list/style.scss
+++ b/packages/edit-site/src/components/list/style.scss
@@ -118,7 +118,7 @@
}
}
-.edit-site-list.is-navigation-open .components-snackbar-list {
+body.is-navigation-sidebar-open .edit-site-list .components-snackbar-list {
@include break-medium() {
margin-left: $nav-sidebar-width;
}
diff --git a/packages/edit-site/src/components/list/table.js b/packages/edit-site/src/components/list/table.js
index 47e7ca49d4aeba..f3ad18c29b71f6 100644
--- a/packages/edit-site/src/components/list/table.js
+++ b/packages/edit-site/src/components/list/table.js
@@ -13,11 +13,15 @@ import { decodeEntities } from '@wordpress/html-entities';
/**
* Internal dependencies
*/
+import { useLocation } from '../routes';
import Link from '../routes/link';
import Actions from './actions';
import AddedBy from './added-by';
-export default function Table( { templateType } ) {
+export default function Table() {
+ const {
+ params: { postType: templateType },
+ } = useLocation();
const { templates, isLoading, postType } = useSelect(
( select ) => {
const {
diff --git a/packages/edit-site/src/components/navigation-sidebar/index.js b/packages/edit-site/src/components/navigation-sidebar/index.js
index 9d03ec1ca7662a..aa91b5b609be88 100644
--- a/packages/edit-site/src/components/navigation-sidebar/index.js
+++ b/packages/edit-site/src/components/navigation-sidebar/index.js
@@ -18,11 +18,6 @@ export const {
Slot: NavigationPanelPreviewSlot,
} = createSlotFill( 'EditSiteNavigationPanelPreview' );
-const {
- Fill: NavigationSidebarFill,
- Slot: NavigationSidebarSlot,
-} = createSlotFill( 'EditSiteNavigationSidebar' );
-
function NavigationSidebar( { isDefaultOpen = false, activeTemplateType } ) {
const isDesktopViewport = useViewportMatch( 'medium' );
const { setIsNavigationPanelOpened } = useDispatch( editSiteStore );
@@ -35,14 +30,12 @@ function NavigationSidebar( { isDefaultOpen = false, activeTemplateType } ) {
);
return (
-
+ <>
-
+ >
);
}
-NavigationSidebar.Slot = NavigationSidebarSlot;
-
export default NavigationSidebar;
diff --git a/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/index.js b/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/index.js
index 2cdc68858e480c..df311c25bb25cb 100644
--- a/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/index.js
+++ b/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/index.js
@@ -6,8 +6,8 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
+import { useRef } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
-import { useEffect, useRef } from '@wordpress/element';
import {
Button,
Icon,
@@ -22,6 +22,7 @@ import { useReducedMotion } from '@wordpress/compose';
* Internal dependencies
*/
import { store as editSiteStore } from '../../../store';
+import useResetFocusOnRouteChange from '../../routes/use-reset-focus-on-route-change';
function NavigationToggle( { icon } ) {
const { isNavigationOpen, isRequestingSiteIcon, siteIconUrl } = useSelect(
@@ -46,16 +47,6 @@ function NavigationToggle( { icon } ) {
const disableMotion = useReducedMotion();
- const navigationToggleRef = useRef();
-
- useEffect( () => {
- // TODO: Remove this effect when alternative solution is merged.
- // See: https://github.com/WordPress/gutenberg/pull/37314
- if ( ! isNavigationOpen ) {
- navigationToggleRef.current.focus();
- }
- }, [ isNavigationOpen ] );
-
const toggleNavigationPanel = () =>
setIsNavigationPanelOpened( ! isNavigationOpen );
@@ -88,6 +79,9 @@ function NavigationToggle( { icon } ) {
'has-icon': siteIconUrl,
} );
+ const buttonRef = useRef();
+ useResetFocusOnRouteChange( buttonRef );
+
return (
{ buttonIcon }
diff --git a/packages/edit-site/src/components/routes/index.js b/packages/edit-site/src/components/routes/index.js
index b24fa069f1efd2..7ef19280d44433 100644
--- a/packages/edit-site/src/components/routes/index.js
+++ b/packages/edit-site/src/components/routes/index.js
@@ -46,7 +46,7 @@ export function Routes( { children } ) {
return (
- { children( location ) }
+ { children }
);
diff --git a/packages/edit-site/src/components/routes/use-reset-focus-on-route-change.js b/packages/edit-site/src/components/routes/use-reset-focus-on-route-change.js
new file mode 100644
index 00000000000000..15a134bd4ba8d6
--- /dev/null
+++ b/packages/edit-site/src/components/routes/use-reset-focus-on-route-change.js
@@ -0,0 +1,45 @@
+/**
+ * External dependencies
+ */
+import { Action } from 'history';
+
+/**
+ * WordPress dependencies
+ */
+import { useRef, useEffect } from '@wordpress/element';
+
+/**
+ * Internal dependencies
+ */
+import { useLocation, useHistory } from './index';
+
+export default function useResetFocusOnRouteChange( targetRef ) {
+ const history = useHistory();
+ const location = useLocation();
+ const isInitialPageLoadRef = useRef( true );
+ const expectRedirectionRef = useRef( false );
+
+ useEffect( () => {
+ // Don't focus for initial page load.
+ if ( isInitialPageLoadRef.current ) {
+ isInitialPageLoadRef.current = false;
+ expectRedirectionRef.current = true;
+ return;
+ }
+ // Don't focus for the initial page redirection.
+ // TODO: This can be removed once #36873 is resolved.
+ if ( expectRedirectionRef.current ) {
+ expectRedirectionRef.current = false;
+ if ( history.action === Action.Replace ) {
+ return;
+ }
+ }
+
+ const activeElement = targetRef.current?.ownerDocument.activeElement;
+
+ // Don't refocus if the activeElement is still on the page (like NavLink).
+ if ( ! activeElement || activeElement === document.body ) {
+ targetRef.current?.focus();
+ }
+ }, [ location, targetRef, history ] );
+}
diff --git a/packages/edit-site/src/components/save-button/index.js b/packages/edit-site/src/components/save-button/index.js
index bd6743ee2dd14f..ac12ae13be3f56 100644
--- a/packages/edit-site/src/components/save-button/index.js
+++ b/packages/edit-site/src/components/save-button/index.js
@@ -6,28 +6,37 @@ import { some } from 'lodash';
/**
* WordPress dependencies
*/
-import { useSelect } from '@wordpress/data';
+import { useSelect, useDispatch } from '@wordpress/data';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { store as coreStore } from '@wordpress/core-data';
-export default function SaveButton( {
- openEntitiesSavedStates,
- isEntitiesSavedStatesOpen,
-} ) {
- const { isDirty, isSaving } = useSelect( ( select ) => {
- const {
- __experimentalGetDirtyEntityRecords,
- isSavingEntityRecord,
- } = select( coreStore );
- const dirtyEntityRecords = __experimentalGetDirtyEntityRecords();
- return {
- isDirty: dirtyEntityRecords.length > 0,
- isSaving: some( dirtyEntityRecords, ( record ) =>
- isSavingEntityRecord( record.kind, record.name, record.key )
- ),
- };
- }, [] );
+/**
+ * Internal dependencies
+ */
+import { store as editSiteStore } from '../../store';
+
+export default function SaveButton() {
+ const { isDirty, isSaving, isEntitiesSavedStatesOpen } = useSelect(
+ ( select ) => {
+ const {
+ __experimentalGetDirtyEntityRecords,
+ isSavingEntityRecord,
+ } = select( coreStore );
+ const dirtyEntityRecords = __experimentalGetDirtyEntityRecords();
+ return {
+ isDirty: dirtyEntityRecords.length > 0,
+ isSaving: some( dirtyEntityRecords, ( record ) =>
+ isSavingEntityRecord( record.kind, record.name, record.key )
+ ),
+ isEntitiesSavedStatesOpen: select(
+ editSiteStore
+ ).getIsEntitiesSavedStatesOpen(),
+ };
+ },
+ []
+ );
+ const { setIsEntitiesSavedStatesOpen } = useDispatch( editSiteStore );
const disabled = ! isDirty || isSaving;
@@ -40,7 +49,11 @@ export default function SaveButton( {
aria-expanded={ isEntitiesSavedStatesOpen }
disabled={ disabled }
isBusy={ isSaving }
- onClick={ disabled ? undefined : openEntitiesSavedStates }
+ onClick={
+ disabled
+ ? undefined
+ : () => setIsEntitiesSavedStatesOpen( true )
+ }
>
{ __( 'Save' ) }
diff --git a/packages/edit-site/src/index.js b/packages/edit-site/src/index.js
index 7e51c857433d53..97046e1b8c06e2 100644
--- a/packages/edit-site/src/index.js
+++ b/packages/edit-site/src/index.js
@@ -22,6 +22,7 @@ import { getQueryArgs } from '@wordpress/url';
*/
import './hooks';
import { store as editSiteStore } from './store';
+import { Routes } from './components/routes';
import EditSiteApp from './components/app';
import getIsListPage from './utils/get-is-list-page';
import redirectToHomepage from './components/routes/redirect-to-homepage';
@@ -87,7 +88,12 @@ export async function reinitializeEditor( target, settings ) {
}
}
- render( , target );
+ render(
+
+
+ ,
+ target
+ );
}
/**
diff --git a/packages/edit-site/src/store/actions.js b/packages/edit-site/src/store/actions.js
index 92eee1dd6778bc..17e42537445abf 100644
--- a/packages/edit-site/src/store/actions.js
+++ b/packages/edit-site/src/store/actions.js
@@ -463,3 +463,10 @@ export const switchEditorMode = ( mode ) => ( { dispatch, registry } ) => {
speak( __( 'Mosaic view selected' ), 'assertive' );
}
};
+
+export function setIsEntitiesSavedStatesOpen( isOpen ) {
+ return {
+ type: 'SET_IS_ENTITIES_SAVED_STATES_OPEN',
+ isOpen,
+ };
+}
diff --git a/packages/edit-site/src/store/reducer.js b/packages/edit-site/src/store/reducer.js
index fa5ca383a4a5af..6d2ede65df925d 100644
--- a/packages/edit-site/src/store/reducer.js
+++ b/packages/edit-site/src/store/reducer.js
@@ -212,6 +212,15 @@ export function listViewPanel( state = false, action ) {
return state;
}
+export function isEntitiesSavedStatesOpen( state = false, action ) {
+ switch ( action.type ) {
+ case 'SET_IS_ENTITIES_SAVED_STATES_OPEN':
+ return action.isOpen;
+ default:
+ return state;
+ }
+}
+
export default combineReducers( {
preferences,
deviceType,
@@ -221,4 +230,5 @@ export default combineReducers( {
navigationPanel,
blockInserterPanel,
listViewPanel,
+ isEntitiesSavedStatesOpen,
} );
diff --git a/packages/edit-site/src/store/selectors.js b/packages/edit-site/src/store/selectors.js
index fc07bb7b77cd1d..c570d4c4886b41 100644
--- a/packages/edit-site/src/store/selectors.js
+++ b/packages/edit-site/src/store/selectors.js
@@ -341,3 +341,12 @@ export const getCurrentTemplateTemplateParts = createRegistrySelector(
export function getEditorMode( state ) {
return state.preferences.editorMode || 'visual';
}
+
+/**
+ * Returns if the entities saves states is open.
+ *
+ * @param {Object} state Global application state.
+ * @return {boolean} Is entities saved states open.
+ */
+export const getIsEntitiesSavedStatesOpen = ( state ) =>
+ state.isEntitiesSavedStatesOpen;