UNPKG

10.5 kBMarkdownView Raw
1# React DnD Multi Backend [![NPM Version][npm-image]][npm-url] [![dependencies Status][deps-image]][deps-url] [![devDependencies Status][deps-dev-image]][deps-dev-url]
2
3[Try it here!](https://louisbrunner.github.io/dnd-multi-backend/examples/react-dnd-multi-backend.html)
4
5This project is a Drag'n'Drop backend compatible with [React DnD](https://github.com/react-dnd/react-dnd).
6It enables your application to use different DnD backends depending on the situation.
7You can either generate your own backend pipeline or use the default one (`HTML5toTouch`).
8
9[HTML5toTouch](src/HTML5toTouch.js) starts by using the [React DnD HTML5 Backend](https://react-dnd.github.io/react-dnd/docs/backends/html5), but switches to the [React DnD Touch Backend](https://react-dnd.github.io/react-dnd/docs/backends/touch) if a touch event is triggered.
10You application can smoothly use the nice HTML5 compatible backend and fallback on the Touch one on mobile devices!
11
12Moreover, because some backends don't support preview, a `Preview` component has been added to make it easier to mock the Drag'n'Drop "ghost".
13
14See the [migration section](#migrating) for instructions when switching from `2.x.x`, `3.x.x` or `4.x.x`.
15
16
17## Installation
18
19### NPM Installation
20
21```sh
22npm install react-dnd-multi-backend
23```
24
25You can then `MultiBackend = require('react-dnd-multi-backend')` or `import MultiBackend from 'react-dnd-multi-backend'`.
26To get the `HTML5toTouch` pipeline, just require/import `react-dnd-multi-backend/dist/BUILD_TYPE/HTML5toTouch` (where `BUILD_TYPE` is either `cjs` for CommonJS or `esm` for ES Module).
27
28### Browser Installation
29
30Use the minified UMD build in the `dist` folder: https://www.jsdelivr.com/package/npm/react-dnd-multi-backend?path=dist%2Fumd.
31
32`react-dnd-multi-backend.min.js` exports a global `window.ReactDnDMultiBackend` when imported as a `<script>` tag.
33
34If you want to use the `HTML5toTouch` pipeline, also include `HTML5toTouch.min.js`.
35It exports a global `window.HTML5toTouch` when imported as a `<script>` tag.
36This file also includes the `HTML5` and `Touch` backends, so no need to include them as well.
37
38
39## Usage
40
41### Backend
42
43You can plug this backend in the `DragDropContext` the same way you do for any backend (e.g. `ReactDnDHTML5Backend`), you can see [the docs](https://react-dnd.github.io/react-dnd/docs/backends/html5) for more information.
44
45You must pass a 'pipeline' to use as argument. This package includes `HTML5toTouch`, but you can write your own.
46Note that if you include this file, you will have to add `react-dnd-html5-backend` and `react-dnd-touch-backend` to your `package.json` `dependencies`.
47
48```js
49import { DndProvider } from 'react-dnd';
50import MultiBackend from 'react-dnd-multi-backend';
51import HTML5toTouch from 'react-dnd-multi-backend/dist/esm/HTML5toTouch'; // or any other pipeline
52...
53const App = () => {
54 return (
55 <DndProvider backend={MultiBackend} options={HTML5toTouch}>
56 <Example />
57 </DndProvider>
58 );
59};
60```
61
62### Create a custom pipeline
63
64Creating a pipeline is fairly easy. A pipeline is composed of a list of backends, the first one will be the default one, loaded at the start of the **MultiBackend**, the order of the rest isn't important.
65
66Each backend entry must specify one property: `backend`, containing the class of the Backend to instantiate.
67But other options are available:
68
69 - `preview` (a boolean indicating if `Preview` components should be shown)
70 - `transition` (an object returned by the `createTransition` function)
71 - `skipDispatchOnTransition` (a boolean indicating transition events should not be dispatched to new backend, defaults to `false`. See [note below](#note-on-skipdispatchontransition) for details and use cases.)
72
73Here is the `HTML5toTouch` pipeline code as an example:
74```js
75...
76import HTML5Backend from 'react-dnd-html5-backend';
77import TouchBackend from 'react-dnd-touch-backend';
78import MultiBackend, { TouchTransition } from 'react-dnd-multi-backend';
79...
80const HTML5toTouch = {
81 backends: [
82 {
83 backend: HTML5Backend
84 },
85 {
86 backend: TouchBackend({enableMouseEvents: true}), // Note that you can call your backends with options
87 preview: true,
88 transition: TouchTransition
89 }
90 ]
91};
92...
93const App = () => {
94 return (
95 <DndProvider backend={MultiBackend} options={HTML5toTouch}>
96 <Example />
97 </DndProvider>
98 );
99};
100```
101
102`TouchTransition` is a predefined transition that you can use in your own pipelines, it is triggered when a *touchstart* is received. Transitions rea really easy to write, here is an example:
103
104```js
105import { createTransition } from 'react-dnd-multi-backend';
106
107const TouchTransition = createTransition('touchstart', (event) => {
108 return event.touches != null;
109});
110```
111
112You can also import `HTML5DragTransition` which works the same way, but detects when a HTML5 DragEvent is received.
113
114#### Note on `skipDispatchOnTransition`
115
116By default, when an event triggers a transition, `dnd-multi-backend` dispatches a cloned version of the event after setting up the new backend. This allows the newly activated backend to handle the original event.
117
118If your app code or another library has registered event listeners for the same events that are being used for transitions, this duplicate event may cause problems.
119
120You can optionally disable this behavior per backend:
121
122```js
123const CustomHTML5toTouch = {
124 backends: [
125 {
126 backend: HTML5Backend,
127 transition: MouseTransition
128 // by default, will dispatch a duplicate `mousedown` event when this backend is activated
129 },
130 {
131 backend: TouchBackend,
132 // Note that you can call your backends with options
133 options: {enableMouseEvents: true},
134 preview: true,
135 transition: TouchTransition,
136 // will not dispatch a duplicate `touchstart` event when this backend is activated
137 skipDispatchOnTransition: true
138 }
139 ]
140};
141```
142
143**WARNING:** if you enable `skipDispatchOnTransition`, the backend transition will happen as expected, but the new backend may not handle the first event!
144
145In this example, the first `touchstart` event would trigger the `TouchBackend` to replace the `HTML5Backend`—but the user would have to start a new touch event for the `TouchBackend` to register a drag.
146
147
148### Preview
149
150The `Preview` class is usable in two different ways: function-based and context-based.
151Both of them receive the same data formatted the same way, an object containing 3 properties:
152
153 - `itemType`: the type of the item (`monitor.getItemType()`)
154 - `item`: the item (`monitor.getItem()`)
155 - `style`: an object representing the style (used for positioning), it should be passed to the `style` property of your preview component
156
157Note that this component will only be showed while using a backend flagged with `preview: true` (see [Create a custom pipeline](#create-a-custom-pipeline)) which is the case for the Touch backend in the default `HTML5toTouch` pipeline.
158
159#### Function-based
160
161```js
162 import MultiBackend, { Preview } from 'react-dnd-multi-backend';
163 ...
164 const generatePreview = ({itemType, item, style}) => {
165 // render your preview
166 };
167 ...
168 <Preview generator={generatePreview} />
169 // or
170 <Preview>{generatePreview}</Preview>
171```
172
173#### Context-based
174
175```js
176 import MultiBackend, { Preview } from 'react-dnd-multi-backend';
177 ...
178 const MyPreview = () => {
179 const {itemType, item, style} = useContext(Preview.Component);
180 // render your preview
181 };
182 ...
183 <Preview>
184 <MyPreview />
185 // or
186 <Preview.Context.Consumer>
187 {({itemType, item, style}) => /* render your preview */}
188 </Preview.Context.Consumer>
189 </Preview>
190```
191
192### Examples
193
194You can see an example [here](examples/).
195
196
197## Migrating
198
199### Migrating from 2.x.x
200
201In 2.x.x, the pipeline was static but corresponded with the behavior of `HTML5toTouch`, so just [including and passing this pipeline as a parameter](#backend) would give you the same experience as before.
202
203If you used the `start` option, it's a bit different.
204With `start: 0` or `start: Backend.HTML5`, **MultiBackend** simply used the default pipeline, so you can also just pass `HTML5toTouch`.
205With `start: 1` or `start: Backend.TOUCH`, **MultiBackend** would only use the TouchBackend, so you can replace **MultiBackend** with **TouchBackend** (however, you would lose the `Preview` component) or create a simple pipeline (see [Create a custom pipeline](#create-a-custom-pipeline)) and pass it as a parameter:
206```js
207var TouchOnly = { backends: [{ backend: TouchBackend, preview: true }] };
208```
209
210### Migrating from 3.1.2
211
212Starting with `3.1.8`, the dependencies of `react-dnd-multi-backend` changed. `react`, `react-dom`, `react-dnd` become peer dependencies and you need to install them manually as `dependencies` in your project `package.json`.
213
214Note that if you use the `HTML5toTouch` pipeline, the same is true for `react-dnd-html5-backend` and `react-dnd-touch-backend`.
215
216### Migrating from 3.x.x
217
218Starting with `4.0.0`, `react-dnd-multi-backend` will start using `react-dnd` (and the corresponding backends) `9.0.0` and later.
219
220This means you need to transition from `DragDropContext(MultiBackend(HTML5toTouch))(App)` to `<DndProvider backend={MultiBackend} options={HTML5toTouch}>`.
221Accordingly, the pipeline syntax changes and you should specify backend options as a separate property, e.g. `{backend: TouchBackend({enableMouseEvents: true})}` becomes `{backend: TouchBackend, options: {enableMouseEvents: true}}`.
222Note that if you use the `HTML5toTouch` pipeline, the same is true for `react-dnd-html5-backend` and `react-dnd-touch-backend`.
223
224### Migrating from 4.x.x
225
226Starting with `5.0.0`, `react-dnd-preview` (which provides the `Preview` component) will start passing its arguments packed in one argument, an object `{itemType, item, style}`, instead of 3 different arguments (`itemType`, `item` and `style`). This means that will need to change your generator function to receive arguments correctly.
227
228
229## License
230
231MIT, Copyright (c) 2016-2019 Louis Brunner
232
233
234
235[npm-image]: https://img.shields.io/npm/v/react-dnd-multi-backend.svg
236[npm-url]: https://npmjs.org/package/react-dnd-multi-backend
237[deps-image]: https://david-dm.org/louisbrunner/react-dnd-multi-backend/status.svg
238[deps-url]: https://david-dm.org/louisbrunner/react-dnd-multi-backend
239[deps-dev-image]: https://david-dm.org/louisbrunner/react-dnd-multi-backend/dev-status.svg
240[deps-dev-url]: https://david-dm.org/louisbrunner/react-dnd-multi-backend?type=dev