diff --git a/packages/edit-post/src/components/layout/index.js b/packages/edit-post/src/components/layout/index.js
index 185f97ba45a56..2cbf5c32e814b 100644
--- a/packages/edit-post/src/components/layout/index.js
+++ b/packages/edit-post/src/components/layout/index.js
@@ -24,7 +24,12 @@ import {
} from '@wordpress/block-editor';
import { PluginArea } from '@wordpress/plugins';
import { __, sprintf } from '@wordpress/i18n';
-import { useCallback, useMemo } from '@wordpress/element';
+import {
+ useCallback,
+ useLayoutEffect,
+ useMemo,
+ useRef,
+} from '@wordpress/element';
import { store as noticesStore } from '@wordpress/notices';
import { store as preferencesStore } from '@wordpress/preferences';
import {
@@ -36,8 +41,8 @@ import { privateApis as blockLibraryPrivateApis } from '@wordpress/block-library
import { addQueryArgs } from '@wordpress/url';
import { decodeEntities } from '@wordpress/html-entities';
import { store as coreStore } from '@wordpress/core-data';
-import { SlotFillProvider } from '@wordpress/components';
-import { useViewportMatch } from '@wordpress/compose';
+import { ResizableBox, SlotFillProvider } from '@wordpress/components';
+import { useMediaQuery, useViewportMatch } from '@wordpress/compose';
/**
* Internal dependencies
@@ -151,6 +156,118 @@ function useEditorStyles() {
] );
}
+/**
+ * @param {Object} props
+ * @param {boolean} props.isLegacy True when the editor canvas is not in an iframe.
+ */
+function MetaBoxesMain( { isLegacy } ) {
+ const [ isOpen, openHeight, hasAnyVisible ] = useSelect( ( select ) => {
+ const { get } = select( preferencesStore );
+ const { isMetaBoxLocationVisible } = select( editPostStore );
+ return [
+ get( 'core/edit-post', 'metaBoxesMainIsOpen' ),
+ get( 'core/edit-post', 'metaBoxesMainOpenHeight' ),
+ isMetaBoxLocationVisible( 'normal' ) ||
+ isMetaBoxLocationVisible( 'advanced' ) ||
+ isMetaBoxLocationVisible( 'side' ),
+ ];
+ }, [] );
+ const { set: setPreference } = useDispatch( preferencesStore );
+ const resizableBoxRef = useRef();
+ const isShort = useMediaQuery( '(max-height: 549px)' );
+
+ const isAutoHeight = openHeight === undefined;
+ // In case a user size is set stops the default max-height from applying.
+ useLayoutEffect( () => {
+ if ( ! isLegacy && hasAnyVisible && ! isShort && ! isAutoHeight ) {
+ resizableBoxRef.current.resizable.classList.add( 'has-user-size' );
+ }
+ }, [ isAutoHeight, isShort, hasAnyVisible, isLegacy ] );
+
+ if ( ! hasAnyVisible ) {
+ return;
+ }
+
+ const className = 'edit-post-meta-boxes-main';
+ const contents = (
+
+
+
+
+ );
+
+ if ( isLegacy ) {
+ return contents;
+ }
+
+ if ( isShort ) {
+ return (
+ {
+ setPreference(
+ 'core/edit-post',
+ 'metaBoxesMainIsOpen',
+ target.open
+ );
+ } }
+ >
+ { __( 'Meta Boxes' ) }
+ { contents }
+
+ );
+ }
+ return (
+ {
+ target.setPointerCapture( pointerId );
+ } }
+ onResizeStart={ ( event, direction, elementRef ) => {
+ // Avoids height jumping in case it’s limited by max-height.
+ elementRef.style.height = `${ elementRef.offsetHeight }px`;
+ // Stops initial max-height from being applied.
+ elementRef.classList.add( 'has-user-size' );
+ } }
+ onResizeStop={ () => {
+ setPreference(
+ 'core/edit-post',
+ 'metaBoxesMainOpenHeight',
+ resizableBoxRef.current.state.height
+ );
+ } }
+ >
+ { contents }
+
+ );
+}
+
function Layout( {
postId: initialPostId,
postType: initialPostType,
@@ -355,10 +472,7 @@ function Layout( {
extraContent={
! isDistractionFree &&
showMetaBoxes && (
-
-
-
-
+
)
}
>
diff --git a/packages/edit-post/src/components/layout/style.scss b/packages/edit-post/src/components/layout/style.scss
index 5fdaceaa002be..5392a7e9da4d9 100644
--- a/packages/edit-post/src/components/layout/style.scss
+++ b/packages/edit-post/src/components/layout/style.scss
@@ -1,6 +1,70 @@
-.edit-post-layout__metaboxes {
- flex-shrink: 0;
- clear: both;
+.edit-post-meta-boxes-main {
+ filter: drop-shadow(0 -1px rgba($color: #000, $alpha: 0.133)); // 0.133 = $gray-200 but with alpha.
+ background-color: $white;
+ clear: both; // This is seemingly only needed in case the canvas is not iframe’d.
+
+ &:not(details) {
+ padding-top: 23px;
+ max-height: 100%;
+
+ &:not(.has-user-size) {
+ max-height: 50% !important;
+ }
+ }
+
+ // The component renders as a details element in short viewports.
+ &:is(details) {
+ & > summary {
+ cursor: pointer;
+ color: $gray-900;
+ background-color: $white;
+ height: $button-size-compact;
+ line-height: $button-size-compact;
+ font-size: 13px;
+ padding-left: $grid-unit-30;
+ box-shadow: 0 $border-width $gray-300;
+ }
+
+ &[open] > summary {
+ position: sticky;
+ top: 0;
+ z-index: 1;
+ }
+ }
+
+ & .components-resizable-box__handle-top {
+ top: 0;
+ box-shadow: 0 $border-width $gray-300;
+ }
+ & .components-resizable-box__side-handle::before {
+ border-radius: 0;
+ top: 0;
+ height: $border-width;
+ }
+ & .components-resizable-box__handle::after {
+ background-color: $gray-300;
+ box-shadow: none;
+ border-radius: 4px;
+ height: $grid-unit-05;
+ top: calc(50% - #{$grid-unit-05} / 2);
+ width: 100px;
+ right: calc(50% - 50px);
+ }
+}
+
+.edit-post-meta-boxes-main__liner {
+ overflow: auto;
+ max-height: 100%;
+ // Keep the contents behind the resize handle or details summary.
+ isolation: isolate;
+}
+
+.has-metaboxes .editor-visual-editor {
+ flex: 1;
+
+ &.is-iframed {
+ isolation: isolate;
+ }
}
// Adjust the position of the notices
diff --git a/packages/edit-post/src/components/layout/use-should-iframe.js b/packages/edit-post/src/components/layout/use-should-iframe.js
index 248ea53109f25..e36a4773c4a1f 100644
--- a/packages/edit-post/src/components/layout/use-should-iframe.js
+++ b/packages/edit-post/src/components/layout/use-should-iframe.js
@@ -6,11 +6,6 @@ import { useSelect } from '@wordpress/data';
import { store as blocksStore } from '@wordpress/blocks';
import { store as blockEditorStore } from '@wordpress/block-editor';
-/**
- * Internal dependencies
- */
-import { store as editPostStore } from '../../store';
-
const isGutenbergPlugin = globalThis.IS_GUTENBERG_PLUGIN ? true : false;
export function useShouldIframe() {
@@ -18,7 +13,6 @@ export function useShouldIframe() {
isBlockBasedTheme,
hasV3BlocksOnly,
isEditingTemplate,
- hasMetaBoxes,
isZoomOutMode,
} = useSelect( ( select ) => {
const { getEditorSettings, getCurrentPostType } = select( editorStore );
@@ -31,14 +25,13 @@ export function useShouldIframe() {
return type.apiVersion >= 3;
} ),
isEditingTemplate: getCurrentPostType() === 'wp_template',
- hasMetaBoxes: select( editPostStore ).hasMetaBoxes(),
isZoomOutMode: __unstableGetEditorMode() === 'zoom-out',
};
}, [] );
return (
- ( ( hasV3BlocksOnly || ( isGutenbergPlugin && isBlockBasedTheme ) ) &&
- ! hasMetaBoxes ) ||
+ hasV3BlocksOnly ||
+ ( isGutenbergPlugin && isBlockBasedTheme ) ||
isEditingTemplate ||
isZoomOutMode
);
diff --git a/packages/edit-post/src/store/selectors.js b/packages/edit-post/src/store/selectors.js
index da1f9959e32e9..5bea6e7d35eb6 100644
--- a/packages/edit-post/src/store/selectors.js
+++ b/packages/edit-post/src/store/selectors.js
@@ -379,7 +379,6 @@ export const isMetaBoxLocationVisible = createRegistrySelector(
isMetaBoxLocationActive( state, location ) &&
getMetaBoxesPerLocation( state, location )?.some( ( { id } ) => {
return select( editorStore ).isEditorPanelEnabled(
- state,
`meta-box-${ id }`
);
} )
diff --git a/test/e2e/specs/editor/plugins/meta-boxes.spec.js b/test/e2e/specs/editor/plugins/meta-boxes.spec.js
index 1b7adc18760ff..511b3837f8030 100644
--- a/test/e2e/specs/editor/plugins/meta-boxes.spec.js
+++ b/test/e2e/specs/editor/plugins/meta-boxes.spec.js
@@ -26,7 +26,7 @@ test.describe( 'Meta boxes', () => {
await expect( saveDraft ).toBeDisabled();
// Add title to enable valid non-empty post save.
- await page
+ await editor.canvas
.getByRole( 'textbox', { name: 'Add title' } )
.fill( 'Hello Meta' );
@@ -44,7 +44,7 @@ test.describe( 'Meta boxes', () => {
page,
} ) => {
// Publish a post so there's something for the latest posts dynamic block to render.
- await page
+ await editor.canvas
.getByRole( 'textbox', { name: 'Add title' } )
.fill( 'A published post' );
await page.keyboard.press( 'Enter' );
@@ -53,7 +53,7 @@ test.describe( 'Meta boxes', () => {
// Publish a post with the latest posts dynamic block.
await admin.createNewPost();
- await page
+ await editor.canvas
.getByRole( 'textbox', { name: 'Add title' } )
.fill( 'Dynamic block test' );
await editor.insertBlock( { name: 'core/latest-posts' } );
@@ -70,10 +70,12 @@ test.describe( 'Meta boxes', () => {
editor,
page,
} ) => {
- await page
+ await editor.canvas
.getByRole( 'textbox', { name: 'Add title' } )
.fill( 'A published post' );
- await page.getByRole( 'button', { name: 'Add default block' } ).click();
+ await editor.canvas
+ .getByRole( 'button', { name: 'Add default block' } )
+ .click();
await page.keyboard.type( 'Excerpt from content.' );
const postId = await editor.publishPost();
@@ -89,9 +91,11 @@ test.describe( 'Meta boxes', () => {
page,
} ) => {
await editor.openDocumentSettingsSidebar();
- await page.getByRole( 'button', { name: 'Add default block' } ).click();
+ await editor.canvas
+ .getByRole( 'button', { name: 'Add default block' } )
+ .click();
await page.keyboard.type( 'Excerpt from content.' );
- await page
+ await editor.canvas
.getByRole( 'textbox', { name: 'Add title' } )
.fill( 'A published post' );
diff --git a/test/e2e/specs/editor/plugins/wp-editor-meta-box.spec.js b/test/e2e/specs/editor/plugins/wp-editor-meta-box.spec.js
index 710e06b35e124..c5eafdafe918d 100644
--- a/test/e2e/specs/editor/plugins/wp-editor-meta-box.spec.js
+++ b/test/e2e/specs/editor/plugins/wp-editor-meta-box.spec.js
@@ -20,7 +20,7 @@ test.describe( 'WP Editor Meta Boxes', () => {
await admin.createNewPost();
// Add title to enable valid non-empty post save.
- await page
+ await editor.canvas
.locator( 'role=textbox[name="Add title"i]' )
.type( 'Hello Meta' );
diff --git a/test/e2e/specs/editor/various/publish-button.spec.js b/test/e2e/specs/editor/various/publish-button.spec.js
index 631ddcd0fe61b..cdc9c1a993636 100644
--- a/test/e2e/specs/editor/various/publish-button.spec.js
+++ b/test/e2e/specs/editor/various/publish-button.spec.js
@@ -70,13 +70,12 @@ test.describe( 'Post publish button', () => {
admin,
page,
requestUtils,
+ editor,
} ) => {
await requestUtils.activatePlugin( 'gutenberg-test-plugin-meta-box' );
await admin.createNewPost();
- await page
- .getByRole( 'textbox', {
- name: 'Add title',
- } )
+ await editor.canvas
+ .getByRole( 'textbox', { name: 'Add title' } )
.fill( 'Test post' );
const topBar = page.getByRole( 'region', { name: 'Editor top bar' } );