Skip to content

Commit 0a15604

Browse files
committed
Allows arbitrary components anywhere inside <TabList>
1 parent b50c77e commit 0a15604

File tree

2 files changed

+36
-19
lines changed

2 files changed

+36
-19
lines changed

src/components/Tabs.js

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,15 @@ export default class Tabs extends Component {
127127
}
128128

129129
getTabsCount() {
130-
return this.props.children && this.props.children[0] ?
131-
React.Children.count(this.props.children[0].props.children) :
132-
0;
130+
if (
131+
Array.isArray(this.props.children) &&
132+
Array.isArray(this.props.children[0].props.children)
133+
) {
134+
const tabs = this.props.children[0].props.children.filter(x => x.type === Tab);
135+
return React.Children.count(tabs);
136+
}
137+
138+
return 0;
133139
}
134140

135141
getPanelsCount() {
@@ -178,25 +184,28 @@ export default class Tabs extends Component {
178184
return null;
179185
}
180186

181-
const tabRef = (node) => { this.tabNodes[`tabs-${index}`] = node; };
187+
// Exit early if this is not a tab. That way we can have arbitrary
188+
// elements anywhere inside <TabList>
189+
if (tab.type !== Tab) {
190+
return tab;
191+
}
192+
193+
const key = `tabs-${index}`;
194+
const tabRef = (node) => { this.tabNodes[key] = node; };
182195
const id = this.tabIds[index];
183196
const panelId = this.panelIds[index];
184197
const selected = state.selectedIndex === index;
185198
const focus = selected && state.focus;
186199

187200
index++;
188201

189-
if (tab.type === Tab) {
190-
return cloneElement(tab, {
191-
tabRef,
192-
id,
193-
panelId,
194-
selected,
195-
focus,
196-
});
197-
}
198-
199-
return tab;
202+
return cloneElement(tab, {
203+
tabRef,
204+
id,
205+
panelId,
206+
selected,
207+
focus,
208+
});
200209
}),
201210
});
202211

@@ -254,7 +263,7 @@ export default class Tabs extends Component {
254263
return;
255264
}
256265

257-
const index = [].slice.call(node.parentNode.children).indexOf(node);
266+
const index = [].slice.call(node.parentNode.children).filter(isTabNode).indexOf(node);
258267
this.setSelected(index);
259268
return;
260269
}

src/components/__tests__/Tabs-test.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,22 +214,30 @@ describe('<Tabs />', () => {
214214
it('should not clone non tabs element', () => {
215215
class Demo extends React.Component {
216216
render() {
217-
const plus = <div ref="yolo">+</div>; // eslint-disable-line react/no-string-refs
217+
const arbitrary1 = <div ref="arbitrary1">One</div>; // eslint-disable-line react/no-string-refs
218+
const arbitrary2 = <span ref="arbitrary2">Two</span>; // eslint-disable-line react/no-string-refs
219+
const arbitrary3 = <small ref="arbitrary3">Three</small>; // eslint-disable-line react/no-string-refs
218220

219221
return (<Tabs>
220222
<TabList>
223+
{arbitrary1}
221224
<Tab>Foo</Tab>
222-
{plus}
225+
{arbitrary2}
226+
<Tab>Bar</Tab>
227+
{arbitrary3}
223228
</TabList>
224229

225230
<TabPanel>Hello Baz</TabPanel>
231+
<TabPanel>Hello Faz</TabPanel>
226232
</Tabs>);
227233
}
228234
}
229235

230236
const wrapper = mount(<Demo />);
231237

232-
expect(wrapper.ref('yolo').text()).toBe('+');
238+
expect(wrapper.ref('arbitrary1').text()).toBe('One');
239+
expect(wrapper.ref('arbitrary2').text()).toBe('Two');
240+
expect(wrapper.ref('arbitrary3').text()).toBe('Three');
233241
});
234242
});
235243

0 commit comments

Comments
 (0)