From 5f45fad27060f890abd9fbbf52aa5d892e88b51b Mon Sep 17 00:00:00 2001
From: Andrew Serong <14988353+andrewserong@users.noreply.github.com>
Date: Fri, 12 Nov 2021 16:29:11 +1100
Subject: [PATCH 01/12] Add useBlockPreview, fix Query Loop wide alignment in
the editor
---
packages/block-editor/README.md | 17 ++++
.../src/components/block-preview/index.js | 61 ++++++++++++
.../src/components/block-preview/style.scss | 23 +++++
packages/block-editor/src/components/index.js | 2 +-
.../block-library/src/post-template/edit.js | 36 ++++++--
.../compose/src/hooks/use-disabled/index.js | 92 +++++++++++++++++++
packages/compose/src/index.js | 1 +
7 files changed, 221 insertions(+), 11 deletions(-)
create mode 100644 packages/compose/src/hooks/use-disabled/index.js
diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md
index 94a227890243b..06acf28404dd2 100644
--- a/packages/block-editor/README.md
+++ b/packages/block-editor/README.md
@@ -664,6 +664,23 @@ _Returns_
Undocumented declaration.
+### useBlockPreview
+
+This hook is used to lightly mark an element as a block preview wrapper
+element. Call this hook and pass the returned props to the element to mark as
+a block preview wrapper, automatically rendering inner blocks as children. If
+you define a ref for the element, it is important to pass the ref to this
+hook, which the hook in turn will pass to the component through the props it
+returns. Optionally, you can also pass any other props through this hook, and
+they will be merged and returned.
+
+_Parameters_
+
+- _options_ `Object`: Preview options.
+- _options.blocks_ `WPBlock[]`: Block objects.
+- _options.props_ `Object`: Optional. Props to pass to the element. Must contain the ref if one is defined.
+- _options.\_\_experimentalLayout_ `Object`: Layout settings to be used in the preview.
+
### useBlockProps
This hook is used to lightly mark an element as a block element. The element
diff --git a/packages/block-editor/src/components/block-preview/index.js b/packages/block-editor/src/components/block-preview/index.js
index cea2e8ee9b62c..e8ea15edf9271 100644
--- a/packages/block-editor/src/components/block-preview/index.js
+++ b/packages/block-editor/src/components/block-preview/index.js
@@ -2,10 +2,15 @@
* External dependencies
*/
import { castArray } from 'lodash';
+import classnames from 'classnames';
/**
* WordPress dependencies
*/
+import {
+ __experimentalUseDisabled as useDisabled,
+ useMergeRefs,
+} from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
import { memo, useMemo } from '@wordpress/element';
@@ -16,6 +21,7 @@ import BlockEditorProvider from '../provider';
import LiveBlockPreview from './live';
import AutoHeightBlockPreview from './auto';
import { store as blockEditorStore } from '../../store';
+import { BlockListItems } from '../block-list';
export function BlockPreview( {
blocks,
@@ -63,3 +69,58 @@ export function BlockPreview( {
* @return {WPComponent} The component to be rendered.
*/
export default memo( BlockPreview );
+
+/**
+ * This hook is used to lightly mark an element as a block preview wrapper
+ * element. Call this hook and pass the returned props to the element to mark as
+ * a block preview wrapper, automatically rendering inner blocks as children. If
+ * you define a ref for the element, it is important to pass the ref to this
+ * hook, which the hook in turn will pass to the component through the props it
+ * returns. Optionally, you can also pass any other props through this hook, and
+ * they will be merged and returned.
+ *
+ * @param {Object} options Preview options.
+ * @param {WPBlock[]} options.blocks Block objects.
+ * @param {Object} options.props Optional. Props to pass to the element. Must contain
+ * the ref if one is defined.
+ * @param {Object} options.__experimentalLayout Layout settings to be used in the preview.
+ *
+ */
+export function useBlockPreview( {
+ blocks,
+ props = {},
+ __experimentalLayout,
+} ) {
+ const originalSettings = useSelect(
+ ( select ) => select( blockEditorStore ).getSettings(),
+ []
+ );
+ const disabledRef = useDisabled();
+ const ref = useMergeRefs( [ props.ref, disabledRef ] );
+ const settings = useMemo( () => {
+ const _settings = { ...originalSettings };
+ _settings.__experimentalBlockPatterns = [];
+ return _settings;
+ }, [ originalSettings ] );
+ const renderedBlocks = useMemo( () => castArray( blocks ), [ blocks ] );
+
+ const children = (
+
+
+
+ );
+
+ return {
+ ...props,
+ ref,
+ className: classnames(
+ props.className,
+ 'block-editor-block-preview__live-content',
+ 'components-disabled'
+ ),
+ children: blocks?.length ? children : null,
+ };
+}
diff --git a/packages/block-editor/src/components/block-preview/style.scss b/packages/block-editor/src/components/block-preview/style.scss
index bbcccc58a7d8a..7c522fec5c38c 100644
--- a/packages/block-editor/src/components/block-preview/style.scss
+++ b/packages/block-editor/src/components/block-preview/style.scss
@@ -41,3 +41,26 @@
.block-editor-block-preview__content-iframe .block-list-appender {
display: none;
}
+
+.block-editor-block-preview__live-content {
+ * {
+ pointer-events: none;
+ }
+
+ // Hide the block appender, as the block is not editable in this context.
+ .block-list-appender {
+ display: none;
+ }
+
+ // Revert button disable styles to ensure that button styles render as they will on the
+ // front end of the site. For example, this ensures that Social Links icons display correctly.
+ .components-button:disabled {
+ opacity: initial;
+ }
+
+ // Hide placeholders.
+ .components-placeholder,
+ .block-editor-block-list__block[data-empty="true"] {
+ display: none;
+ }
+}
diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js
index b1f991ce5c4d5..f7128d2de0698 100644
--- a/packages/block-editor/src/components/index.js
+++ b/packages/block-editor/src/components/index.js
@@ -104,7 +104,7 @@ 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 BlockMover } from './block-mover';
-export { default as BlockPreview } from './block-preview';
+export { default as BlockPreview, useBlockPreview } from './block-preview';
export {
default as BlockSelectionClearer,
useBlockSelectionClearer as __unstableUseBlockSelectionClearer,
diff --git a/packages/block-library/src/post-template/edit.js b/packages/block-library/src/post-template/edit.js
index 75c7046eba142..7a36083b5d77b 100644
--- a/packages/block-library/src/post-template/edit.js
+++ b/packages/block-library/src/post-template/edit.js
@@ -11,7 +11,7 @@ import { useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import {
BlockContextProvider,
- BlockPreview,
+ useBlockPreview,
useBlockProps,
useInnerBlocksProps,
store as blockEditorStore,
@@ -30,6 +30,23 @@ function PostTemplateInnerBlocks() {
return
+ ),
category: 'text',
title: 'test block',
} );
@@ -39,7 +79,7 @@ describe( 'useBlockPreview', () => {
return ;
}
- it( 'will render a block preview with minimal nesting', () => {
+ it( 'will render a block preview with minimal nesting', async () => {
const blocks = [];
blocks.push( createBlock( 'core/test-block' ) );
@@ -57,6 +97,12 @@ describe( 'useBlockPreview', () => {
);
expect( previewedBlockContents ).toBeInTheDocument();
+ // Test elements within block contents are disabled.
+ await waitFor( () => {
+ const button = screen.getByText( 'Button' );
+ expect( button.hasAttribute( 'disabled' ) ).toBe( true );
+ } );
+
// Ensure the block preview class names are merged with the component's class name.
expect( container.firstChild.className ).toBe(
'test-container-classname block-editor-block-preview__live-content components-disabled'
From 34f40c92ba289ba20ecef88cc0cd0b7914ff1e10 Mon Sep 17 00:00:00 2001
From: Andrew Serong <14988353+andrewserong@users.noreply.github.com>
Date: Tue, 16 Nov 2021 14:50:23 +1100
Subject: [PATCH 06/12] Switch queryBy to getBy to ensure check for block is
stricter
---
.../block-editor/src/components/block-preview/test/index.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/block-editor/src/components/block-preview/test/index.js b/packages/block-editor/src/components/block-preview/test/index.js
index 36a3713849b70..9dcd070b83d69 100644
--- a/packages/block-editor/src/components/block-preview/test/index.js
+++ b/packages/block-editor/src/components/block-preview/test/index.js
@@ -91,7 +91,7 @@ describe( 'useBlockPreview', () => {
);
// Test block and block contents are rendered.
- const previewedBlock = screen.queryByLabelText( 'Block: test block' );
+ const previewedBlock = screen.getByLabelText( 'Block: test block' );
const previewedBlockContents = screen.getByText(
'Test block edit view'
);
From e61e43439321dc6638af3d0e4605a13ee12aab05 Mon Sep 17 00:00:00 2001
From: Andrew Serong <14988353+andrewserong@users.noreply.github.com>
Date: Tue, 16 Nov 2021 16:25:09 +1100
Subject: [PATCH 07/12] Remove comment
---
packages/block-library/src/post-template/edit.js | 2 --
1 file changed, 2 deletions(-)
diff --git a/packages/block-library/src/post-template/edit.js b/packages/block-library/src/post-template/edit.js
index 7a36083b5d77b..43be5e7f1de8d 100644
--- a/packages/block-library/src/post-template/edit.js
+++ b/packages/block-library/src/post-template/edit.js
@@ -161,8 +161,6 @@ export default function PostTemplateEdit( {
return
{ __( 'No results found.' ) }
;
}
- // Insert what we need right here.
-
return (
{ blockContexts &&
From 9c31535e192a97dd9f4ea2ffec692a9388e7d30f Mon Sep 17 00:00:00 2001
From: Andrew Serong <14988353+andrewserong@users.noreply.github.com>
Date: Wed, 17 Nov 2021 17:04:26 +1100
Subject: [PATCH 08/12] Export useBlockPreview as __experimentalUseBlockPreview
---
packages/block-editor/README.md | 17 -----------------
packages/block-editor/src/components/index.js | 5 ++++-
.../block-library/src/post-template/edit.js | 2 +-
3 files changed, 5 insertions(+), 19 deletions(-)
diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md
index 06acf28404dd2..94a227890243b 100644
--- a/packages/block-editor/README.md
+++ b/packages/block-editor/README.md
@@ -664,23 +664,6 @@ _Returns_
Undocumented declaration.
-### useBlockPreview
-
-This hook is used to lightly mark an element as a block preview wrapper
-element. Call this hook and pass the returned props to the element to mark as
-a block preview wrapper, automatically rendering inner blocks as children. If
-you define a ref for the element, it is important to pass the ref to this
-hook, which the hook in turn will pass to the component through the props it
-returns. Optionally, you can also pass any other props through this hook, and
-they will be merged and returned.
-
-_Parameters_
-
-- _options_ `Object`: Preview options.
-- _options.blocks_ `WPBlock[]`: Block objects.
-- _options.props_ `Object`: Optional. Props to pass to the element. Must contain the ref if one is defined.
-- _options.\_\_experimentalLayout_ `Object`: Layout settings to be used in the preview.
-
### useBlockProps
This hook is used to lightly mark an element as a block element. The element
diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js
index f7128d2de0698..d349dea1725ea 100644
--- a/packages/block-editor/src/components/index.js
+++ b/packages/block-editor/src/components/index.js
@@ -104,7 +104,10 @@ 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 BlockMover } from './block-mover';
-export { default as BlockPreview, useBlockPreview } from './block-preview';
+export {
+ default as BlockPreview,
+ useBlockPreview as __experimentalUseBlockPreview,
+} from './block-preview';
export {
default as BlockSelectionClearer,
useBlockSelectionClearer as __unstableUseBlockSelectionClearer,
diff --git a/packages/block-library/src/post-template/edit.js b/packages/block-library/src/post-template/edit.js
index 43be5e7f1de8d..72f5afb4803c6 100644
--- a/packages/block-library/src/post-template/edit.js
+++ b/packages/block-library/src/post-template/edit.js
@@ -11,7 +11,7 @@ import { useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import {
BlockContextProvider,
- useBlockPreview,
+ __experimentalUseBlockPreview as useBlockPreview,
useBlockProps,
useInnerBlocksProps,
store as blockEditorStore,
From 7e47d5a4ae95f5c1a4fc649f9923b71c0051d366 Mon Sep 17 00:00:00 2001
From: Andrew Serong <14988353+andrewserong@users.noreply.github.com>
Date: Fri, 3 Dec 2021 17:19:18 +1100
Subject: [PATCH 09/12] Optimise block preview via memoizing the component, and
always rendering a preview for each block context
---
.../block-library/src/post-template/edit.js | 55 +++++++++++++------
1 file changed, 39 insertions(+), 16 deletions(-)
diff --git a/packages/block-library/src/post-template/edit.js b/packages/block-library/src/post-template/edit.js
index 72f5afb4803c6..59a3e306dd247 100644
--- a/packages/block-library/src/post-template/edit.js
+++ b/packages/block-library/src/post-template/edit.js
@@ -6,7 +6,7 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
-import { useState, useMemo } from '@wordpress/element';
+import { memo, useMemo, useState } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import {
@@ -30,23 +30,39 @@ function PostTemplateInnerBlocks() {
return ;
}
-function PostTemplateBlockPreview( { blocks, onClick } ) {
+function PostTemplateBlockPreview( {
+ blocks,
+ blockContextId,
+ isHidden,
+ setActiveBlockContextId,
+} ) {
const blockPreviewProps = useBlockPreview( {
blocks,
} );
+ const handleOnClick = () => {
+ setActiveBlockContextId( blockContextId );
+ };
+
+ const style = {
+ display: isHidden ? 'none' : undefined,
+ };
+
return (
);
}
+const MemoizedPostTemplateBlockPreview = memo( PostTemplateBlockPreview );
+
export default function PostTemplateEdit( {
clientId,
context: {
@@ -70,7 +86,7 @@ export default function PostTemplateEdit( {
},
} ) {
const [ { page } ] = queryContext;
- const [ activeBlockContext, setActiveBlockContext ] = useState();
+ const [ activeBlockContextId, setActiveBlockContextId ] = useState();
const { posts, blocks } = useSelect(
( select ) => {
@@ -132,7 +148,6 @@ export default function PostTemplateEdit( {
templateSlug,
]
);
-
const blockContexts = useMemo(
() =>
posts?.map( ( post ) => ( {
@@ -161,6 +176,10 @@ export default function PostTemplateEdit( {
return
{ __( 'No results found.' ) }
;
}
+ // To avoid flicker when switching active block contexts, a preview is rendered
+ // for each block context, but the preview for the active block context is hidden.
+ // This ensures that when it is displayed again, the cached rendering of the
+ // block preview is used, instead of having to re-render the preview from scratch.
return (
+This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes.
+
+
+In some circumstances, such as block previews, all focusable DOM elements
+(input fields, links, buttons, etc.) need to be disabled. This hook adds the
+behavior to disable nested DOM elements to the returned ref.
+
+_Usage_
+
+```js
+import { __experimentalUseDisabled as useDisabled } from '@wordpress/compose';
+
+const DisabledExample = () => {
+ const disabledRef = useDisabled();
+ return (
+
+ );
+};
+```
+
+_Returns_
+
+- `import('react').RefCallback`: Element Ref.
+
### useFocusableIframe
Dispatches a bubbling focus event when the iframe receives focus. Use
From ee8881f029940d66ebdead8a0ded7ef57f12fcfb Mon Sep 17 00:00:00 2001
From: Andrew Serong <14988353+andrewserong@users.noreply.github.com>
Date: Tue, 14 Dec 2021 16:46:26 +1100
Subject: [PATCH 12/12] Move documentation to the hook
---
packages/compose/README.md | 30 -------------------
.../compose/src/hooks/use-disabled/index.js | 23 +++++++++++++-
2 files changed, 22 insertions(+), 31 deletions(-)
diff --git a/packages/compose/README.md b/packages/compose/README.md
index 4e75f92e1738b..32c8abb4e3bd0 100644
--- a/packages/compose/README.md
+++ b/packages/compose/README.md
@@ -209,36 +209,6 @@ _Returns_
- `import('lodash').DebouncedFunc`: Debounced function.
-### __experimentalUseDisabled
-
-
-This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes.
-
-
-In some circumstances, such as block previews, all focusable DOM elements
-(input fields, links, buttons, etc.) need to be disabled. This hook adds the
-behavior to disable nested DOM elements to the returned ref.
-
-_Usage_
-
-```js
-import { __experimentalUseDisabled as useDisabled } from '@wordpress/compose';
-
-const DisabledExample = () => {
- const disabledRef = useDisabled();
- return (
-
- );
-};
-```
-
-_Returns_
-
-- `import('react').RefCallback`: Element Ref.
-
### useFocusableIframe
Dispatches a bubbling focus event when the iframe receives focus. Use
diff --git a/packages/compose/src/hooks/use-disabled/index.js b/packages/compose/src/hooks/use-disabled/index.js
index dce96a0a9d8b9..8cb44e39a6798 100644
--- a/packages/compose/src/hooks/use-disabled/index.js
+++ b/packages/compose/src/hooks/use-disabled/index.js
@@ -28,8 +28,29 @@ const DISABLED_ELIGIBLE_NODE_NAMES = [
'TEXTAREA',
];
+/**
+ * In some circumstances, such as block previews, all focusable DOM elements
+ * (input fields, links, buttons, etc.) need to be disabled. This hook adds the
+ * behavior to disable nested DOM elements to the returned ref.
+ *
+ * @return {import('react').RefObject} Element Ref.
+ *
+ * @example
+ * ```js
+ * import { __experimentalUseDisabled as useDisabled } from '@wordpress/compose';
+ * const DisabledExample = () => {
+ * const disabledRef = useDisabled();
+ * return (
+ *