Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
65cac31
Rename dropZoneID prop to follow conventions
roryabraham Jul 25, 2023
9851ad1
Add prop types on default components
roryabraham Jul 25, 2023
f5f8743
Rename disabled prop to isDisabled
roryabraham Jul 25, 2023
faa216b
Create useEffectOnPageLoad hook
roryabraham Jul 25, 2023
931043b
Convert DragAndDrop to functional component
roryabraham Jul 25, 2023
7665425
Handle dragOver event to fix onDrop
roryabraham Jul 25, 2023
401e2c6
Fix passing throttled function to useEffectOnPageLoad
roryabraham Jul 25, 2023
1918bfa
Fix yet another whoops with the throttled function
roryabraham Jul 25, 2023
e0bd6f7
Re-implement DragAndDrop with context
roryabraham Jul 27, 2023
6be2fe0
Create useThrottledEffect hook
roryabraham Jul 27, 2023
23f2d4f
remove unused import
roryabraham Jul 27, 2023
5949c3e
Add flex 1 style to fix display
roryabraham Jul 27, 2023
2094ca0
Fix overlay style
roryabraham Jul 27, 2023
f5afe54
Remove throttled effect hook so measure can happen onLayout
roryabraham Jul 27, 2023
989f5fa
Fix drag state by nesting portal inside transparent overlay and imple…
roryabraham Jul 27, 2023
c9a1680
Simplify by removing measurement
roryabraham Jul 27, 2023
58b31c9
Remove unused useEffectOnPageLoad hook
roryabraham Jul 27, 2023
a0f6afa
Remove now-unused DropZone component
roryabraham Jul 27, 2023
807d819
Correctly pass event to subscriber
roryabraham Jul 27, 2023
48ce5e4
Fix storybook
roryabraham Jul 27, 2023
0a09b5b
Get rid of unnecessary hostName
roryabraham Jul 27, 2023
aa27f70
Merge branch 'main' into Rory-MigrateDragNDrop
roryabraham Jul 27, 2023
da885c4
Create useDragAndDrop hook to DRY things up
roryabraham Jul 27, 2023
ebfb46c
Add missing JSDoc
roryabraham Jul 27, 2023
d510e1e
useDragAndDrop in NoDropZone
roryabraham Jul 27, 2023
d140024
Fix ref inconsistencies which were making listeners get unsubscribed
roryabraham Jul 27, 2023
be377db
Fix click events in the drop zone
roryabraham Jul 27, 2023
f0685c3
Fix lint
roryabraham Jul 27, 2023
c6fa4fa
Merge branch 'main' into Rory-MigrateDragNDrop
roryabraham Jul 27, 2023
4373de1
Fix tests
roryabraham Jul 27, 2023
8a4dcf5
Add comment in mock
roryabraham Jul 27, 2023
834791e
Rename DNDUtils to DragAndDropUtils
roryabraham Jul 27, 2023
578c22b
Remove subscriber optimization
roryabraham Jul 28, 2023
ca84268
Fix lint
roryabraham Jul 28, 2023
8a028bb
Simplify context implementation
roryabraham Jul 28, 2023
0e90a13
Remove unused DragAndDropUtils
roryabraham Jul 28, 2023
8972845
Remove unused constant
roryabraham Jul 28, 2023
8711b49
fix lint
roryabraham Jul 28, 2023
cce276f
onDropHandler not onDropListener
roryabraham Jul 28, 2023
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
3 changes: 2 additions & 1 deletion .storybook/preview.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import Onyx from 'react-native-onyx';
import {SafeAreaProvider} from 'react-native-safe-area-context';
import {PortalProvider} from '@gorhom/portal';
import './fonts.css';
import ComposeProviders from '../src/components/ComposeProviders';
import HTMLEngineProvider from '../src/components/HTMLEngineProvider';
Expand All @@ -14,7 +15,7 @@ Onyx.init({

const decorators = [
(Story) => (
<ComposeProviders components={[OnyxProvider, LocaleContextProvider, HTMLEngineProvider, SafeAreaProvider]}>
<ComposeProviders components={[OnyxProvider, LocaleContextProvider, HTMLEngineProvider, SafeAreaProvider, PortalProvider]}>
<Story />
</ComposeProviders>
),
Expand Down
1 change: 1 addition & 0 deletions .storybook/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ module.exports = ({config}) => {
'react-native$': '@expensify/react-native-web',
'react-native-web': '@expensify/react-native-web',
'@react-native-community/netinfo': path.resolve(__dirname, '../__mocks__/@react-native-community/netinfo.js'),
'@react-navigation/native': path.resolve(__dirname, '../__mocks__/@react-navigation/native'),
};

// Necessary to overwrite the values in the existing DefinePlugin hardcoded to the Config staging values
Expand Down
8 changes: 8 additions & 0 deletions __mocks__/@react-navigation/native/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {useIsFocused as realUseIsFocused} from '@react-navigation/native';

// We only want this mocked for storybook, not jest
const useIsFocused = process.env.NODE_ENV === 'test' ? realUseIsFocused : () => true;

export * from '@react-navigation/core';
export * from '@react-navigation/native';
export {useIsFocused};
Comment thread
roryabraham marked this conversation as resolved.
3 changes: 0 additions & 3 deletions src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -480,9 +480,6 @@ const CONST = {
PERSONAL_DETAIL: 'personalDetail',
},
REPORT: {
DROP_HOST_NAME: 'ReportDropZone',
DROP_NATIVE_ID: 'report-dropzone',
ACTIVE_DROP_NATIVE_ID: 'report-dropzone',
MAXIMUM_PARTICIPANTS: 8,
SPLIT_REPORTID: '-2',
ACTIONS: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import PropTypes from 'prop-types';

export default {
/** Children to render inside this component. */
children: PropTypes.node.isRequired,

/** Function to execute when an item is dropped in the drop zone. */
onDrop: PropTypes.func.isRequired,
};
23 changes: 23 additions & 0 deletions src/components/DragAndDrop/Consumer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React, {useContext, useEffect} from 'react';
import {Portal} from '@gorhom/portal';
import dragAndDropConsumerPropTypes from './dragAndDropConsumerPropTypes';
import {DragAndDropContext} from '../Provider';

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

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

if (!isDraggingOver) {
return null;
}

return <Portal hostName={dropZoneID}>{children}</Portal>;
}

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

export default DragAndDropConsumer;
10 changes: 10 additions & 0 deletions src/components/DragAndDrop/Consumer/index.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import dragAndDropConsumerPropTypes from './dragAndDropConsumerPropTypes';

function DragAndDropConsumer({children}) {
return children;
}

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

export default DragAndDropConsumer;
34 changes: 0 additions & 34 deletions src/components/DragAndDrop/DropZone/index.js

This file was deleted.

5 changes: 0 additions & 5 deletions src/components/DragAndDrop/DropZone/index.native.js

This file was deleted.

37 changes: 18 additions & 19 deletions src/components/DragAndDrop/NoDropZone/index.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
import {useEffect} from 'react';
import React, {useRef} from 'react';
import {View} from 'react-native';
import PropTypes from 'prop-types';
import styles from '../../../styles/styles';
import useDragAndDrop from '../../../hooks/useDragAndDrop';

const propTypes = {
/** Content */
children: PropTypes.node.isRequired,
};

function NoDropZone(props) {
function handleDrag(event) {
event.preventDefault();
// eslint-disable-next-line no-param-reassign
event.dataTransfer.dropEffect = 'none';
}

useEffect(() => {
document.addEventListener('dragenter', handleDrag);
document.addEventListener('dragover', handleDrag);

return () => {
document.removeEventListener('dragenter', handleDrag);
document.removeEventListener('dragover', handleDrag);
};
}, []);

return props.children;
function NoDropZone({children}) {
const noDropZone = useRef(null);
useDragAndDrop({
dropZone: noDropZone,
shouldAllowDrop: false,
});
return (
<View

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The wrapping View caused this. When creating a new workspace in ThreePaneView component, props.state.routes still contains NAVIGATORS.RIGHT_MODAL_NAVIGATOR route. This causes the App to be wrapped in NoDropZone even after RHN is closed.
Mentioning it here so that it remains documented.

ref={(e) => (noDropZone.current = e)}
style={[styles.fullScreen]}
>
{children}
</View>
);
}

NoDropZone.displayName = 'NoDropZone';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import PropTypes from 'prop-types';

export default {
/** Children to render inside this component. */
children: PropTypes.node.isRequired,

/** Should this dropZone be disabled? */
isDisabled: PropTypes.bool,
};
57 changes: 57 additions & 0 deletions src/components/DragAndDrop/Provider/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import _ from 'underscore';
import React, {useRef, useCallback} from 'react';
import {View} from 'react-native';
import {PortalHost} from '@gorhom/portal';
import Str from 'expensify-common/lib/str';
import dragAndDropProviderPropTypes from './dragAndDropProviderPropTypes';
import styles from '../../../styles/styles';
import useDragAndDrop from '../../../hooks/useDragAndDrop';

const DragAndDropContext = React.createContext({});

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

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

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

const {isDraggingOver} = useDragAndDrop({
dropZone,
onDrop: onDropHandler.current,
shouldAcceptDrop,
isDisabled,
});

return (
<DragAndDropContext.Provider value={{isDraggingOver, setOnDropHandler, dropZoneID: dropZoneID.current}}>
<View
ref={(e) => (dropZone.current = e)}
style={[styles.flex1, styles.w100, styles.h100]}
Comment thread
roryabraham marked this conversation as resolved.
>
{isDraggingOver && (
<View style={[styles.fullScreen, styles.invisibleOverlay]}>
<PortalHost name={dropZoneID.current} />
</View>
)}
{children}
</View>
</DragAndDropContext.Provider>
);
}

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

export default DragAndDropProvider;
export {DragAndDropContext};
13 changes: 13 additions & 0 deletions src/components/DragAndDrop/Provider/index.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import dragAndDropProviderPropTypes from './dragAndDropProviderPropTypes';

const DragAndDropContext = {};

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

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

export default DragAndDropProvider;
export {DragAndDropContext};
24 changes: 0 additions & 24 deletions src/components/DragAndDrop/dragAndDropPropTypes.js

This file was deleted.

Loading