Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial release, with demo and tests
- Loading branch information
1 parent
76ccd99
commit 75b3b47
Showing
18 changed files
with
804 additions
and
1 deletion.
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 @@ | ||
**/*-bundle.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,30 @@ | ||
{ | ||
"env": { | ||
"node": true, | ||
"browser": true | ||
}, | ||
"ecmaFeatures": { | ||
"jsx": true, | ||
}, | ||
"rules": { | ||
"comma-dangle": [2, "always-multiline"], | ||
"curly": 0, | ||
"radix": 2, | ||
"wrap-iife": 2, | ||
"brace-style": 0, | ||
"comma-style": 2, | ||
"consistent-this": 0, | ||
"indent": [2, 2, { | ||
"SwitchCase": 1 | ||
}], | ||
"no-lonely-if": 2, | ||
"no-nested-ternary": 2, | ||
"no-use-before-define": [2, "nofunc"], | ||
"quotes": [2, "single"], | ||
"space-before-function-paren": [2, "never"], | ||
"space-after-keywords": [2, "always"], | ||
"space-before-blocks": [2, "always"], | ||
"space-in-parens": [2, "never"], | ||
"space-unary-ops": 2, | ||
} | ||
} |
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,3 @@ | ||
node_modules | ||
*.log | ||
**/*-bundle.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,3 @@ | ||
language: node_js | ||
node_js: | ||
- "0.12" |
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,3 @@ | ||
# 1.0.0 | ||
|
||
- Initial release. |
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,2 +1,112 @@ | ||
# react-displace | ||
A higher order component that displaces your component into a remote region of the DOM | ||
|
||
A higher order component that displaces *your* component into a remote region of the DOM. When your component mounts, it renders to the `document.body` or to any other arbitrary DOM node, instead of it's expected place within its React component tree; but it still maintains its normal life cycle within the tree, mounting, updating, and unmounting as expected. | ||
|
||
This is useful when the HTML source order enforced by React's component tree won't serve your purposes. | ||
|
||
For example, if initialization and props for a modal or an obstructive overlay (e.g. "Loading...") will come from some component deeply nested within you app, but you want to render the modal or overlay as a direct child of `document.body` so that you can easily `position` it and set its `z-index`. | ||
|
||
## Installation | ||
|
||
``` | ||
npm install react-displace | ||
``` | ||
|
||
## Usage | ||
|
||
react-displace is a "higher order component": a function that takes your component as an argument and returns a new component that includes your component wrapped in some special functionality. | ||
|
||
It has a simple signature | ||
|
||
```js | ||
displace(YourComponent[, options]) | ||
``` | ||
|
||
### Options | ||
|
||
#### renderTo | ||
|
||
Type: DOM node or string selector | ||
|
||
By default, the displaced component is appended to a new `<div>` attached directly to `document.body`. If instead you would like to specify a node that the component should be displaced to, do that with `renderTo`. | ||
|
||
If `renderTo` is a DOM node, the displaced component will be rendered there. | ||
|
||
If `renderTo` is a selector string, it is passed to `document.querySelector()`, and the displaced component will be rendered to that result. | ||
|
||
### Example | ||
|
||
```js | ||
var React = require('react'); | ||
var displace = require('react-displace'); | ||
|
||
var Foo = React.createClass({ .. }); | ||
var FooDisplacedToBody = displace(Foo); | ||
var FooDisplacedToBar = displace(Foo, document.getElementById('bar')); | ||
var FooDisplacedToBaz = displace(Foo, '#baz'); | ||
``` | ||
|
||
In the example above, you can use any `FooDisplacedTo*` exactly as you would use `Foo`; and any `props` you provide to `FooDisplacedTo*` will be passed through to its internal `Foo` component. (e.g. If `Foo` has a `prop` called `severity`, so does `FooDisplacedTo*`.) | ||
|
||
The only differences are that all of the `FooDisplacedTo*` components will be rendered to some special place in the DOM, instead of being inserted wherever it is used within the React component tree. | ||
- `FooDisplacedToBody` will be rendered into a new `<div>` appended directly to `document.body`, | ||
- `FooDisplacedToBar` and `FooDisplacedToBaz` will be appended into their designated containers. | ||
|
||
The `FooDisplacedTo*` components will also have an additional `prop`: `mounted`. The `mounted` prop can be used to declare whether the component should be rendered or not — which can also be done by actually mounting and unmounting the component. | ||
|
||
So let's say you have the following HTML: | ||
|
||
```html | ||
<div id="app-container"></div> | ||
<div id="bar"></div> | ||
<div id="baz"></div> | ||
``` | ||
|
||
And you have something like the following JS: | ||
|
||
```js | ||
var React = require('react'); | ||
var displace = require('react-displace'); | ||
|
||
var Foo = React.createClass({ .. }); | ||
var FooDisplacedToBody = displace(Foo); | ||
var FooDisplacedToBar = displace(Foo, document.getElementById('bar')); | ||
var FooDisplacedToBaz = displace(Foo, '#baz'); | ||
|
||
var App = React.createClass({ | ||
.. | ||
render: function() { | ||
return ( | ||
<div id="rendered-app"> | ||
<Foo text='in my normal place' /> | ||
<FooDisplacedToBody text='displaced to body' /> | ||
<FooDisplacedToBar text='displaced to bar' /> | ||
<FooDisplacedToBaz text='displaced to baz' /> | ||
</div> | ||
); | ||
}, | ||
}) | ||
``` | ||
|
||
What ends up rendering should look something like this: | ||
|
||
```html | ||
<div id="app-container"> | ||
<div id="rendered-app"> | ||
<div>in my normal place</div> | ||
</div> | ||
</div> | ||
<div id="bar"> | ||
<div>displaced to bar</div> | ||
</div> | ||
<div id="baz"> | ||
<div>displaced to baz</div> | ||
</div> | ||
<div> | ||
<div>displaced to body</div> | ||
</div> | ||
``` | ||
|
||
## Caveats | ||
|
||
I don't think `React.findDOMNode()` always works on the displaced element — which is not surprising. |
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,85 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta http-equiv="x-ua-compatible" content="ie=edge"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<title>react-displace demo</title> | ||
|
||
<link rel="stylesheet" href="style.css"> | ||
<meta name="description" content="A demo of react-displace"> | ||
</head> | ||
<body> | ||
|
||
<h1> | ||
react-displace demo | ||
</h1> | ||
|
||
<p> | ||
react-displace is a higher order function that makes any given React component render into the document's <code>body</code> or some other arbitrary DOM node instead of into its normal place within the React element tree. | ||
</p> | ||
|
||
<p> | ||
<span style='font-size:2em;vertical-align:middle;'>☜</span> | ||
<a href="https://github.com/davidtheclark/react-displace" style='vertical-align:middle;'>Return to the repository.</a> | ||
</p> | ||
|
||
<div class="container"> | ||
<h2> | ||
React apps are attached within here | ||
</h2> | ||
<p> | ||
But you'll see that they control (mount, unmount, and update the state of) React elements <em>outside</em> this DOM node. | ||
</p> | ||
<div class="container"> | ||
<h3> | ||
Demo One | ||
</h3> | ||
<p> | ||
This displaced element should appear at the bottom of the page. | ||
</p> | ||
<div id="demo-one"></div> | ||
</div> | ||
<div class="container"> | ||
<h3> | ||
Demo Two | ||
</h3> | ||
<p> | ||
This displaced element should appear in the Demo Two Displacement Container. | ||
</p> | ||
<div id="demo-two"></div> | ||
</div> | ||
<div class="container"> | ||
<h3> | ||
Demo Three | ||
</h3> | ||
<p> | ||
This displaced element should appear in the Demo Three Displacement Container. | ||
</p> | ||
<div id="demo-three"></div> | ||
</div> | ||
</div> | ||
|
||
<div class="container"> | ||
<h2> | ||
Demo Two Displacement Container | ||
</h2> | ||
<p> | ||
demo-two's displaced element will be attached in here | ||
</p> | ||
<div id="demo-two-displaced"></div> | ||
</div> | ||
|
||
<div class="container"> | ||
<h2> | ||
Demo Three Displacement Container | ||
</h2> | ||
<p> | ||
demo-three's displaced element will be attached in here | ||
</p> | ||
<div id="demo-three-displaced"></div> | ||
</div> | ||
|
||
<script src="demo-bundle.js"></script> | ||
</body> | ||
</html> |
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,61 @@ | ||
var React = require('react'); | ||
var displace = require('../../'); | ||
|
||
var AppendedToBody = displace(React.createClass({ | ||
propTypes: { | ||
number: React.PropTypes.number.isRequired, | ||
}, | ||
|
||
render: function() { | ||
return ( | ||
<div className='container'> | ||
<h2> | ||
Demo One's Displaced Element | ||
</h2> | ||
<p> | ||
I'm appended to the body rather than my parent React element. | ||
</p> | ||
<p> | ||
And I still update correctly. | ||
You've clicked "increment demo-one displaced number" {this.props.number} time(s). | ||
</p> | ||
</div> | ||
) | ||
}, | ||
})); | ||
|
||
var DemoOne = React.createClass({ | ||
getInitialState: function() { | ||
return { | ||
displacedNumber: 0, | ||
displacedMounted: false, | ||
}; | ||
}, | ||
|
||
toggleDisplaced: function() { | ||
this.setState({ displacedMounted: !this.state.displacedMounted }); | ||
}, | ||
|
||
incrementDisplaced: function() { | ||
this.setState({ displacedNumber: this.state.displacedNumber + 1 }); | ||
}, | ||
|
||
render: function() { | ||
return ( | ||
<div> | ||
<button onClick={this.toggleDisplaced}> | ||
toggle demo-one displaced | ||
</button> | ||
<button onClick={this.incrementDisplaced}> | ||
increment demo-one displaced number | ||
</button> | ||
<AppendedToBody | ||
number={this.state.displacedNumber} | ||
mounted={this.state.displacedMounted} | ||
/> | ||
</div> | ||
); | ||
}, | ||
}); | ||
|
||
React.render(<DemoOne />, document.getElementById('demo-one')); |
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,65 @@ | ||
var React = require('react'); | ||
var displace = require('../../'); | ||
|
||
var AppendedToNodeInner = React.createClass({ | ||
propTypes: { | ||
number: React.PropTypes.number.isRequired, | ||
}, | ||
|
||
render: function() { | ||
return ( | ||
<div className='container'> | ||
<h3> | ||
Demo Three's Displaced Element | ||
</h3> | ||
<p> | ||
I'm appended to a specific node that is passed as a node (not selector string). | ||
</p> | ||
<p> | ||
And I still update correctly. | ||
You've clicked "increment demo-three displaced number" {this.props.number} time(s). | ||
</p> | ||
</div> | ||
) | ||
}, | ||
}); | ||
|
||
var AppendedToNode = displace(AppendedToNodeInner, { | ||
renderTo: document.getElementById('demo-three-displaced'), | ||
}); | ||
|
||
var DemoThree = React.createClass({ | ||
getInitialState: function() { | ||
return { | ||
displacedNumber: 0, | ||
displacedMounted: false, | ||
}; | ||
}, | ||
|
||
toggleDisplaced: function() { | ||
this.setState({ displacedMounted: !this.state.displacedMounted }); | ||
}, | ||
|
||
incrementDisplaced: function() { | ||
this.setState({ displacedNumber: this.state.displacedNumber + 1 }); | ||
}, | ||
|
||
render: function() { | ||
return ( | ||
<div> | ||
<button onClick={this.toggleDisplaced}> | ||
toggle demo-three displaced | ||
</button> | ||
<button onClick={this.incrementDisplaced}> | ||
increment demo-three displaced number | ||
</button> | ||
<AppendedToNode | ||
number={this.state.displacedNumber} | ||
mounted={this.state.displacedMounted} | ||
/> | ||
</div> | ||
); | ||
}, | ||
}); | ||
|
||
React.render(<DemoThree />, document.getElementById('demo-three')); |
Oops, something went wrong.