diff --git a/docs/reference-guides/data/data-core-block-editor.md b/docs/reference-guides/data/data-core-block-editor.md
index e0e9695a0036a..f38cc49a87c0a 100644
--- a/docs/reference-guides/data/data-core-block-editor.md
+++ b/docs/reference-guides/data/data-core-block-editor.md
@@ -1492,7 +1492,7 @@ Action that enables or disables the navigation mode.
_Parameters_
-- _isNavigationMode_ `string`: Enable/Disable navigation mode.
+- _isNavigationMode_ `boolean`: Enable/Disable navigation mode.
### setTemplateValidity
diff --git a/packages/block-editor/src/components/block-list-appender/index.js b/packages/block-editor/src/components/block-list-appender/index.js
index d6cc56d5e2cc9..ec5687b6fec9d 100644
--- a/packages/block-editor/src/components/block-list-appender/index.js
+++ b/packages/block-editor/src/components/block-list-appender/index.js
@@ -6,7 +6,7 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
-import { withSelect } from '@wordpress/data';
+import { useSelect } from '@wordpress/data';
import { getDefaultBlockName } from '@wordpress/blocks';
/**
@@ -18,14 +18,38 @@ import { store as blockEditorStore } from '../../store';
function BlockListAppender( {
rootClientId,
- canInsertDefaultBlock,
- isLocked,
renderAppender: CustomAppender,
className,
- selectedBlockClientId,
tagName: TagName = 'div',
} ) {
- if ( isLocked || CustomAppender === false ) {
+ const {
+ hideInserter,
+ canInsertDefaultBlock,
+ selectedBlockClientId,
+ } = useSelect(
+ ( select ) => {
+ const {
+ canInsertBlockType,
+ getTemplateLock,
+ getSelectedBlockClientId,
+ __unstableGetEditorMode,
+ } = select( blockEditorStore );
+
+ return {
+ hideInserter:
+ !! getTemplateLock( rootClientId ) ||
+ __unstableGetEditorMode() !== 'edit',
+ canInsertDefaultBlock: canInsertBlockType(
+ getDefaultBlockName(),
+ rootClientId
+ ),
+ selectedBlockClientId: getSelectedBlockClientId(),
+ };
+ },
+ [ rootClientId ]
+ );
+
+ if ( hideInserter || CustomAppender === false ) {
return null;
}
@@ -92,19 +116,4 @@ function BlockListAppender( {
);
}
-export default withSelect( ( select, { rootClientId } ) => {
- const {
- canInsertBlockType,
- getTemplateLock,
- getSelectedBlockClientId,
- } = select( blockEditorStore );
-
- return {
- isLocked: !! getTemplateLock( rootClientId ),
- canInsertDefaultBlock: canInsertBlockType(
- getDefaultBlockName(),
- rootClientId
- ),
- selectedBlockClientId: getSelectedBlockClientId(),
- };
-} )( BlockListAppender );
+export default BlockListAppender;
diff --git a/packages/block-editor/src/components/block-list/index.js b/packages/block-editor/src/components/block-list/index.js
index b97bb03c5c142..db91eb7c13d3e 100644
--- a/packages/block-editor/src/components/block-list/index.js
+++ b/packages/block-editor/src/components/block-list/index.js
@@ -34,16 +34,16 @@ export const IntersectionObserver = createContext();
function Root( { className, ...settings } ) {
const [ element, setElement ] = useState();
const isLargeViewport = useViewportMatch( 'medium' );
- const { isOutlineMode, isFocusMode, isNavigationMode } = useSelect(
+ const { isOutlineMode, isFocusMode, editorMode } = useSelect(
( select ) => {
- const { getSettings, isNavigationMode: _isNavigationMode } = select(
+ const { getSettings, __unstableGetEditorMode } = select(
blockEditorStore
);
const { outlineMode, focusMode } = getSettings();
return {
isOutlineMode: outlineMode,
isFocusMode: focusMode,
- isNavigationMode: _isNavigationMode(),
+ editorMode: __unstableGetEditorMode(),
};
},
[]
@@ -75,7 +75,8 @@ function Root( { className, ...settings } ) {
className: classnames( 'is-root-container', className, {
'is-outline-mode': isOutlineMode,
'is-focus-mode': isFocusMode && isLargeViewport,
- 'is-navigate-mode': isNavigationMode,
+ 'is-navigate-mode': editorMode === 'navigation',
+ 'is-exploded-mode': editorMode === 'exploded',
} ),
},
settings
diff --git a/packages/block-editor/src/components/block-list/style.scss b/packages/block-editor/src/components/block-list/style.scss
index da02c6fd4b801..b6c37cb2cf2b0 100644
--- a/packages/block-editor/src/components/block-list/style.scss
+++ b/packages/block-editor/src/components/block-list/style.scss
@@ -408,3 +408,38 @@
margin-bottom: auto;
}
}
+
+/** Exploded mode styles **/
+.is-root-container.is-exploded-mode > .wp-block {
+ transform-origin: center center;
+ position: relative;
+ overflow: hidden;
+
+ &::after {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: z-index(".block-editor-block-content-overlay__overlay");
+ pointer-events: unset !important;
+ }
+
+ &:hover:not(.is-selected)::after {
+ background: rgba(var(--wp-admin-theme-color--rgb), 0.1);
+ box-shadow: 0 0 0 0 var(--wp-admin-theme-color) inset;
+ }
+
+ &.overlay-active * {
+ pointer-events: none;
+ }
+
+ &.is-selected {
+ box-shadow: $border-width 0 0 0 var(--wp-admin-theme-color) inset;
+ }
+}
+
+.is-root-container.is-exploded-mode > .block-list-appender {
+ display: none;
+}
diff --git a/packages/block-editor/src/components/block-list/use-block-props/index.js b/packages/block-editor/src/components/block-list/use-block-props/index.js
index 17ea149b61da7..a08a2a5386c81 100644
--- a/packages/block-editor/src/components/block-list/use-block-props/index.js
+++ b/packages/block-editor/src/components/block-list/use-block-props/index.js
@@ -74,6 +74,8 @@ export function useBlockProps(
isPartOfSelection,
adjustScrolling,
enableAnimation,
+ isExplodedMode,
+ isRootBlock,
} = useSelect(
( select ) => {
const {
@@ -86,6 +88,8 @@ export function useBlockProps(
isBlockMultiSelected,
isAncestorMultiSelected,
isFirstMultiSelectedBlock,
+ __unstableGetEditorMode,
+ getBlockRootClientId,
} = select( blockEditorStore );
const isSelected = isBlockSelected( clientId );
const isPartOfMultiSelection =
@@ -106,6 +110,8 @@ export function useBlockProps(
enableAnimation:
! isTyping() &&
getGlobalBlockCount() <= BLOCK_ANIMATION_THRESHOLD,
+ isExplodedMode: __unstableGetEditorMode() === 'exploded',
+ isRootBlock: ! getBlockRootClientId( clientId ),
};
},
[ clientId ]
@@ -128,6 +134,7 @@ export function useBlockProps(
adjustScrolling,
enableAnimation,
triggerAnimationOnChange: index,
+ scale: isExplodedMode && isRootBlock ? 0.8 : 1,
} ),
useDisabled( { isDisabled: ! __unstableIsDisabled } ),
] );
diff --git a/packages/block-editor/src/components/block-list/use-block-props/use-focus-first-element.js b/packages/block-editor/src/components/block-list/use-block-props/use-focus-first-element.js
index 8b95f19f3c9ff..d9b6b3831f1a4 100644
--- a/packages/block-editor/src/components/block-list/use-block-props/use-focus-first-element.js
+++ b/packages/block-editor/src/components/block-list/use-block-props/use-focus-first-element.js
@@ -36,7 +36,7 @@ function useInitialPosition( clientId ) {
( select ) => {
const {
getSelectedBlocksInitialCaretPosition,
- isNavigationMode,
+ __unstableGetEditorMode,
isBlockSelected,
} = select( blockEditorStore );
@@ -44,7 +44,7 @@ function useInitialPosition( clientId ) {
return;
}
- if ( isNavigationMode() ) {
+ if ( __unstableGetEditorMode() !== 'edit' ) {
return;
}
diff --git a/packages/block-editor/src/components/block-list/use-block-props/use-is-hovered.js b/packages/block-editor/src/components/block-list/use-block-props/use-is-hovered.js
index 26fc68c21ce2f..608026214b778 100644
--- a/packages/block-editor/src/components/block-list/use-block-props/use-is-hovered.js
+++ b/packages/block-editor/src/components/block-list/use-block-props/use-is-hovered.js
@@ -26,8 +26,14 @@ function listener( event ) {
*/
export function useIsHovered() {
const isEnabled = useSelect( ( select ) => {
- const { isNavigationMode, getSettings } = select( blockEditorStore );
- return isNavigationMode() || getSettings().outlineMode;
+ const { __unstableGetEditorMode, getSettings } = select(
+ blockEditorStore
+ );
+ return (
+ __unstableGetEditorMode() === 'navigation' ||
+ ( getSettings().outlineMode &&
+ __unstableGetEditorMode() === 'exploded' )
+ );
}, [] );
return useRefEffect(
diff --git a/packages/block-editor/src/components/block-popover/inbetween.js b/packages/block-editor/src/components/block-popover/inbetween.js
index a671d7f312c0e..28c178cf5b3c3 100644
--- a/packages/block-editor/src/components/block-popover/inbetween.js
+++ b/packages/block-editor/src/components/block-popover/inbetween.js
@@ -7,7 +7,13 @@ import classnames from 'classnames';
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';
-import { useCallback, useMemo, createContext } from '@wordpress/element';
+import {
+ useCallback,
+ useMemo,
+ createContext,
+ useState,
+ useEffect,
+} from '@wordpress/element';
import { Popover } from '@wordpress/components';
import { isRTL } from '@wordpress/i18n';
@@ -28,6 +34,13 @@ function BlockPopoverInbetween( {
__unstableContentRef,
...props
} ) {
+ // This is a temporary hack to get the inbetween inserter to recompute properly.
+ const [ positionRecompute, forceRecompute ] = useState( {} );
+ useEffect( () => {
+ const intervalHandle = setInterval( forceRecompute, 500 );
+ return () => clearInterval( intervalHandle );
+ }, [] );
+
const { orientation, rootClientId, isVisible } = useSelect(
( select ) => {
const {
@@ -66,9 +79,7 @@ function BlockPopoverInbetween( {
if ( isVertical ) {
return {
- width: previousElement
- ? previousElement.offsetWidth
- : nextElement.offsetWidth,
+ width: previousRect ? previousRect.width : nextRect.width,
height:
nextRect && previousRect
? nextRect.top - previousRect.bottom
@@ -85,11 +96,15 @@ function BlockPopoverInbetween( {
return {
width,
- height: previousElement
- ? previousElement.offsetHeight
- : nextElement.offsetHeight,
+ height: previousRect ? previousRect.height : nextRect.height,
};
- }, [ previousElement, nextElement, isVertical ] );
+ }, [
+ previousElement,
+ nextElement,
+ isVertical,
+ positionRecompute,
+ isVisible,
+ ] );
const getAnchorRect = useCallback( () => {
if ( ( ! previousElement && ! nextElement ) || ! isVisible ) {
@@ -110,8 +125,8 @@ function BlockPopoverInbetween( {
return {
top: previousRect ? previousRect.bottom : nextRect.top,
left: previousRect ? previousRect.right : nextRect.right,
- right: previousRect ? previousRect.left : nextRect.left,
- bottom: nextRect ? nextRect.top : previousRect.bottom,
+ right: previousRect ? previousRect.right : nextRect.right,
+ bottom: previousRect ? previousRect.bottom : nextRect.top,
height: 0,
width: 0,
ownerDocument,
@@ -121,8 +136,8 @@ function BlockPopoverInbetween( {
return {
top: previousRect ? previousRect.bottom : nextRect.top,
left: previousRect ? previousRect.left : nextRect.left,
- right: previousRect ? previousRect.right : nextRect.right,
- bottom: nextRect ? nextRect.top : previousRect.bottom,
+ right: previousRect ? previousRect.left : nextRect.left,
+ bottom: previousRect ? previousRect.bottom : nextRect.top,
height: 0,
width: 0,
ownerDocument,
@@ -133,8 +148,8 @@ function BlockPopoverInbetween( {
return {
top: previousRect ? previousRect.top : nextRect.top,
left: previousRect ? previousRect.left : nextRect.right,
- right: nextRect ? nextRect.right : previousRect.left,
- bottom: previousRect ? previousRect.bottom : nextRect.bottom,
+ right: previousRect ? previousRect.left : nextRect.right,
+ bottom: previousRect ? previousRect.top : nextRect.top,
height: 0,
width: 0,
ownerDocument,
@@ -144,13 +159,13 @@ function BlockPopoverInbetween( {
return {
top: previousRect ? previousRect.top : nextRect.top,
left: previousRect ? previousRect.right : nextRect.left,
- right: nextRect ? nextRect.left : previousRect.right,
- bottom: previousRect ? previousRect.bottom : nextRect.bottom,
+ right: previousRect ? previousRect.right : nextRect.left,
+ bottom: previousRect ? previousRect.left : nextRect.right,
height: 0,
width: 0,
ownerDocument,
};
- }, [ previousElement, nextElement ] );
+ }, [ previousElement, nextElement, positionRecompute, isVisible ] );
const popoverScrollRef = usePopoverScroll( __unstableContentRef );
@@ -183,8 +198,14 @@ function BlockPopoverInbetween( {
props.className
) }
__unstableForcePosition
+ placement="bottom-start"
>
-
{ children }
+
+ { children }
+
);
/* eslint-enable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
diff --git a/packages/block-editor/src/components/block-popover/index.js b/packages/block-editor/src/components/block-popover/index.js
index ce28d8943b010..83f1478371596 100644
--- a/packages/block-editor/src/components/block-popover/index.js
+++ b/packages/block-editor/src/components/block-popover/index.js
@@ -62,6 +62,7 @@ export default function BlockPopover( {
// Observe movement for block animations (especially horizontal).
__unstableObserveElement={ selectedElement }
__unstableForcePosition
+ __unstableShift
{ ...props }
className={ classnames(
'block-editor-block-popover',
diff --git a/packages/block-editor/src/components/block-popover/style.scss b/packages/block-editor/src/components/block-popover/style.scss
index df2218950999e..c93d6d865059d 100644
--- a/packages/block-editor/src/components/block-popover/style.scss
+++ b/packages/block-editor/src/components/block-popover/style.scss
@@ -6,6 +6,9 @@
// like the popover is impacted by the block gap margin.
margin: 0 !important;
+ // Allow clicking through the toolbar holder.
+ pointer-events: none;
+
.components-popover__content {
margin: 0 !important;
min-width: auto;
@@ -16,13 +19,15 @@
box-shadow: none;
overflow-y: visible;
- // Allow clicking through the toolbar holder.
- pointer-events: none;
-
- // Position the block toolbar.
- > * {
+ > div > * {
pointer-events: all;
}
}
}
+.block-editor-block-popover__inbetween-container {
+ pointer-events: none !important;
+ > div > * {
+ pointer-events: all;
+ }
+}
diff --git a/packages/block-editor/src/components/block-tools/block-selection-button.js b/packages/block-editor/src/components/block-tools/block-selection-button.js
index 07ba78151e9de..c139a5eae6f33 100644
--- a/packages/block-editor/src/components/block-tools/block-selection-button.js
+++ b/packages/block-editor/src/components/block-tools/block-selection-button.js
@@ -39,6 +39,7 @@ import { store as blockEditorStore } from '../../store';
import BlockDraggable from '../block-draggable';
import useBlockDisplayInformation from '../use-block-display-information';
import { __unstableUseBlockElement as useBlockElement } from '../block-list/use-block-props/use-block-refs';
+import BlockMover from '../block-mover';
/**
* Block selection button component, displaying the label of the block. If the block
@@ -59,6 +60,7 @@ function BlockSelectionButton( { clientId, rootClientId } ) {
getBlockIndex,
hasBlockMovingClientId,
getBlockListSettings,
+ __unstableGetEditorMode,
} = select( blockEditorStore );
const index = getBlockIndex( clientId );
const { name, attributes } = getBlock( clientId );
@@ -69,11 +71,19 @@ function BlockSelectionButton( { clientId, rootClientId } ) {
attributes,
blockMovingMode,
orientation: getBlockListSettings( rootClientId )?.orientation,
+ editorMode: __unstableGetEditorMode(),
};
},
[ clientId, rootClientId ]
);
- const { index, name, attributes, blockMovingMode, orientation } = selected;
+ const {
+ index,
+ name,
+ attributes,
+ blockMovingMode,
+ orientation,
+ editorMode,
+ } = selected;
const { setNavigationMode, removeBlock } = useDispatch( blockEditorStore );
const ref = useRef();
@@ -226,6 +236,7 @@ function BlockSelectionButton( { clientId, rootClientId } ) {
'block-editor-block-list__block-selection-button',
{
'is-block-moving-mode': !! blockMovingMode,
+ 'is-exploded-mode': editorMode === 'exploded',
}
);
@@ -241,20 +252,25 @@ function BlockSelectionButton( { clientId, rootClientId } ) {
-
- { ( draggableProps ) => (
-
- ) }
-
+ { editorMode === 'exploded' && (
+
+ ) }
+ { editorMode === 'navigation' && (
+
+ { ( draggableProps ) => (
+
+ ) }
+
+ ) }