Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding a React Component for establishing Context via React Trees [v2] (
#632) * Add DragDropContextProvider React Class * Correct PropTypes, inject document via ContextType * Remave getDocument method, get window directly from context instead of through document * Remove react-dom include * Avoid using variable names that shadow browser globals * Update Documentation with Simple iframe Example * Add some more detail to the iframe exmaple * Correct linting issue * Update the container in the iframe example to reference components from the simple example * Add documentation to the DragDropContextProvider
- Loading branch information
1 parent
919da76
commit 1153d82
Showing
12 changed files
with
294 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
*New to React DnD? [Read the overview](docs-overview.html) before jumping into the docs.* | ||
|
||
DragDropContextProvider | ||
========================= | ||
|
||
As an alternative to the DragDropContext, you can use the DragDropContextProvider element | ||
to set up React DnD for your application. Similar to the DragDropContext, this may be | ||
injected with a backend via the `backend` prop, but it also can be injected with a `window` object. | ||
|
||
### Usage | ||
|
||
------------------- | ||
```js | ||
var HTML5Backend = require('react-dnd-html5-backend'); | ||
var DragDropContextProvider = require('react-dnd').DragDropContextProvider; | ||
|
||
var YourApp = React.createClass( | ||
render() { | ||
return ( | ||
<DragDropContextProvider backend={HTML5Backend}> | ||
/* ... */ | ||
</DragDropContextProvider> | ||
); | ||
}; | ||
); | ||
|
||
module.exports = YourApp; | ||
``` | ||
------------------- | ||
```js | ||
import HTML5Backend from 'react-dnd-html5-backend'; | ||
import { DragDropContextProvider } from 'react-dnd'; | ||
|
||
export default class YourApp { | ||
render() { | ||
return ( | ||
<DragDropContextProvider backend={HTML5Backend}> | ||
/* ... */ | ||
</DragDropContextProvider> | ||
); | ||
}; | ||
} | ||
|
||
``` | ||
------------------- | ||
```js | ||
import HTML5Backend from 'react-dnd-html5-backend'; | ||
import { DragDropContextProvider } from 'react-dnd'; | ||
|
||
export default class YourApp { | ||
render() { | ||
return ( | ||
<DragDropContextProvider backend={HTML5Backend}> | ||
/* ... */ | ||
</DragDropContextProvider> | ||
); | ||
}; | ||
} | ||
``` | ||
------------------- | ||
|
||
### Props | ||
|
||
* **`backend`**: Required. A React DnD backend. Unless you're writing a custom one, you probably want to use the [HTML5 backend](docs-html5-backend.html) that ships with React DnD. | ||
* **`window`**: Optional. The window object used for establishing subscriptions in the HTML5 Backend. This is mainly for iframe support. | ||
|
||
### Injecting a Window Instance (optional) | ||
In order to support iframes, we need to be able to inject the window we're subscribing for events in into the HTML5 Backend. You can do this in a couple of ways. | ||
|
||
* Via the `window` prop. This has the highest precedent for determining the window to use. | ||
* Via the `window` context value. This has the next higest precedent. | ||
|
||
If neither of these arguments are present, then the global `window` variable is used. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import React, { Component } from 'react'; | ||
import { DragDropContextProvider } from 'react-dnd'; | ||
import HTML5Backend from 'react-dnd-html5-backend'; | ||
import Frame from 'react-frame-component'; | ||
import Dustbin from '../Single Target/Dustbin'; | ||
import Box from '../Single Target/Box'; | ||
|
||
// Don't use the decorator, embed the DnD context within the iframe | ||
export default class Container extends Component { | ||
render() { | ||
// The react-frame-component will pass the iframe's 'window' global as a context value | ||
// to the DragDropContext provider. You could also directly inject it in via a prop. | ||
// If neither the prop or the context value for 'window' are present, the DragDropContextProvider | ||
// will just use the global window. | ||
return ( | ||
<Frame style={{ width: '100%', height: '100%' }}> | ||
<DragDropContextProvider backend={HTML5Backend}> | ||
<div> | ||
<div style={{ overflow: 'hidden', clear: 'both' }}> | ||
<Dustbin /> | ||
</div> | ||
<div style={{ overflow: 'hidden', clear: 'both' }}> | ||
<Box name="Glass" /> | ||
<Box name="Banana" /> | ||
<Box name="Paper" /> | ||
</div> | ||
</div> | ||
</DragDropContextProvider> | ||
</Frame> | ||
); | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
examples/01 Dustbin/Single Target in iframe/__tests__/Box-test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import React from 'react'; | ||
import TestUtils from 'react-addons-test-utils'; | ||
import expect from 'expect'; | ||
import wrapInTestContext from '../../../shared/wrapInTestContext'; | ||
import Box from '../Box'; | ||
|
||
describe('Box', () => { | ||
it('can be tested independently', () => { | ||
// Obtain the reference to the component before React DnD wrapping | ||
const OriginalBox = Box.DecoratedComponent; | ||
|
||
// Stub the React DnD connector functions with an identity function | ||
const identity = x => x; | ||
|
||
// Render with one set of props and test | ||
let root = TestUtils.renderIntoDocument( | ||
<OriginalBox | ||
name="test" | ||
connectDragSource={identity} | ||
isDragging={false} | ||
/>, | ||
); | ||
let div = TestUtils.findRenderedDOMComponentWithTag(root, 'div'); | ||
expect(div.style.opacity).toEqual('1'); | ||
|
||
// Render with another set of props and test | ||
root = TestUtils.renderIntoDocument( | ||
<OriginalBox | ||
name="test" | ||
connectDragSource={identity} | ||
isDragging | ||
/>, | ||
); | ||
div = TestUtils.findRenderedDOMComponentWithTag(root, 'div'); | ||
expect(div.style.opacity).toEqual('0.4'); | ||
}); | ||
|
||
it('can be tested with the testing backend', () => { | ||
// Render with the testing backend | ||
const BoxContext = wrapInTestContext(Box); | ||
const root = TestUtils.renderIntoDocument(<BoxContext name="test" />); | ||
|
||
// Obtain a reference to the backend | ||
const backend = root.getManager().getBackend(); | ||
|
||
// Check that the opacity is 1 | ||
let div = TestUtils.findRenderedDOMComponentWithTag(root, 'div'); | ||
expect(div.style.opacity).toEqual('1'); | ||
|
||
// Find the drag source ID and use it to simulate the dragging state | ||
const box = TestUtils.findRenderedComponentWithType(root, Box); | ||
backend.simulateBeginDrag([box.getHandlerId()]); | ||
|
||
// Verify that the div changed its opacity | ||
div = TestUtils.findRenderedDOMComponentWithTag(root, 'div'); | ||
expect(div.style.opacity).toEqual('0.4'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import React, { Component } from 'react'; | ||
import Container from './Container'; | ||
|
||
export default class DustbinSingleTargetIframe extends Component { | ||
render() { | ||
return ( | ||
<div> | ||
<p> | ||
<b><a href="https://github.com/react-dnd/react-dnd/tree/master/examples/01%20Dustbin/Single%20Target%20in%20iframe">Browse the Source</a></b> | ||
</p> | ||
<p> | ||
This is the same simple example, but nested in an iframe. | ||
</p> | ||
<p> | ||
When you are using the react-dnd-html5-backend, you are limited to drag-and-drop within a single iframe. | ||
</p> | ||
<p> | ||
Using react-dnd inside of an iframe requires a slightly different | ||
container configuration. Check out the source for more details. | ||
</p> | ||
<Container /> | ||
</div> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,24 @@ | ||
import React, { Component } from 'react'; | ||
import { DragDropContext } from 'react-dnd'; | ||
import { DragDropContextProvider } from 'react-dnd'; | ||
import HTML5Backend from 'react-dnd-html5-backend'; | ||
import Dustbin from './Dustbin'; | ||
import Box from './Box'; | ||
|
||
@DragDropContext(HTML5Backend) | ||
export default class Container extends Component { | ||
render() { | ||
return ( | ||
<div> | ||
<div style={{ overflow: 'hidden', clear: 'both' }}> | ||
<Dustbin /> | ||
<DragDropContextProvider backend={HTML5Backend}> | ||
<div> | ||
<div style={{ overflow: 'hidden', clear: 'both' }}> | ||
<Dustbin /> | ||
</div> | ||
<div style={{ overflow: 'hidden', clear: 'both' }}> | ||
<Box name="Glass" /> | ||
<Box name="Banana" /> | ||
<Box name="Paper" /> | ||
</div> | ||
</div> | ||
<div style={{ overflow: 'hidden', clear: 'both' }}> | ||
<Box name="Glass" /> | ||
<Box name="Banana" /> | ||
<Box name="Paper" /> | ||
</div> | ||
</div> | ||
</DragDropContextProvider> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { PropTypes, Component, Children } from 'react'; | ||
import { | ||
CHILD_CONTEXT_TYPES, | ||
createChildContext, | ||
unpackBackendForEs5Users, | ||
} from './DragDropContext'; | ||
|
||
/** | ||
* This class is a React-Component based version of the DragDropContext. | ||
* This is an alternative to decorating an application component with an ES7 decorator. | ||
*/ | ||
export default class DragDropContextProvider extends Component { | ||
static propTypes = { | ||
backend: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired, | ||
children: PropTypes.element.isRequired, | ||
window: PropTypes.object, // eslint-disable-line react/forbid-prop-types | ||
}; | ||
|
||
static defaultProps = { | ||
window: undefined, | ||
}; | ||
|
||
static childContextTypes = CHILD_CONTEXT_TYPES; | ||
|
||
static displayName = 'DragDropContextProvider'; | ||
|
||
static contextTypes = { | ||
window: PropTypes.object, | ||
}; | ||
|
||
constructor(props, context) { | ||
super(props, context); | ||
this.backend = unpackBackendForEs5Users(props.backend); | ||
} | ||
|
||
getChildContext() { | ||
/** | ||
* This property determines which window global to use for creating the DragDropManager. | ||
* If a window has been injected explicitly via props, that is used first. If it is available | ||
* as a context value, then use that, otherwise use the browser global. | ||
*/ | ||
const getWindow = () => { | ||
if (this.props && this.props.window) { | ||
return this.props.window; | ||
} else if (this.context && this.context.window) { | ||
return this.context.window; | ||
} | ||
return window; | ||
}; | ||
|
||
return createChildContext(this.backend, { window: getWindow() }); | ||
} | ||
|
||
render() { | ||
return Children.only(this.props.children); | ||
} | ||
} |
Oops, something went wrong.