Skip to content

Commit

Permalink
Add useDisabled hook, pass layout with alignments, use BlockListItems
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewserong committed Oct 29, 2021
1 parent 9d57526 commit 8b4c0d8
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export function BlockPreview( {
<LiveBlockPreview
__experimentalAsButton={ __experimentalAsButton }
onClick={ __experimentalOnClick }
themeSupportsLayout={ !! settings?.supportsLayout }
/>
) : (
<AutoHeightBlockPreview
Expand Down
31 changes: 25 additions & 6 deletions packages/block-editor/src/components/block-preview/live.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,36 @@ import { Disabled } from '@wordpress/components';
/**
* Internal dependencies
*/
import BlockList from '../block-list';
import { BlockListItems } 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,
} ) {
const blockList = (
<Disabled className="block-editor-block-preview__live-content">
<BlockList />
</Disabled>
);
let blockList;

if ( __experimentalAsButton ) {
blockList = (
<Disabled className="block-editor-block-preview__live-content">
<BlockListItems />
</Disabled>
);
} else {
const props = {};
if ( themeSupportsLayout ) {
props.__experimentalLayout = layout;
}
blockList = <BlockListItems { ...props } />;
}

return __experimentalAsButton ? (
<div
Expand Down
4 changes: 4 additions & 0 deletions packages/block-editor/src/components/block-preview/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
}

.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;
Expand Down
20 changes: 17 additions & 3 deletions packages/block-library/src/post-content/edit.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
Expand All @@ -14,12 +19,14 @@ 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 } ) {
const [ , , content ] = useEntityProp(
Expand All @@ -28,7 +35,15 @@ function ReadOnlyContent( { userCanEdit, postType, postId } ) {
'content',
postId
);
const blockProps = useBlockProps( { className: 'is-readonly' } );
const { ref, ...blockProps } = useBlockProps( {
className: classnames(
'components-disabled',
'block-editor-block-preview__live-content'
),
} );
const node = useDisabled();

const mergedRefs = useMergeRefs( [ ref, node ] );

const rawContent = content?.raw;
const blocks = useMemo( () => {
Expand All @@ -40,12 +55,11 @@ function ReadOnlyContent( { userCanEdit, postType, postId } ) {
<Warning>{ __( 'This content is password protected.' ) }</Warning>
</div>
) : (
<div { ...blockProps }>
<div { ...blockProps } ref={ mergedRefs }>
<BlockPreview
blocks={ blocks }
__experimentalAsButton={ false }
__experimentalLive={ true }
__experimentalIsDisabled={ false }
/>
</div>
);
Expand Down
92 changes: 92 additions & 0 deletions packages/block-library/src/post-content/use-disabled.js
Original file line number Diff line number Diff line change
@@ -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<HTMLDivElement>} */
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;
}

0 comments on commit 8b4c0d8

Please sign in to comment.