diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js index 5f94206c78752..87a9dc503a9be 100644 --- a/packages/block-editor/src/components/rich-text/index.js +++ b/packages/block-editor/src/components/rich-text/index.js @@ -19,7 +19,6 @@ import { removeFormat, } from '@wordpress/rich-text'; import { Popover } from '@wordpress/components'; -import { getBlockType, store as blocksStore } from '@wordpress/blocks'; /** * Internal dependencies @@ -45,8 +44,7 @@ import FormatEdit from './format-edit'; import { getAllowedFormats } from './utils'; import { Content } from './content'; import { withDeprecations } from './with-deprecations'; -import { unlock } from '../../lock-unlock'; -import { BLOCK_BINDINGS_ALLOWED_BLOCKS } from '../../hooks/use-bindings-attributes'; +import { useShouldDisableEditing } from './use-should-disable-editing'; export const keyboardShortcutContext = createContext(); export const inputEventContext = createContext(); @@ -117,11 +115,7 @@ export function RichTextWrapper( props = removeNativeProps( props ); const anchorRef = useRef(); - const { - clientId, - isSelected: isBlockSelected, - name: blockName, - } = useBlockEditContext(); + const { clientId, isSelected: isBlockSelected } = useBlockEditContext(); const selector = ( select ) => { // Avoid subscribing to the block editor store if the block is not // selected. @@ -129,12 +123,10 @@ export function RichTextWrapper( return { isSelected: false }; } - const { getSelectionStart, getSelectionEnd, getBlockAttributes } = + const { getSelectionStart, getSelectionEnd } = select( blockEditorStore ); const selectionStart = getSelectionStart(); const selectionEnd = getSelectionEnd(); - const blockBindings = - getBlockAttributes( clientId )?.metadata?.bindings; let isSelected; @@ -147,53 +139,22 @@ export function RichTextWrapper( isSelected = selectionStart.clientId === clientId; } - // Disable Rich Text editing if block bindings specify that. - let disableBoundBlocks = false; - if ( blockBindings && blockName in BLOCK_BINDINGS_ALLOWED_BLOCKS ) { - const blockTypeAttributes = getBlockType( blockName ).attributes; - const { getBlockBindingsSource } = unlock( select( blocksStore ) ); - for ( const [ attribute, args ] of Object.entries( - blockBindings - ) ) { - if ( - blockTypeAttributes?.[ attribute ]?.source !== 'rich-text' - ) { - break; - } - - // If the source is not defined, or if its value of `lockAttributesEditing` is `true`, disable it. - const blockBindingsSource = getBlockBindingsSource( - args.source - ); - if ( - ! blockBindingsSource || - blockBindingsSource.lockAttributesEditing - ) { - disableBoundBlocks = true; - break; - } - } - } - return { selectionStart: isSelected ? selectionStart.offset : undefined, selectionEnd: isSelected ? selectionEnd.offset : undefined, isSelected, - disableBoundBlocks, }; }; - const { selectionStart, selectionEnd, isSelected, disableBoundBlocks } = - useSelect( selector, [ - clientId, - identifier, - originalIsSelected, - isBlockSelected, - ] ); - - const shouldDisableEditing = disableEditing || disableBoundBlocks; - + const { selectionStart, selectionEnd, isSelected } = useSelect( selector, [ + clientId, + identifier, + originalIsSelected, + isBlockSelected, + ] ); const { getSelectionStart, getSelectionEnd, getBlockRootClientId } = useSelect( blockEditorStore ); + // Disable Rich Text editing if block bindings specify that. + const shouldDisableEditing = useShouldDisableEditing( identifier ); const { selectionChange } = useDispatch( blockEditorStore ); const adjustedAllowedFormats = getAllowedFormats( { allowedFormats, @@ -333,6 +294,7 @@ export function RichTextWrapper( } const TagName = tagName; + const tabIndex = props.tabIndex === 0 ? null : props.tabIndex; return ( <> { isSelected && ( @@ -415,6 +377,7 @@ export function RichTextWrapper( disableLineBreaks, onSplitAtEnd, onSplitAtDoubleLineEnd, + shouldDisableEditing, } ), useFirefoxCompat(), anchorRef, @@ -426,17 +389,13 @@ export function RichTextWrapper( props.className, 'rich-text' ) } - // Setting tabIndex to 0 is unnecessary, the element is already + // Setting tabIndex to 0 is unnecessary, if the element is already // focusable because it's contentEditable. This also fixes a // Safari bug where it's not possible to Shift+Click multi // select blocks when Shift Clicking into an element with // tabIndex because Safari will focus the element. However, // Safari will correctly ignore nested contentEditable elements. - tabIndex={ - props.tabIndex === 0 && ! shouldDisableEditing - ? null - : props.tabIndex - } + tabIndex={ shouldDisableEditing ? 0 : tabIndex } data-wp-block-attribute-key={ identifier } /> diff --git a/packages/block-editor/src/components/rich-text/use-enter.js b/packages/block-editor/src/components/rich-text/use-enter.js index 4daf70e7fa3c7..5f07462e7c972 100644 --- a/packages/block-editor/src/components/rich-text/use-enter.js +++ b/packages/block-editor/src/components/rich-text/use-enter.js @@ -38,6 +38,7 @@ export function useEnter( props ) { disableLineBreaks, onSplitAtEnd, onSplitAtDoubleLineEnd, + shouldDisableEditing, } = propsRef.current; event.preventDefault(); @@ -67,7 +68,13 @@ export function useEnter( props ) { const { text, start, end } = _value; - if ( event.shiftKey ) { + if ( shouldDisableEditing ) { + // Simulate the cursor is at the end of the rich text. + _value.start = _value.text?.length; + _value.end = _value.text?.length; + } + + if ( event.shiftKey && ! shouldDisableEditing ) { if ( ! disableLineBreaks ) { onChange( insert( _value, '\n' ) ); } diff --git a/packages/block-editor/src/components/rich-text/use-should-disable-editing.js b/packages/block-editor/src/components/rich-text/use-should-disable-editing.js new file mode 100644 index 0000000000000..4c8b7ed3e391a --- /dev/null +++ b/packages/block-editor/src/components/rich-text/use-should-disable-editing.js @@ -0,0 +1,40 @@ +/** + * WordPress dependencies + */ +import { store as blocksStore } from '@wordpress/blocks'; +import { useSelect } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { BLOCK_BINDINGS_ALLOWED_BLOCKS } from '../../hooks/use-bindings-attributes'; +import { useBlockEditContext } from '../block-edit'; +import { store as blockEditorStore } from '../../store'; +import { unlock } from '../../lock-unlock'; + +export function useShouldDisableEditing( attributeName ) { + const { clientId, name: blockName } = useBlockEditContext(); + return useSelect( + ( select ) => { + if ( + ! attributeName || + ! BLOCK_BINDINGS_ALLOWED_BLOCKS[ blockName ]?.includes( + attributeName + ) + ) { + return false; + } + const blockBindings = + select( blockEditorStore ).getBlockAttributes( clientId ) + ?.metadata?.bindings; + if ( ! blockBindings?.[ attributeName ]?.source ) { + return false; + } + const blockBindingsSource = unlock( + select( blocksStore ) + ).getBlockBindingsSource( blockBindings[ attributeName ].source ); + return blockBindingsSource?.lockAttributesEditing !== false; + }, + [ clientId, blockName, attributeName ] + ); +} diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js index 1d124baf1a7e3..912b541e28d0c 100644 --- a/packages/block-library/src/button/edit.js +++ b/packages/block-library/src/button/edit.js @@ -293,12 +293,23 @@ function ButtonEdit( props ) { ...spacingProps.style, ...shadowProps.style, } } - onSplit={ ( value ) => - createBlock( 'core/button', { - ...attributes, - text: value, - } ) - } + onSplit={ ( value, isOriginal ) => { + let newAttributes; + if ( isOriginal || value ) { + newAttributes = { + ...attributes, + text: value, + }; + } + const block = createBlock( + 'core/button', + newAttributes + ); + if ( isOriginal ) { + block.clientId = clientId; + } + return block; + } } onReplace={ onReplace } onMerge={ mergeBlocks } identifier="text"