Skip to content

Commit 9cc1a26

Browse files
committed
introduce the nodes property
1 parent 7ac0e97 commit 9cc1a26

File tree

2 files changed

+126
-8
lines changed

2 files changed

+126
-8
lines changed

src/ElementPortal.js

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,28 @@ import React from 'react';
33
import ReactDOM from 'react-dom';
44
import createReactClass from 'create-react-class';
55

6-
const { slice } = Array.prototype;
6+
const { push, slice } = Array.prototype;
77

88
const noop = () => {};
99

10+
const toNodesArray = (x) => (
11+
x instanceof NodeList
12+
? slice.call(x)
13+
: Array.isArray(x)
14+
? x
15+
: x != null
16+
? [x]
17+
: null
18+
);
19+
1020
const ElementPortal = createReactClass({
1121
propTypes: {
1222
selector: PropTypes.string,
23+
nodes: PropTypes.oneOfType([
24+
PropTypes.instanceOf(HTMLElement),
25+
PropTypes.instanceOf(NodeList),
26+
PropTypes.arrayOf(PropTypes.instanceOf(HTMLElement))
27+
]),
1328
component: PropTypes.func,
1429
mapNodeToProps: PropTypes.func,
1530
resetStyle: PropTypes.bool
@@ -24,12 +39,14 @@ const ElementPortal = createReactClass({
2439
},
2540

2641
renderToNodes() {
27-
const nodes = this.props.selector
28-
? slice.call(document.querySelectorAll(this.props.selector))
29-
: null;
42+
const { nodes, selector } = this.props;
43+
const collectedNodes = [];
44+
45+
push.apply(collectedNodes, toNodesArray(document.querySelectorAll(selector)));
46+
push.apply(collectedNodes, toNodesArray(nodes));
3047

31-
if (nodes) {
32-
nodes.forEach(this.renderNode);
48+
if (collectedNodes.length) {
49+
collectedNodes.forEach(this.renderNode);
3350
}
3451
},
3552

test/ElementPortal.js

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import 'babel-core/register';
99
import uniqueId from './helpers/uniqueId';
1010
import ElementPortal, { withElementPortal } from '../src';
1111

12-
test('can render to ElementPortal using element id', t => {
12+
test('can render to ElementPortal using id selector', t => {
1313
const node = document.createElement('div');
1414
document.body.appendChild(node);
1515
const headerId = uniqueId();
@@ -32,7 +32,7 @@ test('can render to ElementPortal using element id', t => {
3232
t.is(document.getElementById(headerId).textContent, 'Hello');
3333
});
3434

35-
test('can render to ElementPortal using selector', t => {
35+
test('can render to ElementPortal using class selector', t => {
3636
const node = document.createElement('div');
3737
document.body.appendChild(node);
3838
const appId = uniqueId();
@@ -83,6 +83,107 @@ test('can render to ElementPortal using selector with custom component', t => {
8383
t.is(elements[1].textContent, 'Hello');
8484
});
8585

86+
test('can render to ElementPortal using nodes', t => {
87+
const node = document.createElement('div');
88+
document.body.appendChild(node);
89+
const headerId = uniqueId();
90+
const appId = uniqueId();
91+
node.innerHTML = `
92+
<div id="${headerId}">
93+
</div>
94+
<div id="${appId}">
95+
</div>
96+
`;
97+
const Greeting = () => (<div>Hello</div>);
98+
render(
99+
<div>
100+
<ElementPortal nodes={document.getElementById(headerId)}>
101+
<Greeting/>
102+
</ElementPortal>
103+
</div>,
104+
document.getElementById(appId)
105+
);
106+
t.is(document.getElementById(headerId).textContent, 'Hello');
107+
});
108+
109+
test('can render to ElementPortal using nodes', t => {
110+
const node = document.createElement('div');
111+
document.body.appendChild(node);
112+
const appId = uniqueId();
113+
node.innerHTML = `
114+
<ul>
115+
<li class="greeting"></li>
116+
<li class="greeting"></li>
117+
</ul>
118+
<div id="${appId}">
119+
</div>
120+
`;
121+
const Greeting = () => (<div>Hello</div>);
122+
const elements = [].slice.call(node.querySelectorAll('li.greeting'));
123+
render(
124+
<div>
125+
<ElementPortal nodes={elements}>
126+
<Greeting/>
127+
</ElementPortal>
128+
</div>,
129+
document.getElementById(appId)
130+
);
131+
elements.forEach(liNode => {
132+
t.is(liNode.textContent, 'Hello');
133+
});
134+
});
135+
136+
test('can render to ElementPortal using nodes as a NodeList', t => {
137+
const node = document.createElement('div');
138+
document.body.appendChild(node);
139+
const appId = uniqueId();
140+
node.innerHTML = `
141+
<ul>
142+
<li class="greeting"></li>
143+
<li class="greeting"></li>
144+
</ul>
145+
<div id="${appId}">
146+
</div>
147+
`;
148+
const Greeting = () => (<div>Hello</div>);
149+
render(
150+
<div>
151+
<ElementPortal nodes={node.querySelectorAll('li.greeting')}>
152+
<Greeting/>
153+
</ElementPortal>
154+
</div>,
155+
document.getElementById(appId)
156+
);
157+
const elements = [].slice.call(node.querySelectorAll('li.greeting'));
158+
elements.forEach(liNode => {
159+
t.is(liNode.textContent, 'Hello');
160+
});
161+
});
162+
163+
test('can render to ElementPortal using nodes with custom component', t => {
164+
const node = document.createElement('div');
165+
document.body.appendChild(node);
166+
const appId = uniqueId();
167+
node.innerHTML = `
168+
<ul>
169+
<li class="greeting"></li>
170+
<li class="greeting"></li>
171+
</ul>
172+
<div id="${appId}">
173+
</div>
174+
`;
175+
const Greeting = () => (<div>Hello</div>);
176+
const elements = [].slice.call(node.querySelectorAll('li.greeting'));
177+
render(
178+
<div>
179+
<ElementPortal nodes={elements} component={Greeting}/>
180+
</div>,
181+
document.getElementById(appId)
182+
);
183+
t.is(elements[0].textContent, 'Hello');
184+
t.is(elements[1].textContent, 'Hello');
185+
});
186+
86187
test('map dom node to props', t => {
87188
const node = document.createElement('div');
88189
document.body.appendChild(node);

0 commit comments

Comments
 (0)