diff --git a/static/app-strings.json b/static/app-strings.json index 1ced8769f..9d0121e3a 100644 --- a/static/app-strings.json +++ b/static/app-strings.json @@ -1218,4 +1218,4 @@ "Check your rewards page to see if you qualify for paid content reimbursement. Only content in this section qualifies.": "Check your rewards page to see if you qualify for paid content reimbursement. Only content in this section qualifies.", "blocked channels": "blocked channels", "%count% %channels%. ": "%count% %channels%. " -} \ No newline at end of file +} diff --git a/ui/effects/use-drag-drop.js b/ui/effects/use-drag-drop.js new file mode 100644 index 000000000..78d524a0b --- /dev/null +++ b/ui/effects/use-drag-drop.js @@ -0,0 +1,97 @@ +import React from 'react'; + +const LISTENER = { + ADD: 'add', + REMOVE: 'remove', +}; + +const DRAG_TYPES = { + END: 'dragend', + START: 'dragstart', + ENTER: 'dragenter', + LEAVE: 'dragleave', +}; + +const DRAG_SCORE = { + [DRAG_TYPES.ENTER]: 1, + [DRAG_TYPES.LEAVE]: -1, +}; + +const DRAG_STATE = { + [DRAG_TYPES.END]: false, + [DRAG_TYPES.START]: true, +}; + +// Returns simple detection for global drag-drop +export default function useFetched() { + const [drag, setDrag] = React.useState(false); + const [drop, setDrop] = React.useState(null); + + React.useEffect(() => { + let dragCount = 0; + let draggingElement = false; + + // Handle file drop + const handleDropEvent = event => { + // Ignore non file types ( html elements / text ) + if (!draggingElement) { + event.stopPropagation(); + event.preventDefault(); + // Get files + const files = event.dataTransfer.files; + // Store files in state + if (files.length && files.length > 0) { + setDrop(files); + } + } + // Reset state ( hide drop zone ) + dragCount = 0; + setDrag(false); + }; + + // Drag event for non files type ( html elements / text ) + const handleDragElementEvent = event => { + draggingElement = DRAG_STATE[event.type]; + }; + + // Drag events + const handleDragEvent = event => { + event.stopPropagation(); + event.preventDefault(); + // Prevent multiple drop areas + dragCount += DRAG_SCORE[event.type]; + // Dragged file enters the drop area + if (dragCount === 1 && !draggingElement && event.type === DRAG_TYPES.ENTER) { + setDrag(true); + } + // Dragged file leaves the drop area + if (dragCount === 0 && event.type === DRAG_TYPES.LEAVE) { + setDrag(false); + } + }; + + // Register / Unregister listeners + const handleEventListeners = event => { + const action = `${event}EventListener`; + // Handle drop event + document[action]('drop', handleDropEvent); + // Handle drag events + document[action](DRAG_TYPES.ENTER, handleDragEvent); + document[action](DRAG_TYPES.LEAVE, handleDragEvent); + // Handle non files drag events + document[action](DRAG_TYPES.END, handleDragElementEvent); + document[action](DRAG_TYPES.START, handleDragElementEvent); + }; + // On component mounted: + // Register event listeners + handleEventListeners(LISTENER.ADD); + + // On component unmounted: + return () => { + // Unregister event listeners + handleEventListeners(LISTENER.REMOVE); + }; + }, []); + + return { drag, drop }; +}