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

Add option for Dropzone without context (bring-your-own non-HTML5 context) #56

Merged
merged 10 commits into from
Dec 24, 2018
Merged
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,37 @@ import Dropzone from 'react-dnd-dropzone';
/>;
```

With custom React-dnd context (PR [#56](https://github.com/evenchange4/react-dnd-dropzone/pull/56) by [@smallfx](https://github.com/smallfx)).

```js
import * as React from 'react';
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import { DropTarget, Target } from 'react-dnd-dropzone';

const HTML5DropContext = DragDropContext(HTML5Backend)(({ children }) => (
<div>{children}</div>
));
const Dropzone = DropTarget(Target);

const App = () => (
<HTML5DropContext>
<Dropzone
onDrop={files => console.log(files)}
render={({ canDrop, isOver }) => (
<div>
<pre>{JSON.stringify({ canDrop, isOver }, null, 2)}</pre>
</div>
)}
/>
</HTML5DropContext>
);
```

## API

```js
type Props = {
type DropzoneProps = {
onDrop: (files: Array<File>, monitor: any) => void,
render: ({ canDrop: boolean, isOver: boolean }) => React.Element<any>,
accepts?: Array<string>,
Expand Down
20 changes: 20 additions & 0 deletions src/DropTarget.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @flow
import { DropTarget } from 'react-dnd';
import { NativeTypes } from 'react-dnd-html5-backend';

export default DropTarget(
({ accepts }) => accepts || [NativeTypes.FILE],
{
drop(props, monitor) {
if (monitor) {
const { files } = monitor.getItem();
props.onDrop(files, monitor);
}
},
},
(connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}),
);
79 changes: 59 additions & 20 deletions src/Dropzone.example.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,64 @@
import * as React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import Dropzone from '.';
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import Dropzone, { DropTarget, Target } from '.';

storiesOf('Dropzone', module).add(
'Basic',
() => (
<Dropzone
onDrop={files => action('onDrop')(files)}
render={({ canDrop, isOver }) => (
<div style={{ border: '1px dashed black', height: 200 }}>
Drop file here!
<pre>{JSON.stringify({ canDrop, isOver }, null, 2)}</pre>
</div>
)}
/>
),
{
info: {
text: `API: https://github.com/evenchange4/react-dnd-dropzone#api`,
inline: true,
storiesOf('Dropzone', module)
.add(
'Basic',
() => (
<Dropzone
onDrop={files => action('onDrop')(files)}
render={({ canDrop, isOver }) => (
<div style={{ border: '1px dashed black', height: 200 }}>
Drop file here!
<pre>{JSON.stringify({ canDrop, isOver }, null, 2)}</pre>
</div>
)}
/>
),
{
info: {
text: `API: https://github.com/evenchange4/react-dnd-dropzone#api`,
inline: true,
source: false,
propTables: [Dropzone],
},
},
},
);
)
.add(
'Custom context',
() => {
const HTML5DropContext: React.StatelessFunctionalComponent<Object> = DragDropContext(
HTML5Backend,
)(({ children }) => <div>{children}</div>);
const DropzoneWithoutContext = DropTarget(Target);

return (
<HTML5DropContext>
<DropzoneWithoutContext
onDrop={files => action('onDrop')(files)}
render={({ canDrop, isOver }) => (
<div style={{ border: '1px dashed black', height: 200 }}>
(Without built-in <code>HTML5Backend</code> context)
<br />
<br />
Drop file here!
<pre>{JSON.stringify({ canDrop, isOver }, null, 2)}</pre>
</div>
)}
/>
</HTML5DropContext>
);
},
{
info: {
text: `API: https://github.com/evenchange4/react-dnd-dropzone#api`,
inline: true,
source: false,
propTables: [DropTarget, Target],
},
},
);
50 changes: 6 additions & 44 deletions src/Dropzone.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,22 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { compose } from 'recompose';
import {
DropTarget,
DragDropContext,
DragDropContextProvider,
} from 'react-dnd';
import HTML5Backend, { NativeTypes } from 'react-dnd-html5-backend';

export const Target = ({
canDrop,
isOver,
connectDropTarget,
render,
}: {
// Note: from react-dnd hoc
canDrop: boolean,
isOver: boolean,
connectDropTarget: Function,
// Note: render props
render: ({ canDrop: boolean, isOver: boolean }) => React.Element<any>,
}) => (
<DragDropContextProvider backend={HTML5Backend}>
{connectDropTarget(<div>{render({ canDrop, isOver })}</div>)}
</DragDropContextProvider>
);
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import Target from './Target';
import DropTarget from './DropTarget';

export type Props = {
onDrop: (files: Array<File>, monitor: any) => void | Promise<void>,
render: ({ canDrop: boolean, isOver: boolean }) => React.Element<any>,
accepts?: Array<string>,
};

export const Dropzone: React.StatelessFunctionalComponent<Props> = compose(
const Dropzone: React.StatelessFunctionalComponent<Props> = compose(
DragDropContext(HTML5Backend),
DropTarget(
({ accepts }) => accepts || [NativeTypes.FILE],
{
drop(props, monitor) {
if (monitor) {
const { files } = monitor.getItem();
props.onDrop(files, monitor);
}
},
},
(connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}),
),
DropTarget,
)(Target);

/**
* For react-storybook addon info
*/
Dropzone.displayName = 'ReactDndDropzone';
Dropzone.propTypes = {
onDrop: PropTypes.func.isRequired,
Expand Down
26 changes: 26 additions & 0 deletions src/Target.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// @flow
import * as React from 'react';
import { DragDropContextProvider } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';

export type Props = {
// Note: from react-dnd hoc
canDrop: boolean,
isOver: boolean,
connectDropTarget: Function,
// Note: render props
render: ({ canDrop: boolean, isOver: boolean }) => React.Element<any>,
};

export const Target = ({
canDrop,
isOver,
connectDropTarget,
render,
}: Props) => (
<DragDropContextProvider backend={HTML5Backend}>
{connectDropTarget(<div>{render({ canDrop, isOver })}</div>)}
</DragDropContextProvider>
);

export default Target;
51 changes: 51 additions & 0 deletions src/__snapshots__/Dropzone.example.storyshot
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,54 @@ exports[`Storyshots Dropzone Basic 1`] = `
</DropTarget(Target)>
</ReactDndDropzone>
`;

exports[`Storyshots Dropzone Custom context 1`] = `
<DragDropContext(Component)>
<Component>
<div>
<DropTarget(Target)
onDrop={[Function]}
render={[Function]}
>
<Target
canDrop={false}
connectDropTarget={[Function]}
isOver={false}
onDrop={[Function]}
render={[Function]}
>
<Component
backend={[Function]}
>
<div>
<div
style={
Object {
"border": "1px dashed black",
"height": 200,
}
}
>
(Without built-in
<code>
HTML5Backend
</code>
context)
<br />
<br />
Drop file here!
<pre>
{
"canDrop": false,
"isOver": false
}
</pre>
</div>
</div>
</Component>
</Target>
</DropTarget(Target)>
</div>
</Component>
</DragDropContext(Component)>
`;
14 changes: 14 additions & 0 deletions src/__tests__/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// @flow
import * as Modules from '../index';

it('should export Target Component', () => {
expect(Modules).toHaveProperty('Target');
});

it('should export DropTarget HOC', () => {
expect(Modules).toHaveProperty('DropTarget');
});

it('should export default Dropzone component', () => {
expect(Modules).toHaveProperty('default');
});
5 changes: 4 additions & 1 deletion src/__tests__/storyshots.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ initStoryshots({
const converter = new Stories2SnapsConverter();
const snapshotFileName = converter.getSnapshotFileName(context);
const storyElement = story.render(context);
const tree = mount(storyElement)
const root = mount(storyElement);
const tree = root
.find('#snapshot')
.children()
.first();
Expand All @@ -23,5 +24,7 @@ initStoryshots({
// Remind: property `toMatchSpecificSnapshot`. Property not found in Jest flowtype
(expect(json): any).toMatchSpecificSnapshot(snapshotFileName);
}

root.unmount();
},
});
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
// @flow
export { default } from './Dropzone';

export { default as Target } from './Target';
export { default as DropTarget } from './DropTarget';