Skip to content

Commit c6588d8

Browse files
patrick91danez
authored andcommitted
Allow other components inside TabList (#123)
* Allow other child types inside TabList * Updated tests * Fix lint issue * Don't clone non Tabs elements * Test that non tab elements are not cloned * Don't compare element type by display name * Disable multiple components lint inside Tabs tests
1 parent cb701e6 commit c6588d8

File tree

5 files changed

+70
-17
lines changed

5 files changed

+70
-17
lines changed

examples/basic/app.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ const App = React.createClass({
1717
<Tab>React</Tab>
1818
<Tab>Ember</Tab>
1919
<Tab>Angular</Tab>
20+
21+
<span>+</span>
2022
</TabList>
2123

2224
<TabPanel>

src/components/TabList.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
11
import React, { PropTypes } from 'react';
22
import cx from 'classnames';
3+
import Tab from './Tab';
34

45
function renderChildren(props) {
5-
return React.Children.map(props.children, (child) =>
6-
React.cloneElement(child, {
6+
return React.Children.map(props.children, (child) => {
7+
// if child is not a tab we don't need to clone it
8+
// since we don't need to add custom props
9+
10+
if (child.type !== Tab) {
11+
return child;
12+
}
13+
14+
const clonedProps = {
715
activeTabClassName: props.activeTabClassName,
816
disabledTabClassName: props.disabledTabClassName,
9-
})
10-
);
17+
};
18+
19+
return React.cloneElement(child, clonedProps);
20+
});
1121
}
1222

1323
module.exports = React.createClass({

src/components/Tabs.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import cx from 'classnames';
44
import jss from 'js-stylesheet';
55
import uuid from '../helpers/uuid';
66
import childrenPropType from '../helpers/childrenPropType';
7+
import Tab from './Tab';
78

89
// Determine if a node from event.target is a Tab element
910
function isTabNode(node) {
@@ -209,13 +210,17 @@ module.exports = React.createClass({
209210

210211
index++;
211212

212-
return cloneElement(tab, {
213-
ref,
214-
id,
215-
panelId,
216-
selected,
217-
focus,
218-
});
213+
if (tab.type === Tab) {
214+
return cloneElement(tab, {
215+
ref,
216+
id,
217+
panelId,
218+
selected,
219+
focus,
220+
});
221+
}
222+
223+
return tab;
219224
}),
220225
});
221226

src/components/__tests__/Tabs-test.js

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable react/no-multi-comp */
12
/* global jest, describe, it, expect */
23
import React from 'react';
34
import { shallow, mount } from 'enzyme';
@@ -185,6 +186,27 @@ describe('react-tabs', () => {
185186
expect(wrapper.childAt(2).text()).toBe('Hello Bar');
186187
expect(wrapper.childAt(3).text()).toBe('Hello Baz');
187188
});
189+
190+
it('should not clone non tabs element', () => {
191+
class Demo extends React.Component {
192+
render() {
193+
const plus = <div ref="yolo">+</div>;
194+
195+
return (<Tabs>
196+
<TabList>
197+
<Tab>Foo</Tab>
198+
{plus}
199+
</TabList>
200+
201+
<TabPanel>Hello Baz</TabPanel>
202+
</Tabs>);
203+
}
204+
}
205+
206+
const wrapper = mount(<Demo />);
207+
208+
expect(wrapper.ref('yolo').text()).toBe('+');
209+
});
188210
});
189211

190212
describe('validation', () => {
@@ -201,7 +223,25 @@ describe('react-tabs', () => {
201223
expect(result instanceof Error).toBe(true);
202224
});
203225

204-
it('should result with a warning when wrong element is found', () => {
226+
it(`should result with warning when tabs/panels are imbalanced and
227+
it should ignore non tab children`, () => {
228+
const wrapper = shallow(
229+
<Tabs>
230+
<TabList>
231+
<Tab>Foo</Tab>
232+
<div>+</div>
233+
</TabList>
234+
235+
<TabPanel>Hello Foo</TabPanel>
236+
<TabPanel>Hello Bar</TabPanel>
237+
</Tabs>
238+
);
239+
240+
const result = Tabs.propTypes.children(wrapper.props(), 'children', 'Tabs');
241+
expect(result instanceof Error).toBe(true);
242+
});
243+
244+
it('should not throw a warning when wrong element is found', () => {
205245
const wrapper = shallow(
206246
<Tabs>
207247
<TabList>
@@ -213,7 +253,7 @@ describe('react-tabs', () => {
213253
);
214254

215255
const result = Tabs.propTypes.children(wrapper.props(), 'children', 'Tabs');
216-
expect(result instanceof Error).toBe(true);
256+
expect(result instanceof Error).toBe(false);
217257
});
218258

219259
it('should be okay with rendering without any children', () => {

src/helpers/childrenPropType.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ module.exports = function childrenPropTypes(props, propName) {
2525

2626
if (c.type === Tab) {
2727
tabsCount++;
28-
} else {
29-
error = new Error(
30-
`Expected 'Tab' but found '${c.type.displayName || c.type}'`
31-
);
3228
}
3329
});
3430
} else if (child.type.displayName === 'TabPanel') {

0 commit comments

Comments
 (0)