From cd78f319198874ff06f3e96c53c127403dc58c79 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Fri, 22 Oct 2021 17:11:43 +1100 Subject: [PATCH 1/9] Post Content Block: try rendering read only content as blocks to preserve block supports styles --- packages/block-library/src/post-content/edit.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/post-content/edit.js b/packages/block-library/src/post-content/edit.js index 4a0c277a1f5cf..ec76a81264dba 100644 --- a/packages/block-library/src/post-content/edit.js +++ b/packages/block-library/src/post-content/edit.js @@ -2,9 +2,10 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; +import { parse } from '@wordpress/blocks'; import { useSelect } from '@wordpress/data'; -import { RawHTML } from '@wordpress/element'; import { + BlockPreview, useBlockProps, useInnerBlocksProps, useSetting, @@ -27,13 +28,20 @@ function ReadOnlyContent( { userCanEdit, postType, postId } ) { postId ); const blockProps = useBlockProps(); + + let blocks; + + if ( content?.raw ) { + blocks = parse( content.raw ); + } + return content?.protected && ! userCanEdit ? (
{ __( 'This content is password protected.' ) }
) : (
- { content?.rendered } +
); } From 9a680bd8b4c4bdf25c37f759c398de54d313ec60 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Mon, 25 Oct 2021 16:23:48 +1100 Subject: [PATCH 2/9] Prevent post content inner from being tabbable, fix disabled styles, hide placeholders --- .../src/components/block-preview/index.js | 6 +++++- .../src/components/block-preview/live.js | 4 ++-- packages/block-library/src/editor.scss | 1 + .../block-library/src/post-content/edit.js | 19 +++++++++++------- .../src/post-content/editor.scss | 20 +++++++++++++++++++ 5 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 packages/block-library/src/post-content/editor.scss diff --git a/packages/block-editor/src/components/block-preview/index.js b/packages/block-editor/src/components/block-preview/index.js index cea2e8ee9b62c..2abe8636039e6 100644 --- a/packages/block-editor/src/components/block-preview/index.js +++ b/packages/block-editor/src/components/block-preview/index.js @@ -20,6 +20,7 @@ import { store as blockEditorStore } from '../../store'; export function BlockPreview( { blocks, __experimentalPadding = 0, + tabIndex = 0, viewportWidth = 1200, __experimentalLive = false, __experimentalOnClick, @@ -40,7 +41,10 @@ export function BlockPreview( { return ( { __experimentalLive ? ( - + ) : ( { + return rawContent ? parse( rawContent ) : []; + }, [ rawContent ] ); return content?.protected && ! userCanEdit ? (
@@ -41,7 +41,12 @@ function ReadOnlyContent( { userCanEdit, postType, postId } ) {
) : (
- +
); } diff --git a/packages/block-library/src/post-content/editor.scss b/packages/block-library/src/post-content/editor.scss new file mode 100644 index 0000000000000..1b8570f28a1a2 --- /dev/null +++ b/packages/block-library/src/post-content/editor.scss @@ -0,0 +1,20 @@ +.wp-block-post-content { + &.is-readonly { + // Hide the block appender within the block, 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; + } + } +} From 4a296d5489fe0e3a7f4e523319ae3af752870228 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Wed, 27 Oct 2021 14:08:37 +1100 Subject: [PATCH 3/9] Remove tabIndex prop, replace with __experimentalAsButton, move CSS styles to block-preview --- .../src/components/block-preview/index.js | 4 ++-- .../src/components/block-preview/live.js | 21 +++++++++++++------ .../src/components/block-preview/style.scss | 19 +++++++++++++++++ packages/block-library/src/editor.scss | 1 - .../block-library/src/post-content/edit.js | 1 + .../src/post-content/editor.scss | 20 ------------------ 6 files changed, 37 insertions(+), 29 deletions(-) delete mode 100644 packages/block-library/src/post-content/editor.scss diff --git a/packages/block-editor/src/components/block-preview/index.js b/packages/block-editor/src/components/block-preview/index.js index 2abe8636039e6..ad1843da4cece 100644 --- a/packages/block-editor/src/components/block-preview/index.js +++ b/packages/block-editor/src/components/block-preview/index.js @@ -20,8 +20,8 @@ import { store as blockEditorStore } from '../../store'; export function BlockPreview( { blocks, __experimentalPadding = 0, - tabIndex = 0, viewportWidth = 1200, + __experimentalAsButton = true, __experimentalLive = false, __experimentalOnClick, } ) { @@ -42,8 +42,8 @@ export function BlockPreview( { { __experimentalLive ? ( ) : ( + + + ); + + return __experimentalAsButton ? (
- - - + { blockList }
+ ) : ( + <>{ blockList } ); } diff --git a/packages/block-editor/src/components/block-preview/style.scss b/packages/block-editor/src/components/block-preview/style.scss index 71ca31e9bc221..6f6465dd1f387 100644 --- a/packages/block-editor/src/components/block-preview/style.scss +++ b/packages/block-editor/src/components/block-preview/style.scss @@ -36,3 +36,22 @@ } } } + +.block-editor-block-preview__live-content { + // 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-library/src/editor.scss b/packages/block-library/src/editor.scss index 7e01efe66a33f..7aebaf17a09cb 100644 --- a/packages/block-library/src/editor.scss +++ b/packages/block-library/src/editor.scss @@ -22,7 +22,6 @@ @import "./nextpage/editor.scss"; @import "./page-list/editor.scss"; @import "./paragraph/editor.scss"; -@import "./post-content/editor.scss"; @import "./post-excerpt/editor.scss"; @import "./pullquote/editor.scss"; @import "./rss/editor.scss"; diff --git a/packages/block-library/src/post-content/edit.js b/packages/block-library/src/post-content/edit.js index bf7097a2f3d12..2c9212e868407 100644 --- a/packages/block-library/src/post-content/edit.js +++ b/packages/block-library/src/post-content/edit.js @@ -44,6 +44,7 @@ function ReadOnlyContent( { userCanEdit, postType, postId } ) { diff --git a/packages/block-library/src/post-content/editor.scss b/packages/block-library/src/post-content/editor.scss deleted file mode 100644 index 1b8570f28a1a2..0000000000000 --- a/packages/block-library/src/post-content/editor.scss +++ /dev/null @@ -1,20 +0,0 @@ -.wp-block-post-content { - &.is-readonly { - // Hide the block appender within the block, 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; - } - } -} From 6c039894886744c28149a8d2e0ed1ca24646bf33 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Wed, 27 Oct 2021 14:11:05 +1100 Subject: [PATCH 4/9] Remove tabIndex prop from post-content edit --- packages/block-library/src/post-content/edit.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/block-library/src/post-content/edit.js b/packages/block-library/src/post-content/edit.js index 2c9212e868407..d6cd4f4278821 100644 --- a/packages/block-library/src/post-content/edit.js +++ b/packages/block-library/src/post-content/edit.js @@ -43,7 +43,6 @@ function ReadOnlyContent( { userCanEdit, postType, postId } ) {
Date: Fri, 29 Oct 2021 17:35:13 +1100 Subject: [PATCH 5/9] Add useDisabled hook, pass layout with alignments, use BlockListItems --- .../src/components/block-preview/index.js | 1 + .../src/components/block-preview/live.js | 31 +++++-- .../src/components/block-preview/style.scss | 4 + .../block-library/src/post-content/edit.js | 20 +++- .../src/post-content/use-disabled.js | 92 +++++++++++++++++++ 5 files changed, 139 insertions(+), 9 deletions(-) create mode 100644 packages/block-library/src/post-content/use-disabled.js diff --git a/packages/block-editor/src/components/block-preview/index.js b/packages/block-editor/src/components/block-preview/index.js index ad1843da4cece..8fff2adfa1a83 100644 --- a/packages/block-editor/src/components/block-preview/index.js +++ b/packages/block-editor/src/components/block-preview/index.js @@ -44,6 +44,7 @@ export function BlockPreview( { ) : ( - - - ); + let blockList; + + if ( __experimentalAsButton ) { + blockList = ( + + + + ); + } else { + const props = {}; + if ( themeSupportsLayout ) { + props.__experimentalLayout = layout; + } + blockList = ; + } return __experimentalAsButton ? (
{ @@ -40,12 +55,11 @@ function ReadOnlyContent( { userCanEdit, postType, postId } ) { { __( 'This content is password protected.' ) }
) : ( -
+
); diff --git a/packages/block-library/src/post-content/use-disabled.js b/packages/block-library/src/post-content/use-disabled.js new file mode 100644 index 0000000000000..9a017bd797085 --- /dev/null +++ b/packages/block-library/src/post-content/use-disabled.js @@ -0,0 +1,92 @@ +/** + * External dependencies + */ +import { includes, debounce } from 'lodash'; + +/** + * WordPress dependencies + */ +import { useCallback, useLayoutEffect, useRef } from '@wordpress/element'; +import { focus } from '@wordpress/dom'; + +/** + * Names of control nodes which qualify for disabled behavior. + * + * See WHATWG HTML Standard: 4.10.18.5: "Enabling and disabling form controls: the disabled attribute". + * + * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#enabling-and-disabling-form-controls:-the-disabled-attribute + * + * @type {string[]} + */ +const DISABLED_ELIGIBLE_NODE_NAMES = [ + 'BUTTON', + 'FIELDSET', + 'INPUT', + 'OPTGROUP', + 'OPTION', + 'SELECT', + 'TEXTAREA', +]; + +export function useDisabled() { + /** @type {import('react').RefObject} */ + const node = useRef( null ); + + const disable = () => { + if ( ! node.current ) { + return; + } + + focus.focusable.find( node.current ).forEach( ( focusable ) => { + if ( + includes( DISABLED_ELIGIBLE_NODE_NAMES, focusable.nodeName ) + ) { + focusable.setAttribute( 'disabled', '' ); + } + + if ( focusable.nodeName === 'A' ) { + focusable.setAttribute( 'tabindex', '-1' ); + } + + const tabIndex = focusable.getAttribute( 'tabindex' ); + if ( tabIndex !== null && tabIndex !== '-1' ) { + focusable.removeAttribute( 'tabindex' ); + } + + if ( focusable.hasAttribute( 'contenteditable' ) ) { + focusable.setAttribute( 'contenteditable', 'false' ); + } + } ); + }; + + // Debounce re-disable since disabling process itself will incur + // additional mutations which should be ignored. + const debouncedDisable = useCallback( + debounce( disable, undefined, { leading: true } ), + [] + ); + + useLayoutEffect( () => { + disable(); + + /** @type {MutationObserver | undefined} */ + let observer; + if ( node.current ) { + observer = new window.MutationObserver( debouncedDisable ); + observer.observe( node.current, { + childList: true, + attributes: true, + subtree: true, + } ); + } + + return () => { + if ( observer ) { + observer.disconnect(); + } + debouncedDisable.cancel(); + }; + }, [] ); + + return node; +} From b06b3741bf2036bf87fe1903984074a6628a71e4 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Wed, 3 Nov 2021 17:26:44 +1100 Subject: [PATCH 6/9] Refactor block preview behaviour to a useBlockPreview hook for the post content block --- packages/block-editor/README.md | 17 ++++ .../src/components/block-preview/index.js | 67 ++++++++++++-- .../src/components/block-preview/live.js | 40 ++------ packages/block-editor/src/components/index.js | 2 +- .../block-library/src/post-content/edit.js | 42 ++++----- .../compose/src/hooks/use-disabled/index.js | 92 +++++++++++++++++++ packages/compose/src/index.js | 1 + 7 files changed, 195 insertions(+), 66 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 5c8f30a5802ce..63315ada1be69 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -660,6 +660,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_ + +- _props_ `Object`: Optional. Props to pass to the element. Must contain the ref if one is defined. +- _options_ `Object`: Preview options. +- _options.blocks_ `WPBlock[]`: Block objects. +- _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 8fff2adfa1a83..c3002e9045be0 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,12 +21,12 @@ 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, __experimentalPadding = 0, viewportWidth = 1200, - __experimentalAsButton = true, __experimentalLive = false, __experimentalOnClick, } ) { @@ -41,11 +46,7 @@ export function BlockPreview( { return ( { __experimentalLive ? ( - + ) : ( 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/live.js b/packages/block-editor/src/components/block-preview/live.js index 8b946c00b5629..792740bb2c02b 100644 --- a/packages/block-editor/src/components/block-preview/live.js +++ b/packages/block-editor/src/components/block-preview/live.js @@ -6,47 +6,19 @@ import { Disabled } from '@wordpress/components'; /** * Internal dependencies */ -import { BlockListItems } from '../block-list'; +import BlockList from '../block-list'; -const DEFAULT_CONTROLS = [ 'none', 'left', 'center', 'right', 'wide', 'full' ]; -const WIDE_CONTROLS = [ 'wide', 'full' ]; - -const layout = { - type: 'default', - alignments: [ ...DEFAULT_CONTROLS, ...WIDE_CONTROLS ], -}; - -export default function LiveBlockPreview( { - onClick, - __experimentalAsButton = true, - themeSupportsLayout = false, -} ) { - let blockList; - - if ( __experimentalAsButton ) { - blockList = ( - - - - ); - } else { - const props = {}; - if ( themeSupportsLayout ) { - props.__experimentalLayout = layout; - } - blockList = ; - } - - return __experimentalAsButton ? ( +export default function LiveBlockPreview( { onClick } ) { + return (
- { blockList } + + +
- ) : ( - <>{ blockList } ); } diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index dcccb216217e3..a2e4b5c3a02db 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -103,7 +103,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-content/edit.js b/packages/block-library/src/post-content/edit.js index 625d704462bf3..da5ce6f4175d5 100644 --- a/packages/block-library/src/post-content/edit.js +++ b/packages/block-library/src/post-content/edit.js @@ -1,8 +1,3 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; - /** * WordPress dependencies */ @@ -10,7 +5,7 @@ import { __ } from '@wordpress/i18n'; import { parse } from '@wordpress/blocks'; import { useSelect } from '@wordpress/data'; import { - BlockPreview, + useBlockPreview, useBlockProps, useInnerBlocksProps, useSetting, @@ -19,49 +14,45 @@ import { Warning, } from '@wordpress/block-editor'; import { useEntityProp, useEntityBlockEditor } from '@wordpress/core-data'; -import { useMergeRefs } from '@wordpress/compose'; import { useMemo } from '@wordpress/element'; /** * Internal dependencies */ import { useCanEditEntity } from '../utils/hooks'; -import { useDisabled } from './use-disabled'; -function ReadOnlyContent( { userCanEdit, postType, postId } ) { +function ReadOnlyContent( { layout, userCanEdit, postType, postId } ) { const [ , , content ] = useEntityProp( 'postType', postType, 'content', postId ); - const { ref, ...blockProps } = useBlockProps( { - className: classnames( - 'components-disabled', - 'block-editor-block-preview__live-content' - ), - } ); - const node = useDisabled(); + const blockProps = useBlockProps(); - const mergedRefs = useMergeRefs( [ ref, node ] ); + const themeSupportsLayout = useSelect( ( select ) => { + const { getSettings } = select( blockEditorStore ); + return getSettings()?.supportsLayout; + }, [] ); + const defaultLayout = useSetting( 'layout' ) || {}; + const usedLayout = !! layout && layout.inherit ? defaultLayout : layout; const rawContent = content?.raw; const blocks = useMemo( () => { return rawContent ? parse( rawContent ) : []; }, [ rawContent ] ); + const blockPreviewProps = useBlockPreview( blockProps, { + blocks, + __experimentalLayout: themeSupportsLayout ? usedLayout : undefined, + } ); + return content?.protected && ! userCanEdit ? (
{ __( 'This content is password protected.' ) }
) : ( -
- -
+
); } @@ -92,7 +83,7 @@ function EditableContent( { layout, context = {} } ) { } function Content( props ) { - const { context: { queryId, postType, postId } = {} } = props; + const { context: { queryId, postType, postId } = {}, layout } = props; const isDescendentOfQueryLoop = !! queryId; const userCanEdit = useCanEditEntity( 'postType', postType, postId ); const isEditable = userCanEdit && ! isDescendentOfQueryLoop; @@ -101,6 +92,7 @@ function Content( props ) { ) : ( } */ + const node = useRef( null ); + + const disable = () => { + if ( ! node.current ) { + return; + } + + focus.focusable.find( node.current ).forEach( ( focusable ) => { + if ( + includes( DISABLED_ELIGIBLE_NODE_NAMES, focusable.nodeName ) + ) { + focusable.setAttribute( 'disabled', '' ); + } + + if ( focusable.nodeName === 'A' ) { + focusable.setAttribute( 'tabindex', '-1' ); + } + + const tabIndex = focusable.getAttribute( 'tabindex' ); + if ( tabIndex !== null && tabIndex !== '-1' ) { + focusable.removeAttribute( 'tabindex' ); + } + + if ( focusable.hasAttribute( 'contenteditable' ) ) { + focusable.setAttribute( 'contenteditable', 'false' ); + } + } ); + }; + + // Debounce re-disable since disabling process itself will incur + // additional mutations which should be ignored. + const debouncedDisable = useCallback( + debounce( disable, undefined, { leading: true } ), + [] + ); + + useLayoutEffect( () => { + disable(); + + /** @type {MutationObserver | undefined} */ + let observer; + if ( node.current ) { + observer = new window.MutationObserver( debouncedDisable ); + observer.observe( node.current, { + childList: true, + attributes: true, + subtree: true, + } ); + } + + return () => { + if ( observer ) { + observer.disconnect(); + } + debouncedDisable.cancel(); + }; + }, [] ); + + return node; +} diff --git a/packages/compose/src/index.js b/packages/compose/src/index.js index 2ce3a2ab33f6f..2bfc7c7f5f848 100644 --- a/packages/compose/src/index.js +++ b/packages/compose/src/index.js @@ -17,6 +17,7 @@ export { default as useConstrainedTabbing } from './hooks/use-constrained-tabbin export { default as useCopyOnClick } from './hooks/use-copy-on-click'; export { default as useCopyToClipboard } from './hooks/use-copy-to-clipboard'; export { default as __experimentalUseDialog } from './hooks/use-dialog'; +export { default as __experimentalUseDisabled } from './hooks/use-disabled'; export { default as __experimentalUseDragging } from './hooks/use-dragging'; export { default as useFocusOnMount } from './hooks/use-focus-on-mount'; export { default as __experimentalUseFocusOutside } from './hooks/use-focus-outside'; From 2a5a2462eca58fb15e4eeb7049327425c418da09 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Wed, 3 Nov 2021 17:29:03 +1100 Subject: [PATCH 7/9] Remove useDisabled hook from post content now that it has been moved to the compose package --- .../src/post-content/use-disabled.js | 92 ------------------- 1 file changed, 92 deletions(-) delete mode 100644 packages/block-library/src/post-content/use-disabled.js diff --git a/packages/block-library/src/post-content/use-disabled.js b/packages/block-library/src/post-content/use-disabled.js deleted file mode 100644 index 9a017bd797085..0000000000000 --- a/packages/block-library/src/post-content/use-disabled.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * External dependencies - */ -import { includes, debounce } from 'lodash'; - -/** - * WordPress dependencies - */ -import { useCallback, useLayoutEffect, useRef } from '@wordpress/element'; -import { focus } from '@wordpress/dom'; - -/** - * Names of control nodes which qualify for disabled behavior. - * - * See WHATWG HTML Standard: 4.10.18.5: "Enabling and disabling form controls: the disabled attribute". - * - * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#enabling-and-disabling-form-controls:-the-disabled-attribute - * - * @type {string[]} - */ -const DISABLED_ELIGIBLE_NODE_NAMES = [ - 'BUTTON', - 'FIELDSET', - 'INPUT', - 'OPTGROUP', - 'OPTION', - 'SELECT', - 'TEXTAREA', -]; - -export function useDisabled() { - /** @type {import('react').RefObject} */ - const node = useRef( null ); - - const disable = () => { - if ( ! node.current ) { - return; - } - - focus.focusable.find( node.current ).forEach( ( focusable ) => { - if ( - includes( DISABLED_ELIGIBLE_NODE_NAMES, focusable.nodeName ) - ) { - focusable.setAttribute( 'disabled', '' ); - } - - if ( focusable.nodeName === 'A' ) { - focusable.setAttribute( 'tabindex', '-1' ); - } - - const tabIndex = focusable.getAttribute( 'tabindex' ); - if ( tabIndex !== null && tabIndex !== '-1' ) { - focusable.removeAttribute( 'tabindex' ); - } - - if ( focusable.hasAttribute( 'contenteditable' ) ) { - focusable.setAttribute( 'contenteditable', 'false' ); - } - } ); - }; - - // Debounce re-disable since disabling process itself will incur - // additional mutations which should be ignored. - const debouncedDisable = useCallback( - debounce( disable, undefined, { leading: true } ), - [] - ); - - useLayoutEffect( () => { - disable(); - - /** @type {MutationObserver | undefined} */ - let observer; - if ( node.current ) { - observer = new window.MutationObserver( debouncedDisable ); - observer.observe( node.current, { - childList: true, - attributes: true, - subtree: true, - } ); - } - - return () => { - if ( observer ) { - observer.disconnect(); - } - debouncedDisable.cancel(); - }; - }, [] ); - - return node; -} From 284ded1f7e22da7a970332e51ad04601719571d5 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Thu, 4 Nov 2021 17:18:12 +1100 Subject: [PATCH 8/9] Combine props into options param of useBlockPreview --- packages/block-editor/README.md | 2 +- .../src/components/block-preview/index.js | 11 ++++++----- packages/block-library/src/post-content/edit.js | 3 ++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index 63315ada1be69..1736d857763df 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -672,9 +672,9 @@ they will be merged and returned. _Parameters_ -- _props_ `Object`: Optional. Props to pass to the element. Must contain the ref if one is defined. - _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 diff --git a/packages/block-editor/src/components/block-preview/index.js b/packages/block-editor/src/components/block-preview/index.js index c3002e9045be0..e8ea15edf9271 100644 --- a/packages/block-editor/src/components/block-preview/index.js +++ b/packages/block-editor/src/components/block-preview/index.js @@ -79,17 +79,18 @@ export default memo( BlockPreview ); * returns. Optionally, you can also pass any other props through this hook, and * they will be merged and returned. * - * @param {Object} props Optional. Props to pass to the element. Must contain - * the ref if one is defined. * @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( +export function useBlockPreview( { + blocks, props = {}, - { blocks, __experimentalLayout } -) { + __experimentalLayout, +} ) { const originalSettings = useSelect( ( select ) => select( blockEditorStore ).getSettings(), [] diff --git a/packages/block-library/src/post-content/edit.js b/packages/block-library/src/post-content/edit.js index da5ce6f4175d5..573fc17dec5bf 100644 --- a/packages/block-library/src/post-content/edit.js +++ b/packages/block-library/src/post-content/edit.js @@ -42,8 +42,9 @@ function ReadOnlyContent( { layout, userCanEdit, postType, postId } ) { return rawContent ? parse( rawContent ) : []; }, [ rawContent ] ); - const blockPreviewProps = useBlockPreview( blockProps, { + const blockPreviewProps = useBlockPreview( { blocks, + props: blockProps, __experimentalLayout: themeSupportsLayout ? usedLayout : undefined, } ); From 89fba21c75b1337de9aaf2d84bdc6c75a6dbae03 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Thu, 4 Nov 2021 17:35:34 +1100 Subject: [PATCH 9/9] Combine layout logic --- .../block-library/src/post-content/edit.js | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/packages/block-library/src/post-content/edit.js b/packages/block-library/src/post-content/edit.js index 573fc17dec5bf..fa4eb89973979 100644 --- a/packages/block-library/src/post-content/edit.js +++ b/packages/block-library/src/post-content/edit.js @@ -21,7 +21,12 @@ import { useMemo } from '@wordpress/element'; */ import { useCanEditEntity } from '../utils/hooks'; -function ReadOnlyContent( { layout, userCanEdit, postType, postId } ) { +function ReadOnlyContent( { + __experimentalLayout, + postId, + postType, + userCanEdit, +} ) { const [ , , content ] = useEntityProp( 'postType', postType, @@ -30,13 +35,6 @@ function ReadOnlyContent( { layout, userCanEdit, postType, postId } ) { ); const blockProps = useBlockProps(); - const themeSupportsLayout = useSelect( ( select ) => { - const { getSettings } = select( blockEditorStore ); - return getSettings()?.supportsLayout; - }, [] ); - const defaultLayout = useSetting( 'layout' ) || {}; - const usedLayout = !! layout && layout.inherit ? defaultLayout : layout; - const rawContent = content?.raw; const blocks = useMemo( () => { return rawContent ? parse( rawContent ) : []; @@ -45,7 +43,7 @@ function ReadOnlyContent( { layout, userCanEdit, postType, postId } ) { const blockPreviewProps = useBlockPreview( { blocks, props: blockProps, - __experimentalLayout: themeSupportsLayout ? usedLayout : undefined, + __experimentalLayout, } ); return content?.protected && ! userCanEdit ? ( @@ -57,14 +55,8 @@ function ReadOnlyContent( { layout, userCanEdit, postType, postId } ) { ); } -function EditableContent( { layout, context = {} } ) { +function EditableContent( { __experimentalLayout, context = {} } ) { const { postType, postId } = context; - const themeSupportsLayout = useSelect( ( select ) => { - const { getSettings } = select( blockEditorStore ); - return getSettings()?.supportsLayout; - }, [] ); - const defaultLayout = useSetting( 'layout' ) || {}; - const usedLayout = !! layout && layout.inherit ? defaultLayout : layout; const [ blocks, onInput, onChange ] = useEntityBlockEditor( 'postType', postType, @@ -77,7 +69,7 @@ function EditableContent( { layout, context = {} } ) { value: blocks, onInput, onChange, - __experimentalLayout: themeSupportsLayout ? usedLayout : undefined, + __experimentalLayout, } ); return
; @@ -89,11 +81,22 @@ function Content( props ) { const userCanEdit = useCanEditEntity( 'postType', postType, postId ); const isEditable = userCanEdit && ! isDescendentOfQueryLoop; + const themeSupportsLayout = useSelect( ( select ) => { + const { getSettings } = select( blockEditorStore ); + return getSettings()?.supportsLayout; + }, [] ); + const defaultLayout = useSetting( 'layout' ) || {}; + const usedLayout = !! layout && layout.inherit ? defaultLayout : layout; + const __experimentalLayout = themeSupportsLayout ? usedLayout : undefined; + return isEditable ? ( - + ) : (