diff --git a/packages/block-editor/src/components/block-selection-clearer/index.js b/packages/block-editor/src/components/block-selection-clearer/index.js index b97b8895b5a9bb..8501d3179eacd1 100644 --- a/packages/block-editor/src/components/block-selection-clearer/index.js +++ b/packages/block-editor/src/components/block-selection-clearer/index.js @@ -2,8 +2,9 @@ * WordPress dependencies */ import { useSelect, useDispatch } from '@wordpress/data'; +import { useEffect, useRef } from '@wordpress/element'; -function useBlockSelectionClearer() { +export function useBlockSelectionClearer( ref ) { const hasSelection = useSelect( ( select ) => { const { hasSelectedBlock, hasMultiSelection } = select( 'core/block-editor' @@ -13,14 +14,25 @@ function useBlockSelectionClearer() { } ); const { clearSelectedBlock } = useDispatch( 'core/block-editor' ); - return ( event ) => { - if ( event.target === event.currentTarget && hasSelection ) { + useEffect( () => { + if ( ! hasSelection ) { + return; + } + + function onFocus() { clearSelectedBlock(); } - }; + + ref.current.addEventListener( 'focus', onFocus ); + + return () => { + ref.current.removeEventListener( 'focus', onFocus ); + }; + }, [ hasSelection, clearSelectedBlock ] ); } export default function BlockSelectionClearer( props ) { - const onFocus = useBlockSelectionClearer(); - return
; + const ref = useRef(); + useBlockSelectionClearer( ref ); + return ; } diff --git a/packages/block-editor/src/components/copy-handler/index.js b/packages/block-editor/src/components/copy-handler/index.js index 808c9cedf24179..887005b48488f5 100644 --- a/packages/block-editor/src/components/copy-handler/index.js +++ b/packages/block-editor/src/components/copy-handler/index.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { useCallback, useRef } from '@wordpress/element'; +import { useCallback, useEffect, useRef } from '@wordpress/element'; import { serialize, pasteHandler } from '@wordpress/blocks'; import { documentHasSelection, @@ -71,97 +71,99 @@ export function useNotifyCopy() { }, [] ); } -function CopyHandler( { children } ) { - const containerRef = useRef(); - +export function useClipboardHandler( ref ) { const { getBlocksByClientId, getSelectedBlockClientIds, hasMultiSelection, getSettings, } = useSelect( ( select ) => select( 'core/block-editor' ), [] ); - const { flashBlock, removeBlocks, replaceBlocks } = useDispatch( 'core/block-editor' ); - const notifyCopy = useNotifyCopy(); - const { - __experimentalCanUserUseUnfilteredHTML: canUserUseUnfilteredHTML, - } = getSettings(); + useEffect( () => { + function handler( event ) { + const selectedBlockClientIds = getSelectedBlockClientIds(); - const handler = ( event ) => { - const selectedBlockClientIds = getSelectedBlockClientIds(); + if ( selectedBlockClientIds.length === 0 ) { + return; + } - if ( selectedBlockClientIds.length === 0 ) { - return; - } + // Always handle multiple selected blocks. + if ( ! hasMultiSelection() ) { + const { target } = event; + const { ownerDocument } = target; + // If copying, only consider actual text selection as selection. + // Otherwise, any focus on an input field is considered. + const hasSelection = + event.type === 'copy' || event.type === 'cut' + ? documentHasUncollapsedSelection( ownerDocument ) + : documentHasSelection( ownerDocument ); + + // Let native copy behaviour take over in input fields. + if ( hasSelection ) { + return; + } + } - // Always handle multiple selected blocks. - if ( ! hasMultiSelection() ) { - const { target } = event; - const { ownerDocument } = target; - // If copying, only consider actual text selection as selection. - // Otherwise, any focus on an input field is considered. - const hasSelection = - event.type === 'copy' || event.type === 'cut' - ? documentHasUncollapsedSelection( ownerDocument ) - : documentHasSelection( ownerDocument ); - - // Let native copy behaviour take over in input fields. - if ( hasSelection ) { + if ( ! ref.current.contains( event.target ) ) { return; } - } + event.preventDefault(); + + if ( event.type === 'copy' || event.type === 'cut' ) { + if ( selectedBlockClientIds.length === 1 ) { + flashBlock( selectedBlockClientIds[ 0 ] ); + } + notifyCopy( event.type, selectedBlockClientIds ); + const blocks = getBlocksByClientId( selectedBlockClientIds ); + const serialized = serialize( blocks ); + + event.clipboardData.setData( 'text/plain', serialized ); + event.clipboardData.setData( 'text/html', serialized ); + } - if ( ! containerRef.current.contains( event.target ) ) { - return; + if ( event.type === 'cut' ) { + removeBlocks( selectedBlockClientIds ); + } else if ( event.type === 'paste' ) { + const { + __experimentalCanUserUseUnfilteredHTML: canUserUseUnfilteredHTML, + } = getSettings(); + const { plainText, html } = getPasteEventData( event ); + const blocks = pasteHandler( { + HTML: html, + plainText, + mode: 'BLOCKS', + canUserUseUnfilteredHTML, + } ); + + replaceBlocks( + selectedBlockClientIds, + blocks, + blocks.length - 1, + -1 + ); + } } - event.preventDefault(); - if ( event.type === 'copy' || event.type === 'cut' ) { - if ( selectedBlockClientIds.length === 1 ) { - flashBlock( selectedBlockClientIds[ 0 ] ); - } - notifyCopy( event.type, selectedBlockClientIds ); - const blocks = getBlocksByClientId( selectedBlockClientIds ); - const serialized = serialize( blocks ); + ref.current.addEventListener( 'copy', handler ); + ref.current.addEventListener( 'cut', handler ); + ref.current.addEventListener( 'paste', handler ); - event.clipboardData.setData( 'text/plain', serialized ); - event.clipboardData.setData( 'text/html', serialized ); - } + return () => { + ref.current.removeEventListener( 'copy', handler ); + ref.current.removeEventListener( 'cut', handler ); + ref.current.removeEventListener( 'paste', handler ); + }; + }, [] ); +} - if ( event.type === 'cut' ) { - removeBlocks( selectedBlockClientIds ); - } else if ( event.type === 'paste' ) { - const { plainText, html } = getPasteEventData( event ); - const blocks = pasteHandler( { - HTML: html, - plainText, - mode: 'BLOCKS', - canUserUseUnfilteredHTML, - } ); - - replaceBlocks( - selectedBlockClientIds, - blocks, - blocks.length - 1, - -1 - ); - } - }; - - return ( -