Skip to content

Commit 995059e

Browse files
committed
Fix handling the index when removing the last tab
1 parent 0255921 commit 995059e

File tree

4 files changed

+39
-17
lines changed

4 files changed

+39
-17
lines changed

examples/dyno/app.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class App extends React.Component {
5151
removeTab = (index) => {
5252
this.setState({
5353
tabs: this.state.tabs.filter((tab, i) => i !== index),
54-
selectedIndex: this.state.selectedIndex - 1,
54+
selectedIndex: Math.max(this.state.selectedIndex - 1, 0),
5555
});
5656
}
5757

src/components/Tabs.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
22
import React, { Component } from 'react';
33
import { childrenPropType, onSelectPropType, selectedIndexPropType } from '../helpers/propTypes';
44
import UncontrolledTabs from './UncontrolledTabs';
5+
import { getTabsCount } from '../helpers/count';
56

67
export default class Tabs extends Component {
78

@@ -59,12 +60,20 @@ export default class Tabs extends Component {
5960
}
6061
}
6162

62-
// This is an anti-pattern, so sue me
63+
// preserve the existing selectedIndex from state.
64+
// If the state has not selectedIndex, default to the defaultIndex or 0
6365
static copyPropsToState(props, state) {
64-
// preserve the existing selectedIndex from state.
65-
// If the state has not selectedIndex, default to the defaultIndex or 0
66+
const maxTabIndex = getTabsCount(props.children) - 1;
67+
let selectedIndex = null;
68+
69+
if (state.selectedIndex != null) {
70+
selectedIndex = Math.min(state.selectedIndex, maxTabIndex);
71+
} else {
72+
selectedIndex = props.defaultIndex || 0;
73+
}
74+
6675
return {
67-
selectedIndex: state.selectedIndex || props.defaultIndex || 0,
76+
selectedIndex,
6877
focus: state.focus || props.defaultFocus,
6978
};
7079
}

src/components/UncontrolledTabs.js

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { childrenPropType } from '../helpers/propTypes';
66
import Tab from './Tab';
77
import TabList from './TabList';
88
import TabPanel from './TabPanel';
9+
import { getPanelsCount, getTabsCount } from '../helpers/count';
910

1011
// Determine if a node from event.target is a Tab element
1112
function isTabNode(node) {
@@ -90,21 +91,11 @@ export default class UncontrolledTabs extends Component {
9091
}
9192

9293
getTabsCount() {
93-
const tabLists = React.Children.toArray(this.props.children).filter(x => x.type === TabList);
94-
95-
if (tabLists[0] && tabLists[0].props.children) {
96-
return React.Children.count(
97-
React.Children.toArray(tabLists[0].props.children).filter(x => x.type === Tab),
98-
);
99-
}
100-
101-
return 0;
94+
return getTabsCount(this.props.children);
10295
}
10396

10497
getPanelsCount() {
105-
return React.Children.count(
106-
React.Children.toArray(this.props.children).filter(x => x.type === TabPanel),
107-
);
98+
return getPanelsCount(this.props.children);
10899
}
109100

110101
getTab(index) {

src/helpers/count.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from 'react';
2+
import TabList from '../components/TabList';
3+
import Tab from '../components/Tab';
4+
import TabPanel from '../components/TabPanel';
5+
6+
export function getTabsCount(children) {
7+
const tabLists = React.Children.toArray(children).filter(x => x.type === TabList);
8+
9+
if (tabLists[0] && tabLists[0].props.children) {
10+
return React.Children.count(
11+
React.Children.toArray(tabLists[0].props.children).filter(x => x.type === Tab),
12+
);
13+
}
14+
15+
return 0;
16+
}
17+
18+
export function getPanelsCount(children) {
19+
return React.Children.count(
20+
React.Children.toArray(children).filter(x => x.type === TabPanel),
21+
);
22+
}

0 commit comments

Comments
 (0)