diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 3980dd7b2aead..01ba9102db24a 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -11,6 +11,7 @@ import { useMemo, useCallback, RawHTML, + useRef, } from '@wordpress/element'; import { getBlockType, @@ -28,8 +29,9 @@ import { withSelect, useDispatch, useSelect, + useRegistry, } from '@wordpress/data'; -import { compose, pure, ifCondition } from '@wordpress/compose'; +import { compose, pure } from '@wordpress/compose'; import { safeHTML } from '@wordpress/dom'; /** @@ -78,7 +80,7 @@ function Block( { children, isHtml, ...props } ) { } function BlockListBlock( { - block: { __unstableBlockSource }, + __unstableBlockSource, mode, isLocked, canRemove, @@ -283,7 +285,7 @@ const applyWithSelect = withSelect( ( select, { clientId, rootClientId } ) => { // This function should never be called when a block is not present in // the state. It happens now because the order in withSelect rendering // is not correct. - const { name, attributes, isValid } = block || {}; + const { name, isValid, __unstableBlockSource } = block || {}; // Do not add new properties here, use `useSelect` instead to avoid // leaking new props to the public API (editor.BlockListBlock filter). @@ -297,10 +299,11 @@ const applyWithSelect = withSelect( ( select, { clientId, rootClientId } ) => { // access the block prop. // Ideally these blocks would rely on the clientId prop only. // This is kept for backward compatibility reasons. - block, + // block, name, - attributes, + // attributes, isValid, + __unstableBlockSource, isSelected, }; } ); @@ -540,9 +543,38 @@ export default compose( pure, applyWithSelect, applyWithDispatch, + ( WrappedComponent ) => ( props ) => { + const subscriptions = useRef( new Set() ); + const registry = useRegistry(); + const attributes = useSelect( + ( select ) => + Object.fromEntries( + Object.entries( + select( blockEditorStore ).getBlockAttributes( + props.clientId + ) + ).filter( ( [ key ] ) => subscriptions.current.has( key ) ) + ), + [ props.clientId ] + ); + + const proxy = new Proxy( attributes, { + get( target, name ) { + if ( target.hasOwnProperty( name ) ) { + return target[ name ]; + } + + subscriptions.current.add( name ); + return registry + .select( blockEditorStore ) + .getBlockAttributes( props.clientId )[ name ]; + }, + } ); + return ; + }, // Block is sometimes not mounted at the right time, causing it be undefined // see issue for more info // https://github.com/WordPress/gutenberg/issues/17013 - ifCondition( ( { block } ) => !! block ), + // ifCondition( ( { block } ) => !! block ), withFilters( 'editor.BlockListBlock' ) )( BlockListBlock ); diff --git a/packages/block-editor/src/hooks/layout.js b/packages/block-editor/src/hooks/layout.js index 836a9cd5a57c6..00c7dba948779 100644 --- a/packages/block-editor/src/hooks/layout.js +++ b/packages/block-editor/src/hooks/layout.js @@ -350,7 +350,7 @@ export const withInspectorControls = createHigherOrderComponent( */ export const withLayoutStyles = createHigherOrderComponent( ( BlockListBlock ) => ( props ) => { - const { name, attributes, block } = props; + const { name, attributes } = props; const hasLayoutBlockSupport = hasBlockSupport( name, layoutBlockSupportKey @@ -372,7 +372,7 @@ export const withLayoutStyles = createHigherOrderComponent( ? { ...layout, type: 'constrained' } : layout || defaultBlockLayout || {}; const layoutClasses = hasLayoutBlockSupport - ? useLayoutClasses( block ) + ? useLayoutClasses( { name, attributes } ) : null; // Higher specificity to override defaults from theme.json. const selector = `.wp-container-${ id }.wp-container-${ id }`; diff --git a/packages/block-library/src/paragraph/edit.js b/packages/block-library/src/paragraph/edit.js index 5cb465dc6da66..50e39d42c1d3b 100644 --- a/packages/block-library/src/paragraph/edit.js +++ b/packages/block-library/src/paragraph/edit.js @@ -19,6 +19,7 @@ import { RichText, useBlockProps, useSetting, + store as blockEditorStore, } from '@wordpress/block-editor'; import { createBlock } from '@wordpress/blocks'; import { formatLtr } from '@wordpress/icons'; @@ -27,6 +28,7 @@ import { formatLtr } from '@wordpress/icons'; * Internal dependencies */ import { useOnEnter } from './use-enter'; +import { useSelect } from '@wordpress/data'; const name = 'core/paragraph'; @@ -49,6 +51,74 @@ function hasDropCapDisabled( align ) { return align === ( isRTL() ? 'left' : 'right' ) || align === 'center'; } +// function useAttributes( name ) { +// return useSelect( +// ( select ) => select( blockEditorStore ).getAttribute( name ), +// [ name ] +// ); +// } + +function BlockContent( { + attributes, + mergeBlocks, + onReplace, + onRemove, + setAttributes, + clientId, + blockProps, +} ) { + const content = useSelect( + ( select ) => + select( blockEditorStore ).getBlockAttributes( clientId ).content, + [ clientId ] + ); + const { placeholder } = attributes; + return ( + + setAttributes( { content: newContent } ) + } + onSplit={ ( value, isOriginal ) => { + let newAttributes; + + if ( isOriginal || value ) { + newAttributes = { + ...attributes, + content: value, + }; + } + + const block = createBlock( name, newAttributes ); + + if ( isOriginal ) { + block.clientId = clientId; + } + + return block; + } } + onMerge={ mergeBlocks } + onReplace={ onReplace } + onRemove={ onRemove } + aria-label={ + content + ? __( 'Paragraph block' ) + : __( + 'Empty block; start writing or type forward slash to choose a block' + ) + } + data-empty={ content ? false : true } + placeholder={ placeholder || __( 'Type / to choose a block' ) } + data-custom-placeholder={ placeholder ? true : undefined } + __unstableEmbedURLOnPaste + __unstableAllowPrefixTransformations + /> + ); +} + function ParagraphBlock( { attributes, mergeBlocks, @@ -57,16 +127,8 @@ function ParagraphBlock( { setAttributes, clientId, } ) { - const { align, content, direction, dropCap, placeholder } = attributes; + const { align, direction, dropCap } = attributes; const isDropCapFeatureEnabled = useSetting( 'typography.dropCap' ); - const blockProps = useBlockProps( { - ref: useOnEnter( { clientId, content } ), - className: classnames( { - 'has-drop-cap': hasDropCapDisabled( align ) ? false : dropCap, - [ `has-text-align-${ align }` ]: align, - } ), - style: { direction }, - } ); let helpText; if ( hasDropCapDisabled( align ) ) { @@ -77,6 +139,15 @@ function ParagraphBlock( { helpText = __( 'Toggle to show a large initial letter.' ); } + const blockProps = useBlockProps( { + ref: useOnEnter( { clientId } ), + className: classnames( { + 'has-drop-cap': hasDropCapDisabled( align ) ? false : dropCap, + [ `has-text-align-${ align }` ]: align, + } ), + style: { direction }, + } ); + return ( <> @@ -123,47 +194,14 @@ function ParagraphBlock( { ) } - - setAttributes( { content: newContent } ) - } - onSplit={ ( value, isOriginal ) => { - let newAttributes; - - if ( isOriginal || value ) { - newAttributes = { - ...attributes, - content: value, - }; - } - - const block = createBlock( name, newAttributes ); - - if ( isOriginal ) { - block.clientId = clientId; - } - - return block; - } } - onMerge={ mergeBlocks } + ); diff --git a/packages/block-library/src/paragraph/use-enter.js b/packages/block-library/src/paragraph/use-enter.js index 22bef120ef17c..fb7619df5e957 100644 --- a/packages/block-library/src/paragraph/use-enter.js +++ b/packages/block-library/src/paragraph/use-enter.js @@ -23,6 +23,7 @@ export function useOnEnter( props ) { getBlockName, getBlock, getNextBlockClientId, + getBlockAttributes, } = useSelect( blockEditorStore ); const propsRef = useRef( props ); propsRef.current = props; @@ -36,7 +37,8 @@ export function useOnEnter( props ) { return; } - const { content, clientId } = propsRef.current; + const { clientId } = propsRef.current; + const { content } = getBlockAttributes( clientId ); // The paragraph should be empty. if ( content.length ) {