diff --git a/src/components/DragAndDrop/Provider/index.native.tsx b/src/components/DragAndDrop/Provider/index.native.tsx index ba32599c62b5..838b9439c313 100644 --- a/src/components/DragAndDrop/Provider/index.native.tsx +++ b/src/components/DragAndDrop/Provider/index.native.tsx @@ -1,6 +1,7 @@ +import React from 'react'; import type {DragAndDropContextParams, DragAndDropProviderProps} from './types'; -const DragAndDropContext: DragAndDropContextParams = {}; +const DragAndDropContext = React.createContext({}); function DragAndDropProvider({children}: DragAndDropProviderProps) { return children; diff --git a/src/hooks/useDragAndDrop.ts b/src/hooks/useDragAndDrop.ts index c34b32db6425..0e82cb22505f 100644 --- a/src/hooks/useDragAndDrop.ts +++ b/src/hooks/useDragAndDrop.ts @@ -1,6 +1,7 @@ import {useIsFocused} from '@react-navigation/native'; -import React, {useCallback, useEffect, useRef, useState} from 'react'; +import React, {useCallback, useContext, useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; +import {PopoverContext} from '@components/PopoverProvider'; const COPY_DROP_EFFECT = 'copy'; const NONE_DROP_EFFECT = 'none'; @@ -27,6 +28,7 @@ type DragAndDropOptions = { export default function useDragAndDrop({dropZone, onDrop = () => {}, shouldAllowDrop = true, isDisabled = false, shouldAcceptDrop = () => true}: DragAndDropParams): DragAndDropOptions { const isFocused = useIsFocused(); const [isDraggingOver, setIsDraggingOver] = useState(false); + const {close: closePopover} = useContext(PopoverContext); // This solution is borrowed from this SO: https://stackoverflow.com/questions/7110353/html5-dragleave-fired-when-hovering-a-child-element // This is necessary because dragging over children will cause dragleave to execute on the parent. @@ -43,9 +45,15 @@ export default function useDragAndDrop({dropZone, onDrop = () => {}, shouldAllow setIsDraggingOver(false); }, [isFocused, isDisabled]); - const setDropEffect = useCallback( + const handleDragEvent = useCallback( (event: DragEvent) => { - const effect = shouldAllowDrop && shouldAcceptDrop(event) ? COPY_DROP_EFFECT : NONE_DROP_EFFECT; + const shouldAcceptThisDrop = shouldAllowDrop && shouldAcceptDrop(event); + + if (shouldAcceptThisDrop && event.type === DRAG_ENTER_EVENT) { + closePopover(); + } + + const effect = shouldAcceptThisDrop ? COPY_DROP_EFFECT : NONE_DROP_EFFECT; if (event.dataTransfer) { // eslint-disable-next-line no-param-reassign @@ -54,7 +62,7 @@ export default function useDragAndDrop({dropZone, onDrop = () => {}, shouldAllow event.dataTransfer.effectAllowed = effect; } }, - [shouldAllowDrop, shouldAcceptDrop], + [shouldAllowDrop, shouldAcceptDrop, closePopover], ); /** @@ -71,11 +79,11 @@ export default function useDragAndDrop({dropZone, onDrop = () => {}, shouldAllow switch (event.type) { case DRAG_OVER_EVENT: - setDropEffect(event); + handleDragEvent(event); break; case DRAG_ENTER_EVENT: dragCounter.current++; - setDropEffect(event); + handleDragEvent(event); if (isDraggingOver) { return; } @@ -98,7 +106,7 @@ export default function useDragAndDrop({dropZone, onDrop = () => {}, shouldAllow break; } }, - [isFocused, isDisabled, shouldAcceptDrop, setDropEffect, isDraggingOver, onDrop], + [isFocused, isDisabled, shouldAcceptDrop, isDraggingOver, onDrop, handleDragEvent], ); useEffect(() => { diff --git a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.js b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.js index 6e8d8d12afaf..e35d1e90bd5a 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.js +++ b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.js @@ -63,7 +63,7 @@ function SuggestionEmoji({ }) { const [suggestionValues, setSuggestionValues] = useState(defaultSuggestionsValues); - const isEmojiSuggestionsMenuVisible = !_.isEmpty(suggestionValues.suggestedEmojis) && suggestionValues.shouldShowEmojiSuggestionMenu; + const isEmojiSuggestionsMenuVisible = !_.isEmpty(suggestionValues.suggestedEmojis) && suggestionValues.shouldShowSuggestionMenu; const [highlightedEmojiIndex, setHighlightedEmojiIndex] = useArrowKeyFocusManager({ isActive: isEmojiSuggestionsMenuVisible, @@ -166,13 +166,13 @@ function SuggestionEmoji({ const nextState = { suggestedEmojis: [], colonIndex, - shouldShowEmojiSuggestionMenu: false, + shouldShowSuggestionMenu: false, }; const newSuggestedEmojis = EmojiUtils.suggestEmojis(leftString, preferredLocale); if (newSuggestedEmojis.length && isCurrentlyShowingEmojiSuggestion) { nextState.suggestedEmojis = newSuggestedEmojis; - nextState.shouldShowEmojiSuggestionMenu = !_.isEmpty(newSuggestedEmojis); + nextState.shouldShowSuggestionMenu = !_.isEmpty(newSuggestedEmojis); } setSuggestionValues((prevState) => ({...prevState, ...nextState})); diff --git a/src/pages/home/report/ReportActionCompose/Suggestions.js b/src/pages/home/report/ReportActionCompose/Suggestions.js index 05f35713c5f8..5dc71fec6419 100644 --- a/src/pages/home/report/ReportActionCompose/Suggestions.js +++ b/src/pages/home/report/ReportActionCompose/Suggestions.js @@ -1,6 +1,8 @@ import PropTypes from 'prop-types'; -import React, {useCallback, useImperativeHandle, useRef} from 'react'; +import React, {useCallback, useContext, useEffect, useImperativeHandle, useRef} from 'react'; import {View} from 'react-native'; +import {DragAndDropContext} from '@components/DragAndDrop/Provider'; +import usePrevious from '@hooks/usePrevious'; import SuggestionEmoji from './SuggestionEmoji'; import SuggestionMention from './SuggestionMention'; import * as SuggestionProps from './suggestionProps'; @@ -45,6 +47,8 @@ function Suggestions({ }) { const suggestionEmojiRef = useRef(null); const suggestionMentionRef = useRef(null); + const {isDraggingOver} = useContext(DragAndDropContext); + const prevIsDraggingOver = usePrevious(isDraggingOver); const getSuggestions = useCallback(() => { if (suggestionEmojiRef.current && suggestionEmojiRef.current.getSuggestions) { @@ -111,6 +115,13 @@ function Suggestions({ [onSelectionChange, resetSuggestions, setShouldBlockSuggestionCalc, triggerHotkeyActions, updateShouldShowSuggestionMenuToFalse, getSuggestions], ); + useEffect(() => { + if (!(!prevIsDraggingOver && isDraggingOver)) { + return; + } + updateShouldShowSuggestionMenuToFalse(); + }, [isDraggingOver, prevIsDraggingOver, updateShouldShowSuggestionMenuToFalse]); + const baseProps = { value, setValue,