diff --git a/package-lock.json b/package-lock.json
index c01f19ad33228..7425d75403ad1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -55359,7 +55359,8 @@
"@wordpress/reusable-blocks": "file:../reusable-blocks",
"@wordpress/url": "file:../url",
"@wordpress/widgets": "file:../widgets",
- "classnames": "^2.3.1"
+ "classnames": "^2.3.1",
+ "rememo": "^4.0.2"
},
"engines": {
"node": ">=12"
@@ -70610,7 +70611,8 @@
"@wordpress/reusable-blocks": "file:../reusable-blocks",
"@wordpress/url": "file:../url",
"@wordpress/widgets": "file:../widgets",
- "classnames": "^2.3.1"
+ "classnames": "^2.3.1",
+ "rememo": "^4.0.2"
}
},
"@wordpress/editor": {
diff --git a/packages/edit-post/src/components/header/header-toolbar/index.js b/packages/edit-post/src/components/header/header-toolbar/index.js
index d585102c06db9..c524a8842ad4c 100644
--- a/packages/edit-post/src/components/header/header-toolbar/index.js
+++ b/packages/edit-post/src/components/header/header-toolbar/index.js
@@ -32,7 +32,7 @@ const preventDefault = ( event ) => {
event.preventDefault();
};
-function HeaderToolbar( { hasFixedToolbar, setListViewToggleElement } ) {
+function HeaderToolbar( { hasFixedToolbar } ) {
const inserterButton = useRef();
const { setIsInserterOpened, setIsListViewOpened } =
useDispatch( editorStore );
@@ -43,10 +43,12 @@ function HeaderToolbar( { hasFixedToolbar, setListViewToggleElement } ) {
showIconLabels,
isListViewOpen,
listViewShortcut,
+ listViewToggleRef,
} = useSelect( ( select ) => {
const { hasInserterItems, getBlockRootClientId, getBlockSelectionEnd } =
select( blockEditorStore );
- const { getEditorSettings, isListViewOpened } = select( editorStore );
+ const { getEditorSettings, isListViewOpened, getListViewToggleRef } =
+ unlock( select( editorStore ) );
const { getEditorMode, isFeatureActive } = select( editPostStore );
const { getShortcutRepresentation } = select( keyboardShortcutsStore );
@@ -65,6 +67,7 @@ function HeaderToolbar( { hasFixedToolbar, setListViewToggleElement } ) {
listViewShortcut: getShortcutRepresentation(
'core/edit-post/toggle-list-view'
),
+ listViewToggleRef: getListViewToggleRef(),
};
}, [] );
@@ -103,7 +106,7 @@ function HeaderToolbar( { hasFixedToolbar, setListViewToggleElement } ) {
showTooltip={ ! showIconLabels }
variant={ showIconLabels ? 'tertiary' : undefined }
aria-expanded={ isListViewOpen }
- ref={ setListViewToggleElement }
+ ref={ listViewToggleRef }
size="compact"
/>
>
diff --git a/packages/edit-post/src/components/header/index.js b/packages/edit-post/src/components/header/index.js
index 67349bd640403..1e0a1f3195613 100644
--- a/packages/edit-post/src/components/header/index.js
+++ b/packages/edit-post/src/components/header/index.js
@@ -55,10 +55,7 @@ const slideX = {
hover: { x: 0, transition: { type: 'tween', delay: 0.2 } },
};
-function Header( {
- setEntitiesSavedStatesCallback,
- setListViewToggleElement,
-} ) {
+function Header( { setEntitiesSavedStatesCallback } ) {
const isWideViewport = useViewportMatch( 'large' );
const isLargeViewport = useViewportMatch( 'medium' );
const blockToolbarRef = useRef();
@@ -111,10 +108,7 @@ function Header( {
transition={ { type: 'tween', delay: 0.8 } }
className="edit-post-header__toolbar"
>
-
+
{ hasFixedToolbar && isLargeViewport && (
<>
{
if ( typeof entitiesSavedStatesCallback === 'function' ) {
@@ -268,11 +265,7 @@ function Layout() {
return
;
}
if ( mode === 'visual' && isListViewOpened ) {
- return (
-
- );
+ return
;
}
return null;
@@ -313,7 +306,6 @@ function Layout() {
setEntitiesSavedStatesCallback={
setEntitiesSavedStatesCallback
}
- setListViewToggleElement={ setListViewToggleElement }
/>
}
editorNotices={
}
diff --git a/packages/edit-post/src/components/secondary-sidebar/list-view-sidebar.js b/packages/edit-post/src/components/secondary-sidebar/list-view-sidebar.js
index fa692d4869004..02690d9115d7a 100644
--- a/packages/edit-post/src/components/secondary-sidebar/list-view-sidebar.js
+++ b/packages/edit-post/src/components/secondary-sidebar/list-view-sidebar.js
@@ -4,7 +4,7 @@
import { __experimentalListView as ListView } from '@wordpress/block-editor';
import { Button, TabPanel } from '@wordpress/components';
import { useFocusOnMount, useMergeRefs } from '@wordpress/compose';
-import { useDispatch } from '@wordpress/data';
+import { useDispatch, useSelect } from '@wordpress/data';
import { focus } from '@wordpress/dom';
import { useCallback, useRef, useState } from '@wordpress/element';
import { __, _x } from '@wordpress/i18n';
@@ -17,9 +17,11 @@ import { store as editorStore } from '@wordpress/editor';
* Internal dependencies
*/
import ListViewOutline from './list-view-outline';
+import { unlock } from '../../lock-unlock';
-export default function ListViewSidebar( { listViewToggleElement } ) {
+export default function ListViewSidebar() {
const { setIsListViewOpened } = useDispatch( editorStore );
+ const { getListViewToggleRef } = unlock( useSelect( editorStore ) );
// This hook handles focus when the sidebar first renders.
const focusOnMountRef = useFocusOnMount( 'firstElement' );
@@ -27,8 +29,8 @@ export default function ListViewSidebar( { listViewToggleElement } ) {
// When closing the list view, focus should return to the toggle button.
const closeListView = useCallback( () => {
setIsListViewOpened( false );
- listViewToggleElement?.focus();
- }, [ listViewToggleElement, setIsListViewOpened ] );
+ getListViewToggleRef().current?.focus();
+ }, [ getListViewToggleRef, setIsListViewOpened ] );
const closeOnEscape = useCallback(
( event ) => {
diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js
index db92c36d75af7..9a1931b2ede39 100644
--- a/packages/edit-site/src/components/editor/index.js
+++ b/packages/edit-site/src/components/editor/index.js
@@ -84,7 +84,7 @@ const blockRemovalRules = {
),
};
-export default function Editor( { listViewToggleElement, isLoading } ) {
+export default function Editor( { isLoading } ) {
const {
record: editedPost,
getTitle,
@@ -251,13 +251,7 @@ export default function Editor( { listViewToggleElement, isLoading } ) {
secondarySidebar={
isEditMode &&
( ( shouldShowInserter &&
) ||
- ( shouldShowListView && (
-
- ) ) )
+ ( shouldShowListView &&
) )
}
sidebar={
isEditMode &&
diff --git a/packages/edit-site/src/components/header-edit-mode/document-tools/index.js b/packages/edit-site/src/components/header-edit-mode/document-tools/index.js
index b67f842128e26..9db8e091265e2 100644
--- a/packages/edit-site/src/components/header-edit-mode/document-tools/index.js
+++ b/packages/edit-site/src/components/header-edit-mode/document-tools/index.js
@@ -35,27 +35,30 @@ export default function DocumentTools( {
hasFixedToolbar,
isDistractionFree,
showIconLabels,
- setListViewToggleElement,
} ) {
const inserterButton = useRef();
- const { isInserterOpen, isListViewOpen, listViewShortcut, isVisualMode } =
- useSelect( ( select ) => {
- const { getEditorMode } = select( editSiteStore );
- const { getShortcutRepresentation } = select(
- keyboardShortcutsStore
- );
- const { isInserterOpened, isListViewOpened } =
- select( editorStore );
+ const {
+ isInserterOpen,
+ isListViewOpen,
+ listViewShortcut,
+ isVisualMode,
+ listViewToggleRef,
+ } = useSelect( ( select ) => {
+ const { getEditorMode } = select( editSiteStore );
+ const { getShortcutRepresentation } = select( keyboardShortcutsStore );
+ const { isInserterOpened, isListViewOpened, getListViewToggleRef } =
+ unlock( select( editorStore ) );
- return {
- isInserterOpen: isInserterOpened(),
- isListViewOpen: isListViewOpened(),
- listViewShortcut: getShortcutRepresentation(
- 'core/edit-site/toggle-list-view'
- ),
- isVisualMode: getEditorMode() === 'visual',
- };
- }, [] );
+ return {
+ isInserterOpen: isInserterOpened(),
+ isListViewOpen: isListViewOpened(),
+ listViewShortcut: getShortcutRepresentation(
+ 'core/edit-site/toggle-list-view'
+ ),
+ isVisualMode: getEditorMode() === 'visual',
+ listViewToggleRef: getListViewToggleRef(),
+ };
+ }, [] );
const { __unstableSetEditorMode } = useDispatch( blockEditorStore );
const { setDeviceType, setIsInserterOpened, setIsListViewOpened } =
useDispatch( editorStore );
@@ -161,7 +164,7 @@ export default function DocumentTools( {
/* translators: button label text should, if possible, be under 16 characters. */
label={ __( 'List View' ) }
onClick={ toggleListView }
- ref={ setListViewToggleElement }
+ ref={ listViewToggleRef }
shortcut={ listViewShortcut }
showTooltip={ ! showIconLabels }
variant={
diff --git a/packages/edit-site/src/components/header-edit-mode/index.js b/packages/edit-site/src/components/header-edit-mode/index.js
index 4b9d48d797952..0d24865e74bf6 100644
--- a/packages/edit-site/src/components/header-edit-mode/index.js
+++ b/packages/edit-site/src/components/header-edit-mode/index.js
@@ -44,7 +44,7 @@ import { FOCUSABLE_ENTITIES } from '../../utils/constants';
const { PostViewLink, PreviewDropdown } = unlock( editorPrivateApis );
-export default function HeaderEditMode( { setListViewToggleElement } ) {
+export default function HeaderEditMode() {
const {
templateType,
isDistractionFree,
@@ -137,7 +137,6 @@ export default function HeaderEditMode( { setListViewToggleElement } ) {
blockEditorMode={ blockEditorMode }
isDistractionFree={ isDistractionFree }
showIconLabels={ showIconLabels }
- setListViewToggleElement={ setListViewToggleElement }
/>
{ isTopToolbar && (
<>
diff --git a/packages/edit-site/src/components/layout/index.js b/packages/edit-site/src/components/layout/index.js
index 6d62ba1df07f4..c6ad3cf565b12 100644
--- a/packages/edit-site/src/components/layout/index.js
+++ b/packages/edit-site/src/components/layout/index.js
@@ -129,8 +129,6 @@ export default function Layout() {
const isEditorLoading = useIsSiteEditorLoading();
const [ isResizableFrameOversized, setIsResizableFrameOversized ] =
useState( false );
- const [ listViewToggleElement, setListViewToggleElement ] =
- useState( null );
// This determines which animation variant should apply to the header.
// There is also a `isDistractionFreeHovering` state that gets priority
@@ -258,11 +256,7 @@ export default function Layout() {
ease: 'easeOut',
} }
>
-
+
) }
@@ -367,9 +361,6 @@ export default function Layout() {
} }
>
{
setIsListViewOpened( false );
- listViewToggleElement?.focus();
- }, [ listViewToggleElement, setIsListViewOpened ] );
+ getListViewToggleRef().current?.focus();
+ }, [ getListViewToggleRef, setIsListViewOpened ] );
const closeOnEscape = useCallback(
( event ) => {
diff --git a/packages/edit-widgets/package.json b/packages/edit-widgets/package.json
index 1ef98df31269f..974a0ba02905f 100644
--- a/packages/edit-widgets/package.json
+++ b/packages/edit-widgets/package.json
@@ -53,7 +53,8 @@
"@wordpress/reusable-blocks": "file:../reusable-blocks",
"@wordpress/url": "file:../url",
"@wordpress/widgets": "file:../widgets",
- "classnames": "^2.3.1"
+ "classnames": "^2.3.1",
+ "rememo": "^4.0.2"
},
"peerDependencies": {
"react": "^18.0.0",
diff --git a/packages/edit-widgets/src/components/header/document-tools/index.js b/packages/edit-widgets/src/components/header/document-tools/index.js
index 8cac7590be5e8..06376bbd76291 100644
--- a/packages/edit-widgets/src/components/header/document-tools/index.js
+++ b/packages/edit-widgets/src/components/header/document-tools/index.js
@@ -24,7 +24,7 @@ import { unlock } from '../../../lock-unlock';
const { useShouldContextualToolbarShow } = unlock( blockEditorPrivateApis );
-function DocumentTools( { setListViewToggleElement } ) {
+function DocumentTools() {
const isMediumViewport = useViewportMatch( 'medium' );
const inserterButton = useRef();
const widgetAreaClientId = useLastSelectedWidgetArea();
@@ -35,14 +35,18 @@ function DocumentTools( { setListViewToggleElement } ) {
),
[ widgetAreaClientId ]
);
- const { isInserterOpen, isListViewOpen } = useSelect( ( select ) => {
- const { isInserterOpened, isListViewOpened } =
- select( editWidgetsStore );
- return {
- isInserterOpen: isInserterOpened(),
- isListViewOpen: isListViewOpened(),
- };
- }, [] );
+ const { isInserterOpen, isListViewOpen, listViewToggleRef } = useSelect(
+ ( select ) => {
+ const { isInserterOpened, isListViewOpened, getListViewToggleRef } =
+ unlock( select( editWidgetsStore ) );
+ return {
+ isInserterOpen: isInserterOpened(),
+ isListViewOpen: isListViewOpened(),
+ listViewToggleRef: getListViewToggleRef(),
+ };
+ },
+ []
+ );
const { setIsWidgetAreaOpen, setIsInserterOpened, setIsListViewOpened } =
useDispatch( editWidgetsStore );
const { selectBlock } = useDispatch( blockEditorStore );
@@ -119,7 +123,7 @@ function DocumentTools( { setListViewToggleElement } ) {
/* translators: button label text should, if possible, be under 16 characters. */
label={ __( 'List View' ) }
onClick={ toggleListView }
- ref={ setListViewToggleElement }
+ ref={ listViewToggleRef }
/>
>
) }
diff --git a/packages/edit-widgets/src/components/header/index.js b/packages/edit-widgets/src/components/header/index.js
index 9d4cb4cb60103..0aadec83d5d2f 100644
--- a/packages/edit-widgets/src/components/header/index.js
+++ b/packages/edit-widgets/src/components/header/index.js
@@ -17,7 +17,7 @@ import DocumentTools from './document-tools';
import SaveButton from '../save-button';
import MoreMenu from '../more-menu';
-function Header( { setListViewToggleElement } ) {
+function Header() {
const isLargeViewport = useViewportMatch( 'medium' );
const blockToolbarRef = useRef();
const { hasFixedToolbar } = useSelect(
@@ -47,9 +47,7 @@ function Header( { setListViewToggleElement } ) {
{ __( 'Widgets' ) }
) }
-
+
{ hasFixedToolbar && isLargeViewport && (
<>
diff --git a/packages/edit-widgets/src/components/layout/interface.js b/packages/edit-widgets/src/components/layout/interface.js
index 2cb1eebcfab73..987e3868de133 100644
--- a/packages/edit-widgets/src/components/layout/interface.js
+++ b/packages/edit-widgets/src/components/layout/interface.js
@@ -3,7 +3,7 @@
*/
import { useViewportMatch } from '@wordpress/compose';
import { BlockBreadcrumb } from '@wordpress/block-editor';
-import { useEffect, useState } from '@wordpress/element';
+import { useEffect } from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
import {
InterfaceSkeleton,
@@ -68,9 +68,6 @@ function Interface( { blockEditorSettings } ) {
[]
);
- const [ listViewToggleElement, setListViewToggleElement ] =
- useState( null );
-
// Inserter and Sidebars are mutually exclusive
useEffect( () => {
if ( hasSidebarEnabled && ! isHugeViewport ) {
@@ -97,16 +94,8 @@ function Interface( { blockEditorSettings } ) {
...interfaceLabels,
secondarySidebar: secondarySidebarLabel,
} }
- header={
-
- }
- secondarySidebar={
- hasSecondarySidebar && (
-
- )
- }
+ header={ }
+ secondarySidebar={ hasSecondarySidebar && }
sidebar={
hasSidebarEnabled && (
diff --git a/packages/edit-widgets/src/components/secondary-sidebar/index.js b/packages/edit-widgets/src/components/secondary-sidebar/index.js
index 20488e4478b98..49e240bd147cb 100644
--- a/packages/edit-widgets/src/components/secondary-sidebar/index.js
+++ b/packages/edit-widgets/src/components/secondary-sidebar/index.js
@@ -13,7 +13,7 @@ import { store as editWidgetsStore } from '../../store';
import InserterSidebar from './inserter-sidebar';
import ListViewSidebar from './list-view-sidebar';
-export default function SecondarySidebar( { listViewToggleElement } ) {
+export default function SecondarySidebar() {
const { isInserterOpen, isListViewOpen } = useSelect( ( select ) => {
const { isInserterOpened, isListViewOpened } =
select( editWidgetsStore );
@@ -27,9 +27,7 @@ export default function SecondarySidebar( { listViewToggleElement } ) {
return ;
}
if ( isListViewOpen ) {
- return (
-
- );
+ return ;
}
return null;
}
diff --git a/packages/edit-widgets/src/components/secondary-sidebar/list-view-sidebar.js b/packages/edit-widgets/src/components/secondary-sidebar/list-view-sidebar.js
index 5104a587d9e2c..6aa2123a6774a 100644
--- a/packages/edit-widgets/src/components/secondary-sidebar/list-view-sidebar.js
+++ b/packages/edit-widgets/src/components/secondary-sidebar/list-view-sidebar.js
@@ -4,7 +4,7 @@
import { __experimentalListView as ListView } from '@wordpress/block-editor';
import { Button } from '@wordpress/components';
import { useFocusOnMount, useMergeRefs } from '@wordpress/compose';
-import { useDispatch } from '@wordpress/data';
+import { useDispatch, useSelect } from '@wordpress/data';
import { useCallback, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { closeSmall } from '@wordpress/icons';
@@ -14,9 +14,11 @@ import { ESCAPE } from '@wordpress/keycodes';
* Internal dependencies
*/
import { store as editWidgetsStore } from '../../store';
+import { unlock } from '../../lock-unlock';
-export default function ListViewSidebar( { listViewToggleElement } ) {
+export default function ListViewSidebar() {
const { setIsListViewOpened } = useDispatch( editWidgetsStore );
+ const { getListViewToggleRef } = unlock( useSelect( editWidgetsStore ) );
// Use internal state instead of a ref to make sure that the component
// re-renders when the dropZoneElement updates.
@@ -27,8 +29,8 @@ export default function ListViewSidebar( { listViewToggleElement } ) {
// When closing the list view, focus should return to the toggle button.
const closeListView = useCallback( () => {
setIsListViewOpened( false );
- listViewToggleElement?.focus();
- }, [ listViewToggleElement, setIsListViewOpened ] );
+ getListViewToggleRef().current?.focus();
+ }, [ getListViewToggleRef, setIsListViewOpened ] );
const closeOnEscape = useCallback(
( event ) => {
diff --git a/packages/edit-widgets/src/store/index.js b/packages/edit-widgets/src/store/index.js
index b8542b2fa5cf1..8768b45954b93 100644
--- a/packages/edit-widgets/src/store/index.js
+++ b/packages/edit-widgets/src/store/index.js
@@ -11,7 +11,9 @@ import reducer from './reducer';
import * as resolvers from './resolvers';
import * as selectors from './selectors';
import * as actions from './actions';
+import * as privateSelectors from './private-selectors';
import { STORE_NAME } from './constants';
+import { unlock } from '../lock-unlock';
/**
* Block editor data store configuration.
@@ -47,3 +49,5 @@ apiFetch.use( function ( options, next ) {
return next( options );
} );
+
+unlock( store ).registerPrivateSelectors( privateSelectors );
diff --git a/packages/edit-widgets/src/store/private-selectors.js b/packages/edit-widgets/src/store/private-selectors.js
new file mode 100644
index 0000000000000..29911091622fb
--- /dev/null
+++ b/packages/edit-widgets/src/store/private-selectors.js
@@ -0,0 +1,16 @@
+/**
+ * External dependencies
+ */
+import createSelector from 'rememo';
+
+/**
+ * WordPress dependencies
+ */
+import { createRef } from '@wordpress/element';
+
+export const getListViewToggleRef = createSelector(
+ () => {
+ return createRef();
+ },
+ () => []
+);
diff --git a/packages/editor/src/store/private-selectors.js b/packages/editor/src/store/private-selectors.js
index 0ab97dea67ce5..b05dcae93c947 100644
--- a/packages/editor/src/store/private-selectors.js
+++ b/packages/editor/src/store/private-selectors.js
@@ -1,8 +1,14 @@
+/**
+ * External dependencies
+ */
+import createSelector from 'rememo';
+
/**
* WordPress dependencies
*/
import { store as blockEditorStore } from '@wordpress/block-editor';
import { createRegistrySelector } from '@wordpress/data';
+import { createRef } from '@wordpress/element';
/**
* Internal dependencies
@@ -45,3 +51,10 @@ export const getInsertionPoint = createRegistrySelector(
return EMPTY_INSERTION_POINT;
}
);
+
+export const getListViewToggleRef = createSelector(
+ () => {
+ return createRef();
+ },
+ () => []
+);