diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx index 68f1aac41a5b..5392f92e7af4 100644 --- a/src/components/Button/index.tsx +++ b/src/components/Button/index.tsx @@ -200,7 +200,7 @@ function Button( accessibilityLabel = '', ...rest }: ButtonProps, - ref: ForwardedRef, + ref: ForwardedRef, ) { const theme = useTheme(); const styles = useThemeStyles(); diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index a4e6e2c87fec..78c51caf0657 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -40,7 +40,7 @@ function ButtonWithDropdownMenu({ const [isMenuVisible, setIsMenuVisible] = useState(false); const [popoverAnchorPosition, setPopoverAnchorPosition] = useState(null); const {windowWidth, windowHeight} = useWindowDimensions(); - const caretButton = useRef(null); + const caretButton = useRef(null); const selectedItem = options[selectedItemIndex] || options[0]; const innerStyleDropButton = StyleUtils.getDropDownButtonHeight(buttonSize); const isButtonSizeLarge = buttonSize === CONST.DROPDOWN_BUTTON_SIZE.LARGE; diff --git a/src/components/DragAndDrop/NoDropZone/index.tsx b/src/components/DragAndDrop/NoDropZone/index.tsx index 4760a16fd20b..ee3f2a6a34a1 100644 --- a/src/components/DragAndDrop/NoDropZone/index.tsx +++ b/src/components/DragAndDrop/NoDropZone/index.tsx @@ -2,20 +2,22 @@ import React, {useRef} from 'react'; import {View} from 'react-native'; import useDragAndDrop from '@hooks/useDragAndDrop'; import useThemeStyles from '@hooks/useThemeStyles'; +import htmlDivElementRef from '@src/types/utils/htmlDivElementRef'; +import viewRef from '@src/types/utils/viewRef'; import type NoDropZoneProps from './types'; function NoDropZone({children}: NoDropZoneProps) { const styles = useThemeStyles(); - const noDropZone = useRef(null); + const noDropZone = useRef(null); useDragAndDrop({ - dropZone: noDropZone, + dropZone: htmlDivElementRef(noDropZone), shouldAllowDrop: false, }); return ( {children} diff --git a/src/components/DragAndDrop/Provider/index.tsx b/src/components/DragAndDrop/Provider/index.tsx index a5da9cc45a36..dc02eea2b12c 100644 --- a/src/components/DragAndDrop/Provider/index.tsx +++ b/src/components/DragAndDrop/Provider/index.tsx @@ -4,6 +4,8 @@ import React, {useCallback, useEffect, useMemo, useRef} from 'react'; import {View} from 'react-native'; import useDragAndDrop from '@hooks/useDragAndDrop'; import useThemeStyles from '@hooks/useThemeStyles'; +import htmlDivElementRef from '@src/types/utils/htmlDivElementRef'; +import viewRef from '@src/types/utils/viewRef'; import type {DragAndDropContextParams, DragAndDropProviderProps, SetOnDropHandlerCallback} from './types'; const DragAndDropContext = React.createContext({}); @@ -14,7 +16,7 @@ function shouldAcceptDrop(event: DragEvent): boolean { function DragAndDropProvider({children, isDisabled = false, setIsDraggingOver = () => {}}: DragAndDropProviderProps) { const styles = useThemeStyles(); - const dropZone = useRef(null); + const dropZone = useRef(null); const dropZoneID = useRef(Str.guid('drag-n-drop')); const onDropHandler = useRef(() => {}); @@ -23,7 +25,7 @@ function DragAndDropProvider({children, isDisabled = false, setIsDraggingOver = }, []); const {isDraggingOver} = useDragAndDrop({ - dropZone, + dropZone: htmlDivElementRef(dropZone), onDrop: onDropHandler.current, shouldAcceptDrop, isDisabled, @@ -38,7 +40,7 @@ function DragAndDropProvider({children, isDisabled = false, setIsDraggingOver = return ( {isDraggingOver && ( diff --git a/src/components/KYCWall/BaseKYCWall.tsx b/src/components/KYCWall/BaseKYCWall.tsx index 7d2f99f49593..d37e00727fa6 100644 --- a/src/components/KYCWall/BaseKYCWall.tsx +++ b/src/components/KYCWall/BaseKYCWall.tsx @@ -69,7 +69,7 @@ function KYCWall({ walletTerms, shouldShowPersonalBankAccountOption = false, }: BaseKYCWallProps) { - const anchorRef = useRef(null); + const anchorRef = useRef(null); const transferBalanceButtonRef = useRef(null); const [shouldShowAddPaymentMenu, setShouldShowAddPaymentMenu] = useState(false); diff --git a/src/hooks/useDragAndDrop/index.native.ts b/src/hooks/useDragAndDrop/index.native.ts new file mode 100644 index 000000000000..4c1d0479aebb --- /dev/null +++ b/src/hooks/useDragAndDrop/index.native.ts @@ -0,0 +1,3 @@ +const useDragAndDrop = () => {}; + +export default useDragAndDrop; diff --git a/src/hooks/useDragAndDrop.ts b/src/hooks/useDragAndDrop/index.ts similarity index 87% rename from src/hooks/useDragAndDrop.ts rename to src/hooks/useDragAndDrop/index.ts index 7644d7bba5f0..b278039ee020 100644 --- a/src/hooks/useDragAndDrop.ts +++ b/src/hooks/useDragAndDrop/index.ts @@ -1,8 +1,7 @@ import {useIsFocused} from '@react-navigation/native'; -import type React from 'react'; import {useCallback, useContext, useEffect, useRef, useState} from 'react'; -import type {View} from 'react-native'; import {PopoverContext} from '@components/PopoverProvider'; +import type UseDragAndDrop from './types'; const COPY_DROP_EFFECT = 'copy'; const NONE_DROP_EFFECT = 'none'; @@ -11,22 +10,10 @@ const DRAG_OVER_EVENT = 'dragover'; const DRAG_LEAVE_EVENT = 'dragleave'; const DROP_EVENT = 'drop'; -type DragAndDropParams = { - dropZone: React.MutableRefObject; - onDrop?: (event: DragEvent) => void; - shouldAllowDrop?: boolean; - isDisabled?: boolean; - shouldAcceptDrop?: (event: DragEvent) => boolean; -}; - -type DragAndDropOptions = { - isDraggingOver: boolean; -}; - /** * @param dropZone – ref to the dropZone component */ -export default function useDragAndDrop({dropZone, onDrop = () => {}, shouldAllowDrop = true, isDisabled = false, shouldAcceptDrop = () => true}: DragAndDropParams): DragAndDropOptions { +const useDragAndDrop: UseDragAndDrop = ({dropZone, onDrop = () => {}, shouldAllowDrop = true, isDisabled = false, shouldAcceptDrop = () => true}) => { const isFocused = useIsFocused(); const [isDraggingOver, setIsDraggingOver] = useState(false); const {close: closePopover} = useContext(PopoverContext); @@ -111,7 +98,7 @@ export default function useDragAndDrop({dropZone, onDrop = () => {}, shouldAllow return; } - const dropZoneRef = dropZone.current as HTMLDivElement; + const dropZoneRef = dropZone.current; // Note that the dragover event needs to be called with `event.preventDefault` in order for the drop event to be fired: // https://stackoverflow.com/questions/21339924/drop-event-not-firing-in-chrome @@ -133,4 +120,6 @@ export default function useDragAndDrop({dropZone, onDrop = () => {}, shouldAllow }, [dropZone, dropZoneDragHandler]); return {isDraggingOver}; -} +}; + +export default useDragAndDrop; diff --git a/src/hooks/useDragAndDrop/types.ts b/src/hooks/useDragAndDrop/types.ts new file mode 100644 index 000000000000..4600b43d97bc --- /dev/null +++ b/src/hooks/useDragAndDrop/types.ts @@ -0,0 +1,15 @@ +type DragAndDropParams = { + dropZone: React.MutableRefObject; + onDrop?: (event: DragEvent) => void; + shouldAllowDrop?: boolean; + isDisabled?: boolean; + shouldAcceptDrop?: (event: DragEvent) => boolean; +}; + +type DragAndDropOptions = { + isDraggingOver: boolean; +}; + +type UseDragAndDrop = (params: DragAndDropParams) => DragAndDropOptions; + +export default UseDragAndDrop; diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index 619dcc54a031..69f3223e46f7 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -87,7 +87,6 @@ function WorkspaceMembersPage({personalDetails, invitedEmailsToAccountIDsDraft, const prevPersonalDetails = usePrevious(personalDetails); const {translate, formatPhoneNumber, preferredLocale} = useLocalize(); const {isSmallScreenWidth} = useWindowDimensions(); - const dropdownButtonRef = useRef(null); const isPolicyAdmin = PolicyUtils.isPolicyAdmin(policy); const isLoading = useMemo( () => !isOfflineAndNoMemberDataAvailable && (!OptionsListUtils.isPersonalDetailsReady(personalDetails) || isEmptyObject(policy?.employeeList)), @@ -515,7 +514,6 @@ function WorkspaceMembersPage({personalDetails, invitedEmailsToAccountIDsDraft, buttonSize={CONST.DROPDOWN_BUTTON_SIZE.MEDIUM} onPress={() => null} options={getBulkActionsButtonOptions()} - buttonRef={dropdownButtonRef} style={[isSmallScreenWidth && styles.flexGrow1]} /> ) : ( diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index 80394623dba8..4a04e326e04b 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -1,6 +1,6 @@ import {useFocusEffect, useIsFocused} from '@react-navigation/native'; import type {StackScreenProps} from '@react-navigation/stack'; -import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {ActivityIndicator, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; @@ -61,7 +61,6 @@ function WorkspaceCategoriesPage({policy, policyCategories, route}: WorkspaceCat const theme = useTheme(); const {translate} = useLocalize(); const [selectedCategories, setSelectedCategories] = useState>({}); - const dropdownButtonRef = useRef(null); const [deleteCategoriesConfirmModalVisible, setDeleteCategoriesConfirmModalVisible] = useState(false); const isFocused = useIsFocused(); @@ -208,7 +207,6 @@ function WorkspaceCategoriesPage({policy, policyCategories, route}: WorkspaceCat return ( null} shouldAlwaysShowDropdownMenu pressOnEnter diff --git a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx index ea35526bcdfa..556358b14619 100644 --- a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx +++ b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx @@ -1,6 +1,6 @@ import {useFocusEffect, useIsFocused} from '@react-navigation/native'; import type {StackScreenProps} from '@react-navigation/stack'; -import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {ActivityIndicator, View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; @@ -54,7 +54,6 @@ function PolicyDistanceRatesPage({policy, route}: PolicyDistanceRatesPageProps) const [selectedDistanceRates, setSelectedDistanceRates] = useState([]); const [isWarningModalVisible, setIsWarningModalVisible] = useState(false); const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false); - const dropdownButtonRef = useRef(null); const policyID = route.params.policyID; const isFocused = useIsFocused(); @@ -257,7 +256,6 @@ function PolicyDistanceRatesPage({policy, route}: PolicyDistanceRatesPageProps) buttonSize={CONST.DROPDOWN_BUTTON_SIZE.MEDIUM} onPress={() => null} options={getBulkActionsButtonOptions()} - buttonRef={dropdownButtonRef} style={[isSmallScreenWidth && styles.flexGrow1]} wrapperStyle={styles.w100} /> diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index fafee7b3b74d..e56154fa7a2a 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -1,7 +1,7 @@ import {useFocusEffect, useIsFocused} from '@react-navigation/native'; import type {StackScreenProps} from '@react-navigation/stack'; import lodashSortBy from 'lodash/sortBy'; -import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {ActivityIndicator, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; @@ -68,7 +68,6 @@ function WorkspaceTagsPage({policyTags, route}: WorkspaceTagsPageProps) { const theme = useTheme(); const {translate} = useLocalize(); const [selectedTags, setSelectedTags] = useState>({}); - const dropdownButtonRef = useRef(null); const [deleteTagsConfirmModalVisible, setDeleteTagsConfirmModalVisible] = useState(false); const isFocused = useIsFocused(); @@ -221,7 +220,6 @@ function WorkspaceTagsPage({policyTags, route}: WorkspaceTagsPageProps) { return ( null} shouldAlwaysShowDropdownMenu pressOnEnter diff --git a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx index a61c8ae72734..f742336f606e 100644 --- a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx +++ b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx @@ -1,6 +1,6 @@ import {useFocusEffect, useIsFocused} from '@react-navigation/native'; import type {StackScreenProps} from '@react-navigation/stack'; -import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {ActivityIndicator, View} from 'react-native'; import Button from '@components/Button'; import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; @@ -53,7 +53,6 @@ function WorkspaceTaxesPage({ const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false); const defaultExternalID = policy?.taxRates?.defaultExternalID; const foreignTaxDefault = policy?.taxRates?.foreignTaxDefault; - const dropdownButtonRef = useRef(null); const isFocused = useIsFocused(); const fetchTaxes = useCallback(() => { @@ -226,7 +225,6 @@ function WorkspaceTaxesPage({ ) : ( - buttonRef={dropdownButtonRef} onPress={() => {}} options={dropdownMenuOptions} buttonSize={CONST.DROPDOWN_BUTTON_SIZE.MEDIUM} diff --git a/src/types/utils/htmlDivElementRef.ts b/src/types/utils/htmlDivElementRef.ts new file mode 100644 index 000000000000..9a20bb87e32e --- /dev/null +++ b/src/types/utils/htmlDivElementRef.ts @@ -0,0 +1,5 @@ +import type {View} from 'react-native'; + +const htmlDivElementRef = (ref: React.RefObject) => ref as React.RefObject; + +export default htmlDivElementRef;