From 35ba228d77b056f119cb92bb198c5403276548a2 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Tue, 14 Nov 2023 14:44:29 +1100 Subject: [PATCH] Code dump from PR #23497 --- .../src/components/block-list/block.js | 12 ++ .../block-list/drag-on-long-press.js | 149 ++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 packages/block-editor/src/components/block-list/drag-on-long-press.js diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index a95075c6f9b42..7cef45fa46206 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -38,6 +38,8 @@ import { useBlockProps } from './use-block-props'; import { store as blockEditorStore } from '../../store'; import { useLayout } from './layout'; import { BlockListBlockContext } from './block-list-block-context'; +import { DragOnLongPress } from './drag-on-long-press'; +import { __unstableUseBlockRef as useBlockRef } from './use-block-props/use-block-refs'; /** * Merges wrapper props with special handling for classNames and styles. @@ -95,18 +97,21 @@ function BlockListBlock( { themeSupportsLayout, isTemporarilyEditingAsBlocks, blockEditingMode, + rootClientId, } = useSelect( ( select ) => { const { getSettings, __unstableGetTemporarilyEditingAsBlocks, getBlockEditingMode, + getBlockRootClientId, } = select( blockEditorStore ); return { themeSupportsLayout: getSettings().supportsLayout, isTemporarilyEditingAsBlocks: __unstableGetTemporarilyEditingAsBlocks() === clientId, blockEditingMode: getBlockEditingMode( clientId ), + rootClientId: getBlockRootClientId( clientId ), }; }, [ clientId ] @@ -229,6 +234,8 @@ function BlockListBlock( { const memoizedValue = useMemo( () => value, Object.values( value ) ); + const blockWrapperRef = useBlockRef( clientId ); + return ( { block } + ); diff --git a/packages/block-editor/src/components/block-list/drag-on-long-press.js b/packages/block-editor/src/components/block-list/drag-on-long-press.js new file mode 100644 index 0000000000000..9f05a2ccbb521 --- /dev/null +++ b/packages/block-editor/src/components/block-list/drag-on-long-press.js @@ -0,0 +1,149 @@ +/** + * WordPress dependencies + */ +import { useRef, useEffect, useState, createPortal } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import BlockDraggableChip from '../block-draggable/draggable-chip'; + +function useOnLongPress( ref, timeout, callback, deps ) { + useEffect( () => { + let timeoutId; + const set = ( event ) => { + clearTimeout( timeoutId ); + timeoutId = setTimeout( () => callback( event ), timeout ); + }; + const unset = () => { + clearTimeout( timeoutId ); + }; + + ref.current.addEventListener( 'mousedown', set ); + ref.current.addEventListener( 'mouseup', unset ); + return () => { + ref.current.removeEventListener( 'mousedown', set ); + ref.current.removeEventListener( 'mouseup', unset ); + clearTimeout( timeoutId ); + }; + }, deps ); +} + +export function DragOnLongPress( { target, clientId, rootClientId } ) { + const [ isDraggging, setIsDragging ] = useState( false ); + const container = useRef( document.createElement( 'div' ) ); + + useOnLongPress( + target, + 250, + () => { + if ( + // isSelected is oudated. + ! target.current.classList.contains( 'is-selected' ) || + ! target.current.ownerDocument.defaultView.getSelection() + .isCollapsed + ) { + return; + } + + const cancel = () => { + window.removeEventListener( 'mouseup', cancel ); + document.removeEventListener( 'selectionchange', cancel ); + + target.current.style.transform = ''; + target.current.style.transition = ''; + }; + + window.addEventListener( 'mouseup', cancel ); + document.addEventListener( 'selectionchange', cancel ); + + target.current.style.transform = 'scale(1.02)'; + // target.current.style.transition = 'transform .75s ease-in-out'; + }, + [] + ); + + useOnLongPress( + target, + 1000, + ( _event ) => { + target.current.style.transform = ''; + target.current.style.transition = ''; + + if ( + ! target.current.classList.contains( 'is-selected' ) || + ! target.current.ownerDocument.defaultView.getSelection() + .isCollapsed + ) { + return; + } + + const { parentNode } = target.current; + + setIsDragging( true ); + target.current.style.display = 'none'; + target.current.ownerDocument.defaultView + .getSelection() + .removeAllRanges(); + parentNode.appendChild( container.current ); + container.current.style.position = 'fixed'; + container.current.style.pointerEvents = 'none'; + container.current.style.left = _event.clientX - 20 + 'px'; + container.current.style.top = _event.clientY + 20 + 'px'; + + const onMouseMove = ( event ) => { + const newEvent = new window.CustomEvent( 'dragover', { + bubbles: true, + detail: { + clientX: event.clientX, + clientY: event.clientY, + }, + } ); + window.dispatchEvent( newEvent ); + + container.current.style.left = event.clientX - 20 + 'px'; + container.current.style.top = event.clientY + 20 + 'px'; + }; + + const onMouseUp = ( event ) => { + window.removeEventListener( 'mousemove', onMouseMove ); + window.removeEventListener( 'mouseup', onMouseUp ); + + setIsDragging( false ); + + const dataTransfer = new window.DataTransfer(); + const data = { + type: 'block', + srcClientId: clientId, + srcRootClientId: rootClientId || '', + }; + + dataTransfer.setData( 'text', JSON.stringify( data ) ); + + const newEvent = new window.DragEvent( 'drop', { + bubbles: true, + dataTransfer, + } ); + event.target.dispatchEvent( newEvent ); + parentNode.removeChild( container.current ); + + if ( target.current ) { + target.current.style.display = ''; + } + }; + + window.addEventListener( 'mousemove', onMouseMove ); + window.addEventListener( 'mouseup', onMouseUp ); + }, + [] + ); + + if ( ! isDraggging ) { + return null; + } + + return createPortal( + , + container.current + ); +}