Skip to content

Commit

Permalink
Drop zone: fix media lib duplicate issue (#29567)
Browse files Browse the repository at this point in the history
* Drop zone: fix media lib duplicate issue

* Use ref effect
  • Loading branch information
ellatrix authored and noisysocks committed Mar 5, 2021
1 parent b543d8b commit 2a4d488
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 125 deletions.
240 changes: 119 additions & 121 deletions packages/components/src/drop-zone/provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,10 @@ import { find, some, filter, includes, throttle } from 'lodash';
/**
* WordPress dependencies
*/
import {
createContext,
useEffect,
useRef,
useContext,
} from '@wordpress/element';
import { createContext, useRef, useContext } from '@wordpress/element';
import { getFilesFromDataTransfer } from '@wordpress/dom';
import isShallowEqual from '@wordpress/is-shallow-equal';
import { useRefEffect } from '@wordpress/compose';

export const Context = createContext();

Expand Down Expand Up @@ -109,135 +105,138 @@ export const INITIAL_DROP_ZONE_STATE = {
type: null,
};

export function useDrop( ref ) {
export function useDrop() {
const dropZones = useContext( Context );

useEffect( () => {
const { ownerDocument } = ref.current;
const { defaultView } = ownerDocument;
return useRefEffect(
( node ) => {
const { ownerDocument } = node;
const { defaultView } = ownerDocument;

let lastRelative;
let lastRelative;

function updateDragZones( event ) {
if ( lastRelative && lastRelative.contains( event.target ) ) {
return;
}

const dragEventType = getDragEventType( event );
const position = getPosition( event );
const hoveredDropZone = getHoveredDropZone(
dropZones,
position,
dragEventType
);

if ( hoveredDropZone && hoveredDropZone.isRelative ) {
lastRelative = hoveredDropZone.element.current.offsetParent;
} else {
lastRelative = null;
}
function updateDragZones( event ) {
if ( lastRelative && lastRelative.contains( event.target ) ) {
return;
}

// Notifying the dropzones
dropZones.forEach( ( dropZone ) => {
const isDraggingOverDropZone = dropZone === hoveredDropZone;
const newState = {
isDraggingOverDocument: isTypeSupportedByDropZone(
dragEventType,
dropZone
),
isDraggingOverElement: isDraggingOverDropZone,
x:
isDraggingOverDropZone && dropZone.withPosition
? position.x
: null,
y:
isDraggingOverDropZone && dropZone.withPosition
? position.y
: null,
type: isDraggingOverDropZone ? dragEventType : null,
};

dropZone.setState( ( state ) => {
if ( isShallowEqual( state, newState ) ) {
return state;
}
const dragEventType = getDragEventType( event );
const position = getPosition( event );
const hoveredDropZone = getHoveredDropZone(
dropZones,
position,
dragEventType
);

if ( hoveredDropZone && hoveredDropZone.isRelative ) {
lastRelative = hoveredDropZone.element.current.offsetParent;
} else {
lastRelative = null;
}

return newState;
// Notifying the dropzones
dropZones.forEach( ( dropZone ) => {
const isDraggingOverDropZone = dropZone === hoveredDropZone;
const newState = {
isDraggingOverDocument: isTypeSupportedByDropZone(
dragEventType,
dropZone
),
isDraggingOverElement: isDraggingOverDropZone,
x:
isDraggingOverDropZone && dropZone.withPosition
? position.x
: null,
y:
isDraggingOverDropZone && dropZone.withPosition
? position.y
: null,
type: isDraggingOverDropZone ? dragEventType : null,
};

dropZone.setState( ( state ) => {
if ( isShallowEqual( state, newState ) ) {
return state;
}

return newState;
} );
} );
} );

event.preventDefault();
}
event.preventDefault();
}

const throttledUpdateDragZones = throttle( updateDragZones, 200 );
const throttledUpdateDragZones = throttle( updateDragZones, 200 );

function onDragOver( event ) {
throttledUpdateDragZones( event );
event.preventDefault();
}
function onDragOver( event ) {
throttledUpdateDragZones( event );
event.preventDefault();
}

function resetDragState() {
// Avoid throttled drag over handler calls
throttledUpdateDragZones.cancel();
function resetDragState() {
// Avoid throttled drag over handler calls
throttledUpdateDragZones.cancel();

dropZones.forEach( ( dropZone ) =>
dropZone.setState( INITIAL_DROP_ZONE_STATE )
);
}
dropZones.forEach( ( dropZone ) =>
dropZone.setState( INITIAL_DROP_ZONE_STATE )
);
}

function onDrop( event ) {
// This seemingly useless line has been shown to resolve a Safari issue
// where files dragged directly from the dock are not recognized
event.dataTransfer && event.dataTransfer.files.length; // eslint-disable-line no-unused-expressions

const dragEventType = getDragEventType( event );
const position = getPosition( event );
const hoveredDropZone = getHoveredDropZone(
dropZones,
position,
dragEventType
);

resetDragState();

if ( hoveredDropZone ) {
switch ( dragEventType ) {
case 'file':
hoveredDropZone.onFilesDrop(
getFilesFromDataTransfer( event.dataTransfer ),
position
);
break;
case 'html':
hoveredDropZone.onHTMLDrop(
event.dataTransfer.getData( 'text/html' ),
position
);
break;
case 'default':
hoveredDropZone.onDrop( event, position );
function onDrop( event ) {
// This seemingly useless line has been shown to resolve a Safari issue
// where files dragged directly from the dock are not recognized
event.dataTransfer && event.dataTransfer.files.length; // eslint-disable-line no-unused-expressions

const dragEventType = getDragEventType( event );
const position = getPosition( event );
const hoveredDropZone = getHoveredDropZone(
dropZones,
position,
dragEventType
);

resetDragState();

if ( hoveredDropZone ) {
switch ( dragEventType ) {
case 'file':
hoveredDropZone.onFilesDrop(
getFilesFromDataTransfer( event.dataTransfer ),
position
);
break;
case 'html':
hoveredDropZone.onHTMLDrop(
event.dataTransfer.getData( 'text/html' ),
position
);
break;
case 'default':
hoveredDropZone.onDrop( event, position );
}
}
}

event.stopPropagation();
event.preventDefault();
}
event.stopPropagation();
event.preventDefault();
}

defaultView.addEventListener( 'drop', onDrop );
defaultView.addEventListener( 'dragover', onDragOver );
defaultView.addEventListener( 'mouseup', resetDragState );
// Note that `dragend` doesn't fire consistently for file and HTML drag
// events where the drag origin is outside the browser window.
// In Firefox it may also not fire if the originating node is removed.
defaultView.addEventListener( 'dragend', resetDragState );

return () => {
defaultView.removeEventListener( 'drop', onDrop );
defaultView.removeEventListener( 'dragover', onDragOver );
defaultView.removeEventListener( 'mouseup', resetDragState );
defaultView.removeEventListener( 'dragend', resetDragState );
};
}, [ ref, dropZones ] );
node.addEventListener( 'drop', onDrop );
defaultView.addEventListener( 'dragover', onDragOver );
defaultView.addEventListener( 'mouseup', resetDragState );
// Note that `dragend` doesn't fire consistently for file and HTML drag
// events where the drag origin is outside the browser window.
// In Firefox it may also not fire if the originating node is removed.
defaultView.addEventListener( 'dragend', resetDragState );

return () => {
node.removeEventListener( 'drop', onDrop );
defaultView.removeEventListener( 'dragover', onDragOver );
defaultView.removeEventListener( 'mouseup', resetDragState );
defaultView.removeEventListener( 'dragend', resetDragState );
};
},
[ dropZones ]
);
}

export function DropZoneContextProvider( props ) {
Expand All @@ -246,8 +245,7 @@ export function DropZoneContextProvider( props ) {
}

function DropContainer( { children } ) {
const ref = useRef();
useDrop( ref );
const ref = useDrop();
return (
<div ref={ ref } className="components-drop-zone__provider">
{ children }
Expand Down
6 changes: 2 additions & 4 deletions packages/edit-post/src/components/layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import {
InterfaceSkeleton,
store as interfaceStore,
} from '@wordpress/interface';
import { useState, useEffect, useCallback, useRef } from '@wordpress/element';
import { useState, useEffect, useCallback } from '@wordpress/element';
import { close } from '@wordpress/icons';
import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts';

Expand Down Expand Up @@ -172,9 +172,7 @@ function Layout( { styles } ) {
},
[ entitiesSavedStatesCallback ]
);
const ref = useRef();

useDrop( ref );
const ref = useDrop( ref );
const [ inserterDialogRef, inserterDialogProps ] = useDialog( {
onClose: () => setIsInserterOpened( false ),
} );
Expand Down

0 comments on commit 2a4d488

Please sign in to comment.