diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md
index bb4dc1725bc3f..ecd6db1713a6a 100644
--- a/packages/block-editor/README.md
+++ b/packages/block-editor/README.md
@@ -173,6 +173,10 @@ _Related_
Undocumented declaration.
+### BlockLockToolbar
+
+Undocumented declaration.
+
### BlockMover
_Related_
diff --git a/packages/block-editor/src/components/block-preview/README.md b/packages/block-editor/src/components/block-preview/README.md
index 6df2cb6773878..f04053b1e5df6 100644
--- a/packages/block-editor/src/components/block-preview/README.md
+++ b/packages/block-editor/src/components/block-preview/README.md
@@ -35,16 +35,9 @@ Width of the preview container in pixels. Controls at what size the blocks will
Padding for the preview container body.
-### `__experimentalLive`
+### `__experimentalScale`
- **Type** `Boolean`
-- **Default:** `false`
+- **Default:** `true`
-Enables displaying previews without an iframe container.
-
-### `__experimentalOnClick`
-
-- **Type** `Function`
-- **Default:** `undefined`
-
-Use this callback in combination with `__experimentalLive`. The callback is attached to the preview container element.
+Enables displaying previews without an iframe container.
\ No newline at end of file
diff --git a/packages/block-editor/src/components/block-preview/auto.js b/packages/block-editor/src/components/block-preview/auto.js
index d2eca43010a7c..c004bb9f8d4c9 100644
--- a/packages/block-editor/src/components/block-preview/auto.js
+++ b/packages/block-editor/src/components/block-preview/auto.js
@@ -23,6 +23,7 @@ function AutoBlockPreview( {
viewportWidth,
__experimentalPadding,
__experimentalMinHeight,
+ __experimentalScale = true,
} ) {
const [
containerResizeListener,
@@ -58,7 +59,10 @@ function AutoBlockPreview( {
// Initialize on render instead of module top level, to avoid circular dependency issues.
MemoizedBlockList = MemoizedBlockList || pure( BlockList );
- const scale = containerWidth / viewportWidth;
+ const scale =
+ __experimentalScale === true
+ ? containerWidth / viewportWidth
+ : __experimentalScale;
return (
@@ -97,7 +101,10 @@ function AutoBlockPreview( {
tabIndex={ -1 }
style={ {
position: 'absolute',
- width: viewportWidth,
+ width:
+ __experimentalScale === true
+ ? viewportWidth
+ : 'calc( 100% / ' + __experimentalScale + ' )',
height: contentHeight,
pointerEvents: 'none',
// This is a catch-all max-height for patterns.
diff --git a/packages/block-editor/src/components/block-preview/index.js b/packages/block-editor/src/components/block-preview/index.js
index d27f6235a658c..37b4fd4ef280b 100644
--- a/packages/block-editor/src/components/block-preview/index.js
+++ b/packages/block-editor/src/components/block-preview/index.js
@@ -18,7 +18,6 @@ import { memo, useMemo } from '@wordpress/element';
* Internal dependencies
*/
import BlockEditorProvider from '../provider';
-import LiveBlockPreview from './live';
import AutoHeightBlockPreview from './auto';
import { store as blockEditorStore } from '../../store';
import { BlockListItems } from '../block-list';
@@ -27,8 +26,7 @@ export function BlockPreview( {
blocks,
__experimentalPadding = 0,
viewportWidth = 1200,
- __experimentalLive = false,
- __experimentalOnClick,
+ __experimentalScale = true,
__experimentalMinHeight,
} ) {
const originalSettings = useSelect(
@@ -46,15 +44,12 @@ export function BlockPreview( {
}
return (
- { __experimentalLive ? (
-
- ) : (
-
- ) }
+
);
}
diff --git a/packages/block-editor/src/components/block-preview/live.js b/packages/block-editor/src/components/block-preview/live.js
deleted file mode 100644
index 792740bb2c02b..0000000000000
--- a/packages/block-editor/src/components/block-preview/live.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { Disabled } from '@wordpress/components';
-
-/**
- * Internal dependencies
- */
-import BlockList from '../block-list';
-
-export default function LiveBlockPreview( { onClick } ) {
- return (
-
-
-
-
-
- );
-}
diff --git a/packages/block-editor/src/components/block-tools/style.scss b/packages/block-editor/src/components/block-tools/style.scss
index 32abd4aafb2c5..c4643421514b6 100644
--- a/packages/block-editor/src/components/block-tools/style.scss
+++ b/packages/block-editor/src/components/block-tools/style.scss
@@ -52,7 +52,8 @@
.block-editor-block-list__empty-block-inserter,
.block-editor-default-block-appender,
.block-editor-block-list__insertion-point-inserter,
-.block-editor-block-list__block-popover-inserter {
+.block-editor-block-list__block-popover-inserter,
+.edit-site-block-list-exploded__inserter {
.block-editor-inserter__toggle.components-button.has-icon {
// Basic look
background: $gray-900;
@@ -70,11 +71,13 @@
}
}
}
-
-.block-editor-block-list__insertion-point-inserter .block-editor-inserter__toggle.components-button.has-icon {
- background: var(--wp-admin-theme-color);
- &:hover {
- background: $gray-900;
+.edit-site-block-list-exploded__inserter,
+.block-editor-block-list__insertion-point-inserter {
+ .block-editor-inserter__toggle.components-button.has-icon {
+ background: var(--wp-admin-theme-color);
+ &:hover {
+ background: $gray-900;
+ }
}
}
diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js
index 8e6395f5b5d70..034874145ae08 100644
--- a/packages/block-editor/src/components/index.js
+++ b/packages/block-editor/src/components/index.js
@@ -108,6 +108,7 @@ export { default as BlockInspector } from './block-inspector';
export { default as BlockList } from './block-list';
export { useBlockProps } from './block-list/use-block-props';
export { LayoutStyle as __experimentalLayoutStyle } from './block-list/layout';
+export { default as BlockLockToolbar } from './block-lock/toolbar';
export { default as BlockMover } from './block-mover';
export {
default as BlockPreview,
diff --git a/packages/block-editor/src/components/inserter/quick-inserter.js b/packages/block-editor/src/components/inserter/quick-inserter.js
index e3973cba6ac1c..bef05b2ae924e 100644
--- a/packages/block-editor/src/components/inserter/quick-inserter.js
+++ b/packages/block-editor/src/components/inserter/quick-inserter.js
@@ -65,9 +65,7 @@ export default function QuickInserter( {
setInserterIsOpened: settings.__experimentalSetIsInserterOpened,
prioritizePatterns:
settings.__experimentalPreferPatternsOnRoot &&
- ! rootClientId &&
- index > 0 &&
- ( index < blockCount || blockCount === 0 ),
+ ! rootClientId,
insertionIndex: index === -1 ? blockCount : index,
};
},
diff --git a/packages/edit-site/src/components/block-editor/index.js b/packages/edit-site/src/components/block-editor/index.js
index d90747db4ad10..8146b4b71ef88 100644
--- a/packages/edit-site/src/components/block-editor/index.js
+++ b/packages/edit-site/src/components/block-editor/index.js
@@ -40,6 +40,7 @@ import BlockInspectorButton from './block-inspector-button';
import EditTemplatePartMenuButton from '../edit-template-part-menu-button';
import BackButton from './back-button';
import ResizableEditor from './resizable-editor';
+import BlockListExploded from '../block-list-exploded';
const LAYOUT = {
type: 'default',
@@ -48,7 +49,7 @@ const LAYOUT = {
};
export default function BlockEditor( { setIsInserterOpen } ) {
- const { settings } = useSelect(
+ const { settings, editorMode } = useSelect(
( select ) => {
let storedSettings = select( editSiteStore ).getSettings(
setIsInserterOpen
@@ -74,6 +75,7 @@ export default function BlockEditor( { setIsInserterOpen } ) {
return {
settings: storedSettings,
+ editorMode: select( editSiteStore ).getEditorMode(),
};
},
[ setIsInserterOpen ]
@@ -158,52 +160,58 @@ export default function BlockEditor( { setIsInserterOpen } ) {
-
{
- // Clear selected block when clicking on the gray background.
- if ( event.target === event.currentTarget ) {
- clearSelectedBlock();
- }
- } }
- >
-
-
- }
+
+ { editorMode === 'visual' && (
+ {
+ // Clear selected block when clicking on the gray background.
+ if ( event.target === event.currentTarget ) {
+ clearSelectedBlock();
+ }
+ } }
>
-
-
- <__unstableBlockSettingsMenuFirstItem>
- { ( { onClose } ) => (
-
- ) }
-
- <__unstableBlockToolbarLastItem>
- <__unstableBlockNameContext.Consumer>
- { ( blockName ) =>
- blockName === 'core/navigation' && (
-
- )
+
+
+
-
-
+ settings={ settings }
+ contentRef={ mergedRefs }
+ >
+
+
+ <__unstableBlockSettingsMenuFirstItem>
+ { ( { onClose } ) => (
+
+ ) }
+
+ <__unstableBlockToolbarLastItem>
+ <__unstableBlockNameContext.Consumer>
+ { ( blockName ) =>
+ blockName === 'core/navigation' && (
+
+ )
+ }
+
+
+
+ ) }
);
diff --git a/packages/edit-site/src/components/block-list-exploded/README.md b/packages/edit-site/src/components/block-list-exploded/README.md
new file mode 100644
index 0000000000000..8ec4ddda30e90
--- /dev/null
+++ b/packages/edit-site/src/components/block-list-exploded/README.md
@@ -0,0 +1,4 @@
+## BlockListExploded Component
+
+This is an experimental component being built to implement the exploded view in the site editor.
+The potential goal for this component is to be a component that can be used by any block editor, so it's important to keep its dependencies minimal. (block-editor dependencies). Eventually, it should be moved to the `@wordpress/block-editor` package.
\ No newline at end of file
diff --git a/packages/edit-site/src/components/block-list-exploded/index.js b/packages/edit-site/src/components/block-list-exploded/index.js
new file mode 100644
index 0000000000000..444ef0e17cd1b
--- /dev/null
+++ b/packages/edit-site/src/components/block-list-exploded/index.js
@@ -0,0 +1,37 @@
+/**
+ * WordPress dependencies
+ */
+import { store as blockEditorStore, Inserter } from '@wordpress/block-editor';
+import { useSelect } from '@wordpress/data';
+import { pure } from '@wordpress/compose';
+
+/**
+ * Internal dependencies
+ */
+import BlockListExplodedItem from './item';
+
+const InserterBeforeBlock = pure( ( { clientId } ) => (
+
+
+
+) );
+
+function BlockListExploded() {
+ const blockOrder = useSelect( ( select ) => {
+ return select( blockEditorStore ).getBlockOrder();
+ }, [] );
+
+ return (
+
+ { blockOrder.map( ( clientId ) => (
+
+
+
+
+ ) ) }
+
+
+ );
+}
+
+export default BlockListExploded;
diff --git a/packages/edit-site/src/components/block-list-exploded/item.js b/packages/edit-site/src/components/block-list-exploded/item.js
new file mode 100644
index 0000000000000..d7278da38171d
--- /dev/null
+++ b/packages/edit-site/src/components/block-list-exploded/item.js
@@ -0,0 +1,89 @@
+/**
+ * External dependencies
+ */
+import classnames from 'classnames';
+
+/**
+ * WordPress dependencies
+ */
+import {
+ store as blockEditorStore,
+ BlockPreview,
+ useBlockDisplayInformation,
+} from '@wordpress/block-editor';
+import { useSelect, useDispatch } from '@wordpress/data';
+import { pure } from '@wordpress/compose';
+import { sprintf, __ } from '@wordpress/i18n';
+import { useMemo, useRef, useEffect } from '@wordpress/element';
+
+/**
+ * Internal dependencies
+ */
+import BlockListExplodedTopToolbar from './top-toolbar';
+import { store as editSiteStore } from '../../store';
+
+function BlockListExplodedItem( { clientId } ) {
+ const blockWrapper = useRef();
+ const { block, isSelected } = useSelect(
+ ( select ) => {
+ const { getBlock, isBlockSelected } = select( blockEditorStore );
+ return {
+ block: getBlock( clientId ),
+ isSelected: isBlockSelected( clientId ),
+ };
+ },
+ [ clientId ]
+ );
+ const { title } = useBlockDisplayInformation( clientId );
+ const { selectBlock } = useDispatch( blockEditorStore );
+ // If the exploded list becomes part of block-editor
+ // This mode also need to move into the block-editor store.
+ const { switchEditorMode } = useDispatch( editSiteStore );
+
+ // translators: %s: Type of block (i.e. Text, Image etc)
+ const blockLabel = sprintf( __( 'Block: %s' ), title );
+ const blocksToPreview = useMemo( () => [ block ], [ block ] );
+
+ useEffect( () => {
+ if ( isSelected ) {
+ blockWrapper.current.focus();
+ }
+ }, [ isSelected ] );
+
+ return (
+
+ { isSelected && (
+
+ ) }
+
{
+ const isFirstClick = event.detail === 1;
+ const isDoubleClick = event.detail === 2;
+ if ( isFirstClick ) {
+ selectBlock( clientId );
+ } else if ( isDoubleClick ) {
+ switchEditorMode( 'visual' );
+ }
+ } }
+ onKeyPress={ () => selectBlock( clientId ) }
+ onFocus={ () => selectBlock( clientId ) }
+ aria-label={ blockLabel }
+ tabIndex={ 0 }
+ >
+
+
+
+ );
+}
+
+export default pure( BlockListExplodedItem );
diff --git a/packages/edit-site/src/components/block-list-exploded/style.scss b/packages/edit-site/src/components/block-list-exploded/style.scss
new file mode 100644
index 0000000000000..9f604c763b163
--- /dev/null
+++ b/packages/edit-site/src/components/block-list-exploded/style.scss
@@ -0,0 +1,66 @@
+.edit-site-block-list-exploded {
+ display: flex;
+ flex-direction: column;
+ width: min(#{$content-width}, calc(100% - #{$grid-unit-40}));
+ margin: auto;
+}
+
+.edit-site-block-list-exploded__inserter > div {
+ display: flex;
+ margin: 30px auto;
+ width: fit-content;
+}
+
+.edit-site-block-list-exploded__item-container {
+ position: relative;
+
+ &::after {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ pointer-events: none;
+ }
+
+ &:hover::after {
+ border: 1px solid var(--wp-admin-theme-color);
+ }
+
+ &.is-selected::after {
+ border: 2px solid var(--wp-admin-theme-color);
+ }
+}
+
+.edit-site-block-list-exploded__item-top-toolbar {
+ position: absolute;
+ top: -$block-toolbar-height - $grid-unit-15;
+ height: $block-toolbar-height;
+ background: var(--wp-admin-theme-color);
+ color: $white;
+ display: flex;
+ align-items: center;
+ gap: $grid-unit-20;
+ padding-left: $grid-unit-20;
+ border-radius: $radius-block-ui;
+
+ .block-editor-block-lock-toolbar,
+ .block-editor-block-mover__move-button-container {
+ background: transparent;
+ color: inherit;
+ border: none;
+
+ .components-button {
+ color: $white;
+ }
+ }
+
+ // TODO: Absorb these in the BlockMover component (outside of mobile).
+ .block-editor-block-mover-button.is-down-button svg {
+ bottom: 5px;
+ }
+ .block-editor-block-mover-button.is-up-button svg {
+ top: 5px;
+ }
+}
diff --git a/packages/edit-site/src/components/block-list-exploded/top-toolbar.js b/packages/edit-site/src/components/block-list-exploded/top-toolbar.js
new file mode 100644
index 0000000000000..cd2ffe42d22d9
--- /dev/null
+++ b/packages/edit-site/src/components/block-list-exploded/top-toolbar.js
@@ -0,0 +1,27 @@
+/**
+ * WordPress dependencies
+ */
+import {
+ BlockTitle,
+ BlockMover,
+ BlockLockToolbar,
+ BlockIcon,
+ useBlockDisplayInformation,
+} from '@wordpress/block-editor';
+
+function BlockListExplodedTopToolbar( { clientId } ) {
+ const { icon } = useBlockDisplayInformation( clientId );
+
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+export default BlockListExplodedTopToolbar;
diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js
index 5564cf454a4c7..7f032185a3ce9 100644
--- a/packages/edit-site/src/components/editor/index.js
+++ b/packages/edit-site/src/components/editor/index.js
@@ -241,7 +241,10 @@ function Editor( { onError } ) {
<>
- { editorMode === 'visual' &&
+ { ( editorMode ===
+ 'visual' ||
+ editorMode ===
+ 'exploded' ) &&
template && (
{
const {
__experimentalGetPreviewDeviceType,
@@ -61,6 +63,7 @@ export default function Header( {
editorStore
);
const { getShortcutRepresentation } = select( keyboardShortcutsStore );
+ const { getBlockCount } = select( blockEditorStore );
const postType = getEditedPostType();
const postId = getEditedPostId();
@@ -78,7 +81,8 @@ export default function Header( {
listViewShortcut: getShortcutRepresentation(
'core/edit-site/toggle-list-view'
),
- isVisualMode: getEditorMode() === 'visual',
+ mode: getEditorMode(),
+ hasMoreThanOneBlock: getBlockCount() > 1,
};
}, [] );
@@ -86,6 +90,7 @@ export default function Header( {
__experimentalSetPreviewDeviceType: setPreviewDeviceType,
setIsInserterOpened,
setIsListViewOpened,
+ switchEditorMode,
} = useDispatch( editSiteStore );
const isLargeViewport = useViewportMatch( 'medium' );
@@ -105,6 +110,8 @@ export default function Header( {
);
const isFocusMode = templateType === 'wp_template_part';
+ const shouldEnableExplodedViewButton =
+ mode === 'exploded' || ( hasMoreThanOneBlock && mode === 'visual' );
return (
@@ -115,7 +122,7 @@ export default function Header( {
variant="primary"
isPressed={ isInserterOpen }
className="edit-site-header-toolbar__inserter-toggle"
- disabled={ ! isVisualMode }
+ disabled={ mode !== 'visual' }
onMouseDown={ preventDefault }
onClick={ openInserter }
icon={ plus }
@@ -131,13 +138,13 @@ export default function Header( {
<>
+
diff --git a/packages/edit-site/src/store/actions.js b/packages/edit-site/src/store/actions.js
index 1185865861c5f..5535f13dcd4b5 100644
--- a/packages/edit-site/src/store/actions.js
+++ b/packages/edit-site/src/store/actions.js
@@ -468,7 +468,7 @@ export const switchEditorMode = ( mode ) => ( { registry } ) => {
if ( mode === 'visual' ) {
speak( __( 'Visual editor selected' ), 'assertive' );
- } else if ( mode === 'mosaic' ) {
- speak( __( 'Mosaic view selected' ), 'assertive' );
+ } else if ( mode === 'exploded' ) {
+ speak( __( 'Exploded view selected' ), 'assertive' );
}
};
diff --git a/packages/edit-site/src/style.scss b/packages/edit-site/src/style.scss
index b61d06574c7aa..ac1daf0924901 100644
--- a/packages/edit-site/src/style.scss
+++ b/packages/edit-site/src/style.scss
@@ -1,6 +1,7 @@
@import "../../interface/src/style.scss";
@import "./components/block-editor/style.scss";
+@import "./components/block-list-exploded/style.scss";
@import "./components/code-editor/style.scss";
@import "./components/global-styles/style.scss";
@import "./components/header/style.scss";