diff --git a/packages/customize-widgets/src/components/block-inspector-button/index.js b/packages/customize-widgets/src/components/block-inspector-button/index.js
new file mode 100644
index 0000000000000..c68c2f46c7468
--- /dev/null
+++ b/packages/customize-widgets/src/components/block-inspector-button/index.js
@@ -0,0 +1,38 @@
+/**
+ * WordPress dependencies
+ */
+import { useMemo } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import { MenuItem } from '@wordpress/components';
+import { useSelect } from '@wordpress/data';
+import { store as blockEditorStore } from '@wordpress/block-editor';
+
+function BlockInspectorButton( { inspector, closeMenu, ...props } ) {
+ const selectedBlockClientId = useSelect(
+ ( select ) => select( blockEditorStore ).getSelectedBlockClientId(),
+ []
+ );
+
+ const selectedBlock = useMemo(
+ () => document.getElementById( `block-${ selectedBlockClientId }` ),
+ [ selectedBlockClientId ]
+ );
+
+ return (
+
+ );
+}
+
+export default BlockInspectorButton;
diff --git a/packages/customize-widgets/src/components/block-inspector-button/style.scss b/packages/customize-widgets/src/components/block-inspector-button/style.scss
new file mode 100644
index 0000000000000..b9a4f0f85d13a
--- /dev/null
+++ b/packages/customize-widgets/src/components/block-inspector-button/style.scss
@@ -0,0 +1,21 @@
+#customize-theme-controls .customize-pane-child.accordion-section-content.customize-widgets-layout__inspector {
+ background: $white;
+ box-sizing: border-box;
+
+ * {
+ box-sizing: inherit;
+ }
+
+ .block-editor-block-inspector {
+ margin: -$grid-unit-15;
+
+ // To override the style in block-editor/block-inspector.
+ h3 {
+ margin-bottom: 0;
+ }
+ }
+}
+
+#customize-theme-controls .customize-pane-child.control-section-sidebar.is-sub-section-open {
+ transform: translateX(-100%);
+}
diff --git a/packages/customize-widgets/src/components/inspector/block-inspector-button.js b/packages/customize-widgets/src/components/inspector/block-inspector-button.js
deleted file mode 100644
index bbf45103063f6..0000000000000
--- a/packages/customize-widgets/src/components/inspector/block-inspector-button.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { __ } from '@wordpress/i18n';
-import { MenuItem } from '@wordpress/components';
-
-function BlockInspectorButton( { isInspectorOpened = false, ...props } ) {
- const label = isInspectorOpened
- ? __( 'Hide more settings' )
- : __( 'Show more settings' );
-
- return ;
-}
-
-export default BlockInspectorButton;
diff --git a/packages/customize-widgets/src/components/inspector/index.js b/packages/customize-widgets/src/components/inspector/index.js
deleted file mode 100644
index 6a362ab9a338f..0000000000000
--- a/packages/customize-widgets/src/components/inspector/index.js
+++ /dev/null
@@ -1,122 +0,0 @@
-/**
- * External dependencies
- */
-import classnames from 'classnames';
-
-/**
- * WordPress dependencies
- */
-import { useEffect, useRef } from '@wordpress/element';
-import { useSelect } from '@wordpress/data';
-import {
- BlockInspector,
- store as blockEditorStore,
-} from '@wordpress/block-editor';
-import { __ } from '@wordpress/i18n';
-import { useInstanceId } from '@wordpress/compose';
-
-export { default as BlockInspectorButton } from './block-inspector-button';
-
-function InspectorSectionMeta( { closeInspector, inspectorTitleId } ) {
- return (
-
-
-
-
-
- { __( 'Customizing ▸ Widgets' ) }
-
- { __( 'Block Settings' ) }
-
-
-
- );
-}
-
-export default function Inspector( {
- isOpened,
- isAnimating,
- setInspectorOpenState,
-} ) {
- const selectedBlockClientId = useSelect( ( select ) =>
- select( blockEditorStore ).getSelectedBlockClientId()
- );
- const selectedBlockRef = useRef();
-
- useEffect( () => {
- selectedBlockRef.current = document.querySelector(
- `[data-block="${ selectedBlockClientId }"]`
- );
- }, [ selectedBlockClientId ] );
-
- const inspectorTitleId = useInstanceId(
- Inspector,
- 'customize-widgets-block-settings'
- );
-
- useEffect( () => {
- const openedSidebarSection = document.querySelector(
- '.control-section-sidebar.open'
- );
-
- if ( isOpened ) {
- openedSidebarSection.classList.add( 'is-inspector-open' );
- } else {
- openedSidebarSection.classList.remove( 'is-inspector-open' );
- }
-
- // In case the "transitionend" event for some reasons doesn't fire.
- // (Like when it's set to "display: none", or when the transition property is removed.)
- // See https://github.com/w3c/csswg-drafts/issues/3043
- const timer = setTimeout( () => {
- setInspectorOpenState( 'TRANSITION_END' );
- }, 180 );
-
- return () => {
- openedSidebarSection.classList.remove( 'is-inspector-open' );
- clearTimeout( timer );
- };
- }, [ isOpened, setInspectorOpenState ] );
-
- return (
- {
- setInspectorOpenState( 'TRANSITION_END' );
- } }
- >
- {
- setInspectorOpenState( 'CLOSE' );
-
- // Wait a tick so that the block editor can transition back from being hidden.
- window.requestAnimationFrame( () => {
- selectedBlockRef.current?.focus();
- } );
- } }
- inspectorTitleId={ inspectorTitleId }
- />
-
-
-
- );
-}
diff --git a/packages/customize-widgets/src/components/inspector/style.scss b/packages/customize-widgets/src/components/inspector/style.scss
deleted file mode 100644
index 42b284a9b466a..0000000000000
--- a/packages/customize-widgets/src/components/inspector/style.scss
+++ /dev/null
@@ -1,25 +0,0 @@
-// To override the style in block-editor/block-inspector.
-.block-editor-block-inspector h3 {
- margin-bottom: 0;
-}
-
-#customize-theme-controls .customize-pane-child.accordion-section-content.customize-widgets-layout__inspector {
- background: $white;
- box-sizing: border-box;
-
- * {
- box-sizing: inherit;
- }
-
- .block-editor-block-inspector {
- margin: -$grid-unit-15;
- }
-}
-
-#customize-theme-controls .customize-pane-child.accordion-section-content.control-section-sidebar.open {
- transition: 0.18s transform cubic-bezier(0.645, 0.045, 0.355, 1); /* easeInOutCubic */
-
- &.is-inspector-open {
- transform: translateX(-100%);
- }
-}
diff --git a/packages/customize-widgets/src/components/sidebar-block-editor/index.js b/packages/customize-widgets/src/components/sidebar-block-editor/index.js
index cddd59ce80096..1b9c0660bbc35 100644
--- a/packages/customize-widgets/src/components/sidebar-block-editor/index.js
+++ b/packages/customize-widgets/src/components/sidebar-block-editor/index.js
@@ -1,11 +1,12 @@
/**
* WordPress dependencies
*/
-import { useReducer, createPortal, useMemo } from '@wordpress/element';
+import { createPortal, useMemo } from '@wordpress/element';
import {
BlockEditorProvider,
BlockList,
BlockSelectionClearer,
+ BlockInspector,
ObserveTyping,
WritingFlow,
BlockEditorKeyboardShortcuts,
@@ -20,39 +21,13 @@ import {
/**
* Internal dependencies
*/
-import Inspector, { BlockInspectorButton } from '../inspector';
+import BlockInspectorButton from '../block-inspector-button';
import Header from '../header';
import useSidebarBlockEditor from './use-sidebar-block-editor';
import useInserter from '../inserter/use-inserter';
-const inspectorOpenStateReducer = ( state, action ) => {
- switch ( action ) {
- case 'OPEN':
- return {
- open: true,
- busy: true,
- };
- case 'TRANSITION_END':
- return {
- ...state,
- busy: false,
- };
- case 'CLOSE':
- return {
- open: false,
- busy: true,
- };
- default:
- throw new Error( 'Unexpected action' );
- }
-};
-
-export default function SidebarBlockEditor( { sidebar, inserter } ) {
+export default function SidebarBlockEditor( { sidebar, inserter, inspector } ) {
const [ blocks, onInput, onChange ] = useSidebarBlockEditor( sidebar );
- const [
- { open: isInspectorOpened, busy: isInspectorAnimating },
- setInspectorOpenState,
- ] = useReducer( inspectorOpenStateReducer, { open: false, busy: false } );
const parentContainer = document.getElementById(
'customize-theme-controls'
);
@@ -69,52 +44,46 @@ export default function SidebarBlockEditor( { sidebar, inserter } ) {
-
-
-
+
+
-
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
+
{ createPortal(
- ,
- parentContainer
+ // This is a temporary hack to prevent button component inside
+ // from submitting form when type="button" is not specified.
+ ,
+ inspector.contentContainer[ 0 ]
) }
<__experimentalBlockSettingsMenuFirstItem>
{ ( { onClose } ) => (
{
- // Open the inspector,
- setInspectorOpenState( 'OPEN' );
- // Then close the dropdown menu.
- onClose();
- } }
+ inspector={ inspector }
+ closeMenu={ onClose }
/>
) }
diff --git a/packages/customize-widgets/src/controls/inspector-section.js b/packages/customize-widgets/src/controls/inspector-section.js
new file mode 100644
index 0000000000000..7c74c1085b214
--- /dev/null
+++ b/packages/customize-widgets/src/controls/inspector-section.js
@@ -0,0 +1,58 @@
+const {
+ wp: { customize },
+} = window;
+
+class InspectorSection extends customize.Section {
+ constructor( id, options ) {
+ super( id, options );
+
+ this.parentSection = options.parentSection;
+
+ this.returnFocusWhenClose = null;
+ }
+ ready() {
+ this.contentContainer[ 0 ].classList.add(
+ 'customize-widgets-layout__inspector'
+ );
+ }
+ onChangeExpanded( expanded, args ) {
+ super.onChangeExpanded( expanded, args );
+
+ if ( this.parentSection && ! args.unchanged ) {
+ if ( expanded ) {
+ this.parentSection.collapse( {
+ manualTransition: true,
+ } );
+ } else {
+ this.parentSection.expand( {
+ manualTransition: true,
+ completeCallback: () => {
+ // Return focus after finishing the transition.
+ if (
+ this.returnFocusWhenClose &&
+ ! this.contentContainer[ 0 ].contains(
+ this.returnFocusWhenClose
+ )
+ ) {
+ this.returnFocusWhenClose.focus();
+ }
+ },
+ } );
+ }
+ }
+ }
+ open( { returnFocusWhenClose } = {} ) {
+ this.returnFocusWhenClose = returnFocusWhenClose;
+
+ this.expand( {
+ allowMultiple: true,
+ } );
+ }
+ close() {
+ this.collapse( {
+ allowMultiple: true,
+ } );
+ }
+}
+
+export default InspectorSection;
diff --git a/packages/customize-widgets/src/controls/sidebar-control.js b/packages/customize-widgets/src/controls/sidebar-control.js
index 32d3fe0823894..f10789bf15967 100644
--- a/packages/customize-widgets/src/controls/sidebar-control.js
+++ b/packages/customize-widgets/src/controls/sidebar-control.js
@@ -20,28 +20,36 @@ class SidebarControl extends customize.Control {
ready() {
this.inserter = new InserterOuterSection( inserterId, {} );
customize.section.add( this.inserter );
+
+ this.sectionInstance = customize.section( this.section() );
+
+ this.inspector = this.sectionInstance.inspector;
+
this.render();
}
- onChangeExpanded() {
- this.render();
- }
- expanded() {
- return customize.section( this.section() ).expanded();
+ onChangeSectionExpanded( expanded, args ) {
+ if ( ! args.unchanged ) {
+ // Close the inserter when the section collapses.
+ if ( ! expanded ) {
+ this.inserter.close();
+ }
+
+ this.render();
+ }
}
render() {
- if ( this.expanded() ) {
+ if ( this.sectionInstance.expanded() ) {
render(
,
this.container[ 0 ]
);
- } else {
+ } else if ( ! this.sectionInstance.hasSubSectionOpened() ) {
+ // Don't unmount the node when the sub section (inspector) is opened.
unmountComponentAtNode( this.container[ 0 ] );
-
- // Close the inserter when the section collapses.
- this.inserter.close();
}
}
}
diff --git a/packages/customize-widgets/src/controls/sidebar-section.js b/packages/customize-widgets/src/controls/sidebar-section.js
index 3cc165f4c3fbd..b91676c3d194b 100644
--- a/packages/customize-widgets/src/controls/sidebar-section.js
+++ b/packages/customize-widgets/src/controls/sidebar-section.js
@@ -1,14 +1,72 @@
+/**
+ * WordPress dependencies
+ */
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import InspectorSection from './inspector-section';
+
const {
wp: { customize },
} = window;
+const getInspectorSectionId = ( sidebarId ) =>
+ `widgets-inspector-${ sidebarId }`;
+
class SidebarSection extends customize.Section {
+ ready() {
+ this.inspector = new InspectorSection(
+ getInspectorSectionId( this.id ),
+ {
+ title: __( 'Block Settings' ),
+ parentSection: this,
+ customizeAction: [
+ __( 'Customizing' ),
+ __( 'Widgets' ),
+ this.params.title,
+ ].join( ' ▸ ' ),
+ }
+ );
+ customize.section.add( this.inspector );
+ }
+ hasSubSectionOpened() {
+ return this.inspector.expanded();
+ }
onChangeExpanded( expanded, args ) {
- super.onChangeExpanded( expanded, args );
+ if ( args.manualTransition ) {
+ if ( expanded ) {
+ this.contentContainer.addClass( [ 'busy', 'open' ] );
+ this.contentContainer.removeClass( 'is-sub-section-open' );
+ this.contentContainer
+ .closest( '.wp-full-overlay' )
+ .addClass( 'section-open' );
+ this.contentContainer.one( 'transitionend', () => {
+ this.contentContainer.removeClass( 'busy' );
+ args.completeCallback?.();
+ } );
+ } else {
+ this.contentContainer.addClass( [
+ 'busy',
+ 'is-sub-section-open',
+ ] );
+ this.contentContainer
+ .closest( '.wp-full-overlay' )
+ .addClass( 'section-open' );
+ this.contentContainer.removeClass( 'open' );
+ this.contentContainer.one( 'transitionend', () => {
+ this.contentContainer.removeClass( 'busy' );
+ args.completeCallback?.();
+ } );
+ }
+ } else {
+ super.onChangeExpanded( expanded, args );
+ }
const controls = this.controls();
controls.forEach( ( control ) => {
- control.onChangeExpanded( expanded, args );
+ control.onChangeSectionExpanded( expanded, args );
} );
}
}
diff --git a/packages/customize-widgets/src/style.scss b/packages/customize-widgets/src/style.scss
index 13b614322b10e..96954c0210097 100644
--- a/packages/customize-widgets/src/style.scss
+++ b/packages/customize-widgets/src/style.scss
@@ -1,3 +1,3 @@
-@import "./components/inspector/style.scss";
+@import "./components/block-inspector-button/style.scss";
@import "./components/header/style.scss";
@import "./components/inserter/style.scss";