Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TS migration] Migrate 'DragAndDrop' component to TypeScript #31267

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import dragAndDropConsumerPropTypes from './dragAndDropConsumerPropTypes';

function DragAndDropConsumer() {
return null;
}

DragAndDropConsumer.propTypes = dragAndDropConsumerPropTypes;
DragAndDropConsumer.displayName = 'DragAndDropConsumer';

export default DragAndDropConsumer;
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {Portal} from '@gorhom/portal';
import React, {useContext, useEffect} from 'react';
import {DragAndDropContext} from '@components/DragAndDrop/Provider';
import dragAndDropConsumerPropTypes from './dragAndDropConsumerPropTypes';
import type DragAndDropConsumerProps from './types';

function DragAndDropConsumer({children, onDrop}) {
function DragAndDropConsumer({children, onDrop}: DragAndDropConsumerProps) {
const {isDraggingOver, setOnDropHandler, dropZoneID} = useContext(DragAndDropContext);

useEffect(() => {
setOnDropHandler(onDrop);
setOnDropHandler?.(onDrop);
}, [onDrop, setOnDropHandler]);

if (!isDraggingOver) {
Expand All @@ -17,7 +17,6 @@ function DragAndDropConsumer({children, onDrop}) {
return <Portal hostName={dropZoneID}>{children}</Portal>;
}

DragAndDropConsumer.propTypes = dragAndDropConsumerPropTypes;
DragAndDropConsumer.displayName = 'DragAndDropConsumer';

export default DragAndDropConsumer;
11 changes: 11 additions & 0 deletions src/components/DragAndDrop/Consumer/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {ReactNode} from 'react';

type DragAndDropConsumerProps = {
/** Children to render inside this component. */
children: ReactNode;

/** Function to execute when an item is dropped in the drop zone. */
onDrop: (event: DragEvent) => void;
};

export default DragAndDropConsumerProps;
5 changes: 0 additions & 5 deletions src/components/DragAndDrop/NoDropZone/index.native.js

This file was deleted.

7 changes: 7 additions & 0 deletions src/components/DragAndDrop/NoDropZone/index.native.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type NoDropZoneProps from './types';

const NoDropZone = ({children}: NoDropZoneProps) => children;

NoDropZone.displayName = 'NoDropZone';

export default NoDropZone;
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
import PropTypes from 'prop-types';
import React, {useRef} from 'react';
import {View} from 'react-native';
import useDragAndDrop from '@hooks/useDragAndDrop';
import styles from '@styles/styles';
import type NoDropZoneProps from './types';

const propTypes = {
/** Content */
children: PropTypes.node.isRequired,
};
function NoDropZone({children}: NoDropZoneProps) {
const noDropZone = useRef<View>(null);

function NoDropZone({children}) {
const noDropZone = useRef(null);
useDragAndDrop({
dropZone: noDropZone,
shouldAllowDrop: false,
});

return (
<View
ref={(e) => (noDropZone.current = e)}
ref={noDropZone}
style={[styles.fullScreen]}
>
{children}
Expand All @@ -26,6 +23,5 @@ function NoDropZone({children}) {
}

NoDropZone.displayName = 'NoDropZone';
NoDropZone.propTypes = propTypes;

export default NoDropZone;
8 changes: 8 additions & 0 deletions src/components/DragAndDrop/NoDropZone/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {ReactNode} from 'react';

type NoDropZoneProps = {
/** Content */
children: ReactNode;
};

export default NoDropZoneProps;

This file was deleted.

13 changes: 0 additions & 13 deletions src/components/DragAndDrop/Provider/index.native.js

This file was deleted.

12 changes: 12 additions & 0 deletions src/components/DragAndDrop/Provider/index.native.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type {DragAndDropContextParams, DragAndDropProviderProps} from './types';

const DragAndDropContext: DragAndDropContextParams = {};

function DragAndDropProvider({children}: DragAndDropProviderProps) {
return children;
}

DragAndDropProvider.displayName = 'DragAndDropProvider';

export default DragAndDropProvider;
export {DragAndDropContext};
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,22 @@ import {PortalHost} from '@gorhom/portal';
import Str from 'expensify-common/lib/str';
import React, {useCallback, useEffect, useMemo, useRef} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
import useDragAndDrop from '@hooks/useDragAndDrop';
import styles from '@styles/styles';
import dragAndDropProviderPropTypes from './dragAndDropProviderPropTypes';
import type {DragAndDropContextParams, DragAndDropProviderProps, SetOnDropHandlerCallback} from './types';

const DragAndDropContext = React.createContext({});
const DragAndDropContext = React.createContext<DragAndDropContextParams>({});

/**
* @param {Event} event – drag event
* @returns {Boolean}
*/
function shouldAcceptDrop(event) {
return _.some(event.dataTransfer.types, (type) => type === 'Files');
function shouldAcceptDrop(event: DragEvent): boolean {
return !!event.dataTransfer?.types.some((type) => type === 'Files');
}

function DragAndDropProvider({children, isDisabled = false, setIsDraggingOver = () => {}}) {
const dropZone = useRef(null);
function DragAndDropProvider({children, isDisabled = false, setIsDraggingOver = () => {}}: DragAndDropProviderProps) {
const dropZone = useRef<View>(null);
const dropZoneID = useRef(Str.guid('drag-n-drop'));

const onDropHandler = useRef(() => {});
const setOnDropHandler = useCallback((callback) => {
const onDropHandler = useRef<SetOnDropHandlerCallback>(() => {});
const setOnDropHandler = useCallback((callback: SetOnDropHandlerCallback) => {
onDropHandler.current = callback;
}, []);

Expand All @@ -38,10 +33,11 @@ function DragAndDropProvider({children, isDisabled = false, setIsDraggingOver =
}, [isDraggingOver, setIsDraggingOver]);

const contextValue = useMemo(() => ({isDraggingOver, setOnDropHandler, dropZoneID: dropZoneID.current}), [isDraggingOver, setOnDropHandler]);

return (
<DragAndDropContext.Provider value={contextValue}>
<View
ref={(e) => (dropZone.current = e)}
ref={dropZone}
style={[styles.flex1, styles.w100, styles.h100]}
>
{isDraggingOver && (
Expand All @@ -55,7 +51,6 @@ function DragAndDropProvider({children, isDisabled = false, setIsDraggingOver =
);
}

DragAndDropProvider.propTypes = dragAndDropProviderPropTypes;
DragAndDropProvider.displayName = 'DragAndDropProvider';

export default DragAndDropProvider;
Expand Down
27 changes: 27 additions & 0 deletions src/components/DragAndDrop/Provider/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {ReactNode} from 'react';

type DragAndDropProviderProps = {
/** Children to render inside this component. */
children: ReactNode;

/** Should this dropZone be disabled? */
isDisabled?: boolean;

/** Indicate that users are dragging file or not */
setIsDraggingOver: (value: boolean) => void;
};

type SetOnDropHandlerCallback = (event: DragEvent) => void;

type DragAndDropContextParams = {
/** Whether something is dragging over a drop zone. */
isDraggingOver?: boolean;

/** Execute callback when an item is dropped in the drop zone. */
setOnDropHandler?: (callback: SetOnDropHandlerCallback) => void;

/** Drop zone id. */
dropZoneID?: string;
};

export type {DragAndDropProviderProps, DragAndDropContextParams, SetOnDropHandlerCallback};
9 changes: 5 additions & 4 deletions src/hooks/useDragAndDrop.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {useIsFocused} from '@react-navigation/native';
import React, {useCallback, useEffect, useRef, useState} from 'react';
import {View} from 'react-native';

const COPY_DROP_EFFECT = 'copy';
const NONE_DROP_EFFECT = 'none';
Expand All @@ -9,11 +10,11 @@ const DRAG_LEAVE_EVENT = 'dragleave';
const DROP_EVENT = 'drop';

type DragAndDropParams = {
dropZone: React.MutableRefObject<HTMLDivElement | null>;
onDrop?: (event?: DragEvent) => void;
dropZone: React.MutableRefObject<HTMLDivElement | View | null>;
onDrop?: (event: DragEvent) => void;
shouldAllowDrop?: boolean;
isDisabled?: boolean;
shouldAcceptDrop?: (event?: DragEvent) => boolean;
shouldAcceptDrop?: (event: DragEvent) => boolean;
};

type DragAndDropOptions = {
Expand Down Expand Up @@ -105,7 +106,7 @@ export default function useDragAndDrop({dropZone, onDrop = () => {}, shouldAllow
return;
}

const dropZoneRef = dropZone.current;
const dropZoneRef = dropZone.current as HTMLDivElement;

// 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
Expand Down
Loading