react-tabs
Advanced tools
Comparing version 3.2.3 to 4.0.0
@@ -30,18 +30,2 @@ (function (global, factory) { | ||
function _inheritsLoose(subClass, superClass) { | ||
subClass.prototype = Object.create(superClass.prototype); | ||
subClass.prototype.constructor = subClass; | ||
_setPrototypeOf(subClass, superClass); | ||
} | ||
function _setPrototypeOf(o, p) { | ||
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { | ||
o.__proto__ = p; | ||
return o; | ||
}; | ||
return _setPrototypeOf(o, p); | ||
} | ||
function _objectWithoutPropertiesLoose(source, excluded) { | ||
@@ -241,11 +225,4 @@ if (source == null) return {}; | ||
} | ||
function getPanelsCount(children) { | ||
var panelCount = 0; | ||
deepForEach(children, function (child) { | ||
if (isTabPanel(child)) panelCount++; | ||
}); | ||
return panelCount; | ||
} | ||
var _excluded$4 = ["children", "className", "disabledTabClassName", "domRef", "focus", "forceRenderTabPanel", "onSelect", "selectedIndex", "selectedTabClassName", "selectedTabPanelClassName", "environment", "disableUpDownKeys"]; | ||
var _excluded$3 = ["children", "className", "disabledTabClassName", "domRef", "focus", "forceRenderTabPanel", "onSelect", "selectedIndex", "selectedTabClassName", "selectedTabPanelClassName", "environment", "disableUpDownKeys"]; | ||
@@ -282,114 +259,43 @@ function isNode(node) { | ||
var UncontrolledTabs = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(UncontrolledTabs, _Component); | ||
var defaultProps$3 = { | ||
className: 'react-tabs', | ||
focus: false | ||
}; | ||
var propTypes$4 = { | ||
children: childrenPropType, | ||
direction: PropTypes__default["default"].oneOf(['rtl', 'ltr']), | ||
className: PropTypes__default["default"].oneOfType([PropTypes__default["default"].string, PropTypes__default["default"].array, PropTypes__default["default"].object]), | ||
disabledTabClassName: PropTypes__default["default"].string, | ||
disableUpDownKeys: PropTypes__default["default"].bool, | ||
domRef: PropTypes__default["default"].func, | ||
focus: PropTypes__default["default"].bool, | ||
forceRenderTabPanel: PropTypes__default["default"].bool, | ||
onSelect: PropTypes__default["default"].func.isRequired, | ||
selectedIndex: PropTypes__default["default"].number.isRequired, | ||
selectedTabClassName: PropTypes__default["default"].string, | ||
selectedTabPanelClassName: PropTypes__default["default"].string, | ||
environment: PropTypes__default["default"].object | ||
} ; | ||
function UncontrolledTabs() { | ||
var _this; | ||
var UncontrolledTabs = function UncontrolledTabs(props) { | ||
var tabNodes = React.useRef([]); | ||
var tabIds = React.useRef([]); | ||
var panelIds = React.useRef([]); | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
var _ref = React.useRef(); | ||
_this = _Component.call.apply(_Component, [this].concat(args)) || this; | ||
_this.tabNodes = []; | ||
_this.handleKeyDown = function (e) { | ||
var _this$props = _this.props, | ||
direction = _this$props.direction, | ||
disableUpDownKeys = _this$props.disableUpDownKeys; | ||
if (_this.isTabFromContainer(e.target)) { | ||
var index = _this.props.selectedIndex; | ||
var preventDefault = false; | ||
var useSelectedIndex = false; | ||
if (e.keyCode === 32 || e.keyCode === 13) { | ||
preventDefault = true; | ||
useSelectedIndex = false; | ||
_this.handleClick(e); | ||
} | ||
if (e.keyCode === 37 || !disableUpDownKeys && e.keyCode === 38) { | ||
// Select next tab to the left, validate if up arrow is not disabled | ||
if (direction === 'rtl') { | ||
index = _this.getNextTab(index); | ||
} else { | ||
index = _this.getPrevTab(index); | ||
} | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 39 || !disableUpDownKeys && e.keyCode === 40) { | ||
// Select next tab to the right, validate if down arrow is not disabled | ||
if (direction === 'rtl') { | ||
index = _this.getPrevTab(index); | ||
} else { | ||
index = _this.getNextTab(index); | ||
} | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 35) { | ||
// Select last tab (End key) | ||
index = _this.getLastTab(); | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 36) { | ||
// Select first tab (Home key) | ||
index = _this.getFirstTab(); | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} // This prevents scrollbars from moving around | ||
if (preventDefault) { | ||
e.preventDefault(); | ||
} // Only use the selected index in the state if we're not using the tabbed index | ||
if (useSelectedIndex) { | ||
_this.setSelected(index, e); | ||
} | ||
} | ||
}; | ||
_this.handleClick = function (e) { | ||
var node = e.target; | ||
do { | ||
if (_this.isTabFromContainer(node)) { | ||
if (isTabDisabled(node)) { | ||
return; | ||
} | ||
var index = [].slice.call(node.parentNode.children).filter(isTabNode).indexOf(node); | ||
_this.setSelected(index, e); | ||
return; | ||
} | ||
} while ((node = node.parentNode) != null); | ||
}; | ||
return _this; | ||
} | ||
var _proto = UncontrolledTabs.prototype; | ||
_proto.setSelected = function setSelected(index, event) { | ||
function setSelected(index, event) { | ||
// Check index boundary | ||
if (index < 0 || index >= this.getTabsCount()) return; | ||
var _this$props2 = this.props, | ||
onSelect = _this$props2.onSelect, | ||
selectedIndex = _this$props2.selectedIndex; // Call change event handler | ||
if (index < 0 || index >= getTabsCount$1()) return; | ||
var onSelect = props.onSelect, | ||
selectedIndex = props.selectedIndex; // Call change event handler | ||
onSelect(index, selectedIndex, event); | ||
}; | ||
} | ||
_proto.getNextTab = function getNextTab(index) { | ||
var count = this.getTabsCount(); // Look for non-disabled tab from index to the last tab on the right | ||
function getNextTab(index) { | ||
var count = getTabsCount$1(); // Look for non-disabled tab from index to the last tab on the right | ||
for (var i = index + 1; i < count; i++) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -401,3 +307,3 @@ } | ||
for (var _i = 0; _i < index; _i++) { | ||
if (!isTabDisabled(this.getTab(_i))) { | ||
if (!isTabDisabled(getTab(_i))) { | ||
return _i; | ||
@@ -409,9 +315,9 @@ } | ||
return index; | ||
}; | ||
} | ||
_proto.getPrevTab = function getPrevTab(index) { | ||
function getPrevTab(index) { | ||
var i = index; // Look for non-disabled tab from index to first tab on the left | ||
while (i--) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -422,6 +328,6 @@ } | ||
i = this.getTabsCount(); | ||
i = getTabsCount$1(); | ||
while (i-- > index) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -433,9 +339,9 @@ } | ||
return index; | ||
}; | ||
} | ||
_proto.getFirstTab = function getFirstTab() { | ||
var count = this.getTabsCount(); // Look for non disabled tab from the first tab | ||
function getFirstTab() { | ||
var count = getTabsCount$1(); // Look for non disabled tab from the first tab | ||
for (var i = 0; i < count; i++) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -446,9 +352,9 @@ } | ||
return null; | ||
}; | ||
} | ||
_proto.getLastTab = function getLastTab() { | ||
var i = this.getTabsCount(); // Look for non disabled tab from the last tab | ||
function getLastTab() { | ||
var i = getTabsCount$1(); // Look for non disabled tab from the last tab | ||
while (i--) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -459,34 +365,26 @@ } | ||
return null; | ||
}; | ||
} | ||
_proto.getTabsCount = function getTabsCount$1() { | ||
var children = this.props.children; | ||
function getTabsCount$1() { | ||
var children = props.children; | ||
return getTabsCount(children); | ||
}; | ||
} | ||
_proto.getPanelsCount = function getPanelsCount$1() { | ||
var children = this.props.children; | ||
return getPanelsCount(children); | ||
}; | ||
function getTab(index) { | ||
return tabNodes.current["tabs-" + index]; | ||
} | ||
_proto.getTab = function getTab(index) { | ||
return this.tabNodes["tabs-" + index]; | ||
}; | ||
_proto.getChildren = function getChildren() { | ||
var _this2 = this; | ||
function getChildren() { | ||
var index = 0; | ||
var _this$props3 = this.props, | ||
children = _this$props3.children, | ||
disabledTabClassName = _this$props3.disabledTabClassName, | ||
focus = _this$props3.focus, | ||
forceRenderTabPanel = _this$props3.forceRenderTabPanel, | ||
selectedIndex = _this$props3.selectedIndex, | ||
selectedTabClassName = _this$props3.selectedTabClassName, | ||
selectedTabPanelClassName = _this$props3.selectedTabPanelClassName, | ||
environment = _this$props3.environment; | ||
this.tabIds = this.tabIds || []; | ||
this.panelIds = this.panelIds || []; | ||
var diff = this.tabIds.length - this.getTabsCount(); // Add ids if new tabs have been added | ||
var children = props.children, | ||
disabledTabClassName = props.disabledTabClassName, | ||
focus = props.focus, | ||
forceRenderTabPanel = props.forceRenderTabPanel, | ||
selectedIndex = props.selectedIndex, | ||
selectedTabClassName = props.selectedTabClassName, | ||
selectedTabPanelClassName = props.selectedTabPanelClassName, | ||
environment = props.environment; | ||
tabIds.current = tabIds.current || []; | ||
panelIds.current = panelIds.current || []; | ||
var diff = tabIds.current.length - getTabsCount$1(); // Add ids if new tabs have been added | ||
// Don't bother removing ids, just keep them in case they are added again | ||
@@ -496,4 +394,4 @@ // This is more efficient, and keeps the uuid counter under control | ||
while (diff++ < 0) { | ||
this.tabIds.push(uuid()); | ||
this.panelIds.push(uuid()); | ||
tabIds.current.push(uuid()); | ||
panelIds.current.push(uuid()); | ||
} // Map children to dynamically setup refs | ||
@@ -518,3 +416,3 @@ | ||
var env = environment || (typeof window !== 'undefined' ? window : undefined); | ||
return env && env.document.activeElement === _this2.getTab(i); | ||
return env && env.document.activeElement === getTab(i); | ||
}); | ||
@@ -529,6 +427,6 @@ } | ||
tabRef: function tabRef(node) { | ||
_this2.tabNodes[key] = node; | ||
tabNodes.current[key] = node; | ||
}, | ||
id: _this2.tabIds[listIndex], | ||
panelId: _this2.panelIds[listIndex], | ||
id: tabIds.current[listIndex], | ||
panelId: panelIds.current[listIndex], | ||
selected: selected, | ||
@@ -544,11 +442,11 @@ focus: selected && (focus || wasTabFocused) | ||
} else if (isTabPanel(child)) { | ||
var props = { | ||
id: _this2.panelIds[index], | ||
tabId: _this2.tabIds[index], | ||
var _props = { | ||
id: panelIds.current[index], | ||
tabId: tabIds.current[index], | ||
selected: selectedIndex === index | ||
}; | ||
if (forceRenderTabPanel) props.forceRender = forceRenderTabPanel; | ||
if (selectedTabPanelClassName) props.selectedClassName = selectedTabPanelClassName; | ||
if (forceRenderTabPanel) _props.forceRender = forceRenderTabPanel; | ||
if (selectedTabPanelClassName) _props.selectedClassName = selectedTabPanelClassName; | ||
index++; | ||
result = /*#__PURE__*/React.cloneElement(child, props); | ||
result = /*#__PURE__*/React.cloneElement(child, _props); | ||
} | ||
@@ -558,4 +456,78 @@ | ||
}); | ||
}; | ||
} | ||
function handleKeyDown(e) { | ||
var direction = props.direction, | ||
disableUpDownKeys = props.disableUpDownKeys; | ||
if (isTabFromContainer(e.target)) { | ||
var index = props.selectedIndex; | ||
var preventDefault = false; | ||
var useSelectedIndex = false; | ||
if (e.keyCode === 32 || e.keyCode === 13) { | ||
preventDefault = true; | ||
useSelectedIndex = false; | ||
handleClick(e); | ||
} | ||
if (e.keyCode === 37 || !disableUpDownKeys && e.keyCode === 38) { | ||
// Select next tab to the left, validate if up arrow is not disabled | ||
if (direction === 'rtl') { | ||
index = getNextTab(index); | ||
} else { | ||
index = getPrevTab(index); | ||
} | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 39 || !disableUpDownKeys && e.keyCode === 40) { | ||
// Select next tab to the right, validate if down arrow is not disabled | ||
if (direction === 'rtl') { | ||
index = getPrevTab(index); | ||
} else { | ||
index = getNextTab(index); | ||
} | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 35) { | ||
// Select last tab (End key) | ||
index = getLastTab(); | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 36) { | ||
// Select first tab (Home key) | ||
index = getFirstTab(); | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} // This prevents scrollbars from moving around | ||
if (preventDefault) { | ||
e.preventDefault(); | ||
} // Only use the selected index in the state if we're not using the tabbed index | ||
if (useSelectedIndex) { | ||
setSelected(index, e); | ||
} | ||
} | ||
} | ||
function handleClick(e) { | ||
var node = e.target; | ||
do { | ||
if (isTabFromContainer(node)) { | ||
if (isTabDisabled(node)) { | ||
return; | ||
} | ||
var index = [].slice.call(node.parentNode.children).filter(isTabNode).indexOf(node); | ||
setSelected(index, e); | ||
return; | ||
} | ||
} while ((node = node.parentNode) != null); | ||
} | ||
/** | ||
@@ -566,3 +538,5 @@ * Determine if a node from event.target is a Tab element for the current Tabs container. | ||
*/ | ||
_proto.isTabFromContainer = function isTabFromContainer(node) { | ||
function isTabFromContainer(node) { | ||
// return immediately if the clicked element is not a Tab. | ||
@@ -577,3 +551,3 @@ if (!isTabNode(node)) { | ||
do { | ||
if (nodeAncestor === this.node) return true; | ||
if (nodeAncestor === _ref.current) return true; | ||
if (nodeAncestor.getAttribute('data-rttabs')) break; | ||
@@ -584,53 +558,47 @@ nodeAncestor = nodeAncestor.parentElement; | ||
return false; | ||
}; | ||
} | ||
_proto.render = function render() { | ||
var _this3 = this; | ||
props.children; | ||
var className = props.className; | ||
props.disabledTabClassName; | ||
var domRef = props.domRef; | ||
props.focus; | ||
props.forceRenderTabPanel; | ||
props.onSelect; | ||
props.selectedIndex; | ||
props.selectedTabClassName; | ||
props.selectedTabPanelClassName; | ||
props.environment; | ||
props.disableUpDownKeys; | ||
var attributes = _objectWithoutPropertiesLoose(props, _excluded$3); | ||
// Delete all known props, so they don't get added to DOM | ||
var _this$props4 = this.props; | ||
_this$props4.children; | ||
var className = _this$props4.className; | ||
_this$props4.disabledTabClassName; | ||
var domRef = _this$props4.domRef; | ||
_this$props4.focus; | ||
_this$props4.forceRenderTabPanel; | ||
_this$props4.onSelect; | ||
_this$props4.selectedIndex; | ||
_this$props4.selectedTabClassName; | ||
_this$props4.selectedTabPanelClassName; | ||
_this$props4.environment; | ||
_this$props4.disableUpDownKeys; | ||
var attributes = _objectWithoutPropertiesLoose(_this$props4, _excluded$4); | ||
return /*#__PURE__*/React__default["default"].createElement("div", _extends({}, attributes, { | ||
className: cx(className), | ||
onClick: handleClick, | ||
onKeyDown: handleKeyDown, | ||
ref: function ref(node) { | ||
_ref.current = node; | ||
if (domRef) domRef(node); | ||
}, | ||
"data-rttabs": true | ||
}), getChildren()); | ||
}; | ||
return /*#__PURE__*/React__default["default"].createElement("div", _extends({}, attributes, { | ||
className: cx(className), | ||
onClick: this.handleClick, | ||
onKeyDown: this.handleKeyDown, | ||
ref: function ref(node) { | ||
_this3.node = node; | ||
if (domRef) domRef(node); | ||
}, | ||
"data-rttabs": true | ||
}), this.getChildren()); | ||
}; | ||
UncontrolledTabs.defaultProps = defaultProps$3; | ||
UncontrolledTabs.propTypes = propTypes$4 ; | ||
return UncontrolledTabs; | ||
}(React.Component); | ||
UncontrolledTabs.defaultProps = { | ||
className: 'react-tabs', | ||
focus: false | ||
}; | ||
UncontrolledTabs.propTypes = { | ||
var MODE_CONTROLLED = 0; | ||
var MODE_UNCONTROLLED = 1; | ||
var propTypes$3 = { | ||
children: childrenPropType, | ||
direction: PropTypes__default["default"].oneOf(['rtl', 'ltr']), | ||
className: PropTypes__default["default"].oneOfType([PropTypes__default["default"].string, PropTypes__default["default"].array, PropTypes__default["default"].object]), | ||
defaultFocus: PropTypes__default["default"].bool, | ||
defaultIndex: PropTypes__default["default"].number, | ||
disabledTabClassName: PropTypes__default["default"].string, | ||
disableUpDownKeys: PropTypes__default["default"].bool, | ||
domRef: PropTypes__default["default"].func, | ||
focus: PropTypes__default["default"].bool, | ||
forceRenderTabPanel: PropTypes__default["default"].bool, | ||
onSelect: PropTypes__default["default"].func.isRequired, | ||
selectedIndex: PropTypes__default["default"].number.isRequired, | ||
onSelect: onSelectPropType, | ||
selectedIndex: selectedIndexPropType, | ||
selectedTabClassName: PropTypes__default["default"].string, | ||
@@ -640,235 +608,125 @@ selectedTabPanelClassName: PropTypes__default["default"].string, | ||
} ; | ||
var defaultProps$2 = { | ||
defaultFocus: false, | ||
forceRenderTabPanel: false, | ||
selectedIndex: null, | ||
defaultIndex: null, | ||
environment: null, | ||
disableUpDownKeys: false | ||
}; | ||
var _excluded$3 = ["children", "defaultIndex", "defaultFocus"]; | ||
var MODE_CONTROLLED = 0; | ||
var MODE_UNCONTROLLED = 1; | ||
var getModeFromProps = function getModeFromProps(props) { | ||
return props.selectedIndex === null ? MODE_UNCONTROLLED : MODE_CONTROLLED; | ||
}; | ||
var Tabs = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(Tabs, _Component); | ||
var checkForIllegalModeChange = function checkForIllegalModeChange(props, mode) { | ||
if (mode != undefined && mode !== getModeFromProps(props)) { | ||
throw new Error("Switching between controlled mode (by using `selectedIndex`) and uncontrolled mode is not supported in `Tabs`.\nFor more information about controlled and uncontrolled mode of react-tabs see https://github.com/reactjs/react-tabs#controlled-vs-uncontrolled-mode."); | ||
} | ||
}; | ||
/** | ||
* State: | ||
* mode: Initialized only once from props and never changes | ||
* selectedIndex: null if controlled mode, otherwise initialized with prop defaultIndex, changed on selection of tabs, has effect to ensure it never gets out of bound | ||
* focus: Because we never remove focus from the Tabs this state is only used to indicate that we should focus the current tab. | ||
* It is initialized from the prop defaultFocus, and after the first render it is reset back to false. Later it can become true again when using keys to navigate the tabs. | ||
*/ | ||
function Tabs(props) { | ||
var _this; | ||
_this = _Component.call(this, props) || this; | ||
var Tabs = function Tabs(props) { | ||
var children = props.children, | ||
defaultFocus = props.defaultFocus, | ||
defaultIndex = props.defaultIndex, | ||
onSelect = props.onSelect; | ||
_this.handleSelected = function (index, last, event) { | ||
var onSelect = _this.props.onSelect; | ||
var mode = _this.state.mode; // Call change event handler | ||
var _useState = React.useState(defaultFocus), | ||
focus = _useState[0], | ||
setFocus = _useState[1]; | ||
if (typeof onSelect === 'function') { | ||
// Check if the change event handler cancels the tab change | ||
if (onSelect(index, last, event) === false) return; | ||
} | ||
var _useState2 = React.useState(getModeFromProps(props)), | ||
mode = _useState2[0]; | ||
var state = { | ||
// Set focus if the change was triggered from the keyboard | ||
focus: event.type === 'keydown' | ||
}; | ||
var _useState3 = React.useState(mode === MODE_UNCONTROLLED ? defaultIndex || 0 : null), | ||
selectedIndex = _useState3[0], | ||
setSelectedIndex = _useState3[1]; | ||
if (mode === MODE_UNCONTROLLED) { | ||
// Update selected index | ||
state.selectedIndex = index; | ||
React.useEffect(function () { | ||
// Reset focus after initial render, see comment above | ||
setFocus(false); | ||
}, []); | ||
if (mode === MODE_UNCONTROLLED) { | ||
// Ensure that we handle removed tabs and don't let selectedIndex get out of bounds | ||
var tabsCount = getTabsCount(children); | ||
React.useEffect(function () { | ||
if (selectedIndex != null) { | ||
var maxTabIndex = Math.max(0, tabsCount - 1); | ||
setSelectedIndex(Math.min(selectedIndex, maxTabIndex)); | ||
} | ||
_this.setState(state); | ||
}; | ||
_this.state = Tabs.copyPropsToState(_this.props, {}, props.defaultFocus); | ||
return _this; | ||
}, [tabsCount]); | ||
} | ||
Tabs.getDerivedStateFromProps = function getDerivedStateFromProps(props, state) { | ||
return Tabs.copyPropsToState(props, state); | ||
}; | ||
checkForIllegalModeChange(props, mode); | ||
Tabs.getModeFromProps = function getModeFromProps(props) { | ||
return props.selectedIndex === null ? MODE_UNCONTROLLED : MODE_CONTROLLED; | ||
}; | ||
var handleSelected = function handleSelected(index, last, event) { | ||
// Call change event handler | ||
if (typeof onSelect === 'function') { | ||
// Check if the change event handler cancels the tab change | ||
if (onSelect(index, last, event) === false) return; | ||
} // Always set focus on tabs | ||
// preserve the existing selectedIndex from state. | ||
// If the state has not selectedIndex, default to the defaultIndex or 0 | ||
Tabs.copyPropsToState = function copyPropsToState(props, state, focus) { | ||
if (focus === void 0) { | ||
focus = false; | ||
} | ||
if (state.mode !== undefined && state.mode !== Tabs.getModeFromProps(props)) { | ||
throw new Error("Switching between controlled mode (by using `selectedIndex`) and uncontrolled mode is not supported in `Tabs`.\nFor more information about controlled and uncontrolled mode of react-tabs see https://github.com/reactjs/react-tabs#controlled-vs-uncontrolled-mode."); | ||
} | ||
setFocus(true); | ||
var newState = { | ||
focus: focus, | ||
mode: Tabs.getModeFromProps(props) | ||
}; | ||
if (newState.mode === MODE_UNCONTROLLED) { | ||
var maxTabIndex = Math.max(0, getTabsCount(props.children) - 1); | ||
var selectedIndex = null; | ||
if (state.selectedIndex != null) { | ||
selectedIndex = Math.min(state.selectedIndex, maxTabIndex); | ||
} else { | ||
selectedIndex = props.defaultIndex || 0; | ||
} | ||
newState.selectedIndex = selectedIndex; | ||
if (mode === MODE_UNCONTROLLED) { | ||
// Update selected index | ||
setSelectedIndex(index); | ||
} | ||
return newState; | ||
}; | ||
var _proto = Tabs.prototype; | ||
var subProps = _extends({}, props); | ||
_proto.render = function render() { | ||
var _this$props = this.props, | ||
children = _this$props.children; | ||
_this$props.defaultIndex; | ||
_this$props.defaultFocus; | ||
var props = _objectWithoutPropertiesLoose(_this$props, _excluded$3); | ||
subProps.focus = focus; | ||
subProps.onSelect = handleSelected; | ||
var _this$state = this.state, | ||
focus = _this$state.focus, | ||
selectedIndex = _this$state.selectedIndex; | ||
props.focus = focus; | ||
props.onSelect = this.handleSelected; | ||
if (selectedIndex != null) { | ||
subProps.selectedIndex = selectedIndex; | ||
} | ||
if (selectedIndex != null) { | ||
props.selectedIndex = selectedIndex; | ||
} | ||
delete subProps.defaultFocus; | ||
delete subProps.defaultIndex; | ||
return /*#__PURE__*/React__default["default"].createElement(UncontrolledTabs, subProps, children); | ||
}; | ||
return /*#__PURE__*/React__default["default"].createElement(UncontrolledTabs, props, children); | ||
}; | ||
return Tabs; | ||
}(React.Component); | ||
Tabs.defaultProps = { | ||
defaultFocus: false, | ||
forceRenderTabPanel: false, | ||
selectedIndex: null, | ||
defaultIndex: null, | ||
environment: null, | ||
disableUpDownKeys: false | ||
}; | ||
Tabs.propTypes = { | ||
children: childrenPropType, | ||
direction: PropTypes__default["default"].oneOf(['rtl', 'ltr']), | ||
className: PropTypes__default["default"].oneOfType([PropTypes__default["default"].string, PropTypes__default["default"].array, PropTypes__default["default"].object]), | ||
defaultFocus: PropTypes__default["default"].bool, | ||
defaultIndex: PropTypes__default["default"].number, | ||
disabledTabClassName: PropTypes__default["default"].string, | ||
disableUpDownKeys: PropTypes__default["default"].bool, | ||
domRef: PropTypes__default["default"].func, | ||
forceRenderTabPanel: PropTypes__default["default"].bool, | ||
onSelect: onSelectPropType, | ||
selectedIndex: selectedIndexPropType, | ||
selectedTabClassName: PropTypes__default["default"].string, | ||
selectedTabPanelClassName: PropTypes__default["default"].string, | ||
environment: PropTypes__default["default"].object | ||
} ; | ||
Tabs.propTypes = propTypes$3 ; | ||
Tabs.defaultProps = defaultProps$2; | ||
Tabs.tabsRole = 'Tabs'; | ||
var _excluded$2 = ["children", "className"]; | ||
var TabList = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(TabList, _Component); | ||
function TabList() { | ||
return _Component.apply(this, arguments) || this; | ||
} | ||
var _proto = TabList.prototype; | ||
_proto.render = function render() { | ||
var _this$props = this.props, | ||
children = _this$props.children, | ||
className = _this$props.className, | ||
attributes = _objectWithoutPropertiesLoose(_this$props, _excluded$2); | ||
return /*#__PURE__*/React__default["default"].createElement("ul", _extends({}, attributes, { | ||
className: cx(className), | ||
role: "tablist" | ||
}), children); | ||
}; | ||
return TabList; | ||
}(React.Component); | ||
TabList.defaultProps = { | ||
var defaultProps$1 = { | ||
className: 'react-tabs__tab-list' | ||
}; | ||
TabList.propTypes = { | ||
var propTypes$2 = { | ||
children: PropTypes__default["default"].oneOfType([PropTypes__default["default"].object, PropTypes__default["default"].array]), | ||
className: PropTypes__default["default"].oneOfType([PropTypes__default["default"].string, PropTypes__default["default"].array, PropTypes__default["default"].object]) | ||
} ; | ||
var TabList = function TabList(props) { | ||
var children = props.children, | ||
className = props.className, | ||
attributes = _objectWithoutPropertiesLoose(props, _excluded$2); | ||
return /*#__PURE__*/React__default["default"].createElement("ul", _extends({}, attributes, { | ||
className: cx(className), | ||
role: "tablist" | ||
}), children); | ||
}; | ||
TabList.tabsRole = 'TabList'; | ||
TabList.propTypes = propTypes$2 ; | ||
TabList.defaultProps = defaultProps$1; | ||
var _excluded$1 = ["children", "className", "disabled", "disabledClassName", "focus", "id", "panelId", "selected", "selectedClassName", "tabIndex", "tabRef"]; | ||
var DEFAULT_CLASS$1 = 'react-tabs__tab'; | ||
var Tab = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(Tab, _Component); | ||
function Tab() { | ||
return _Component.apply(this, arguments) || this; | ||
} | ||
var _proto = Tab.prototype; | ||
_proto.componentDidMount = function componentDidMount() { | ||
this.checkFocus(); | ||
}; | ||
_proto.componentDidUpdate = function componentDidUpdate() { | ||
this.checkFocus(); | ||
}; | ||
_proto.checkFocus = function checkFocus() { | ||
var _this$props = this.props, | ||
selected = _this$props.selected, | ||
focus = _this$props.focus; | ||
if (selected && focus) { | ||
this.node.focus(); | ||
} | ||
}; | ||
_proto.render = function render() { | ||
var _cx, | ||
_this = this; | ||
var _this$props2 = this.props, | ||
children = _this$props2.children, | ||
className = _this$props2.className, | ||
disabled = _this$props2.disabled, | ||
disabledClassName = _this$props2.disabledClassName; | ||
_this$props2.focus; | ||
var id = _this$props2.id, | ||
panelId = _this$props2.panelId, | ||
selected = _this$props2.selected, | ||
selectedClassName = _this$props2.selectedClassName, | ||
tabIndex = _this$props2.tabIndex, | ||
tabRef = _this$props2.tabRef, | ||
attributes = _objectWithoutPropertiesLoose(_this$props2, _excluded$1); | ||
return /*#__PURE__*/React__default["default"].createElement("li", _extends({}, attributes, { | ||
className: cx(className, (_cx = {}, _cx[selectedClassName] = selected, _cx[disabledClassName] = disabled, _cx)), | ||
ref: function ref(node) { | ||
_this.node = node; | ||
if (tabRef) tabRef(node); | ||
}, | ||
role: "tab", | ||
id: id, | ||
"aria-selected": selected ? 'true' : 'false', | ||
"aria-disabled": disabled ? 'true' : 'false', | ||
"aria-controls": panelId, | ||
tabIndex: tabIndex || (selected ? '0' : null), | ||
"data-rttab": true | ||
}), children); | ||
}; | ||
return Tab; | ||
}(React.Component); | ||
Tab.defaultProps = { | ||
var DEFAULT_PROPS = { | ||
className: DEFAULT_CLASS$1, | ||
@@ -882,3 +740,3 @@ disabledClassName: DEFAULT_CLASS$1 + "--disabled", | ||
}; | ||
Tab.propTypes = { | ||
var propTypes$1 = { | ||
children: PropTypes__default["default"].oneOfType([PropTypes__default["default"].array, PropTypes__default["default"].object, PropTypes__default["default"].string]), | ||
@@ -898,44 +756,59 @@ className: PropTypes__default["default"].oneOfType([PropTypes__default["default"].string, PropTypes__default["default"].array, PropTypes__default["default"].object]), | ||
selectedClassName: PropTypes__default["default"].string, | ||
tabRef: PropTypes__default["default"].func // private | ||
tabRef: PropTypes__default["default"].func | ||
} ; | ||
Tab.tabsRole = 'Tab'; | ||
var _excluded = ["children", "className", "forceRender", "id", "selected", "selectedClassName", "tabId"]; | ||
var DEFAULT_CLASS = 'react-tabs__tab-panel'; | ||
var Tab = function Tab(props) { | ||
var _cx; | ||
var TabPanel = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(TabPanel, _Component); | ||
var nodeRef = React.useRef(); | ||
function TabPanel() { | ||
return _Component.apply(this, arguments) || this; | ||
} | ||
var checkFocus = function checkFocus() { | ||
var selected = props.selected, | ||
focus = props.focus; | ||
var _proto = TabPanel.prototype; | ||
if (selected && focus) { | ||
nodeRef.current.focus(); | ||
} | ||
}; | ||
_proto.render = function render() { | ||
var _cx; | ||
React.useEffect(function () { | ||
checkFocus(); | ||
}); | ||
var _this$props = this.props, | ||
children = _this$props.children, | ||
className = _this$props.className, | ||
forceRender = _this$props.forceRender, | ||
id = _this$props.id, | ||
selected = _this$props.selected, | ||
selectedClassName = _this$props.selectedClassName, | ||
tabId = _this$props.tabId, | ||
attributes = _objectWithoutPropertiesLoose(_this$props, _excluded); | ||
var children = props.children, | ||
className = props.className, | ||
disabled = props.disabled, | ||
disabledClassName = props.disabledClassName; | ||
props.focus; | ||
var id = props.id, | ||
panelId = props.panelId, | ||
selected = props.selected, | ||
selectedClassName = props.selectedClassName, | ||
tabIndex = props.tabIndex, | ||
tabRef = props.tabRef, | ||
attributes = _objectWithoutPropertiesLoose(props, _excluded$1); | ||
return /*#__PURE__*/React__default["default"].createElement("div", _extends({}, attributes, { | ||
className: cx(className, (_cx = {}, _cx[selectedClassName] = selected, _cx)), | ||
role: "tabpanel", | ||
id: id, | ||
"aria-labelledby": tabId | ||
}), forceRender || selected ? children : null); | ||
}; | ||
return /*#__PURE__*/React__default["default"].createElement("li", _extends({}, attributes, { | ||
className: cx(className, (_cx = {}, _cx[selectedClassName] = selected, _cx[disabledClassName] = disabled, _cx)), | ||
ref: function ref(node) { | ||
nodeRef.current = node; | ||
if (tabRef) tabRef(node); | ||
}, | ||
role: "tab", | ||
id: id, | ||
"aria-selected": selected ? 'true' : 'false', | ||
"aria-disabled": disabled ? 'true' : 'false', | ||
"aria-controls": panelId, | ||
tabIndex: tabIndex || (selected ? '0' : null), | ||
"data-rttab": true | ||
}), children); | ||
}; | ||
return TabPanel; | ||
}(React.Component); | ||
Tab.propTypes = propTypes$1 ; | ||
Tab.tabsRole = 'Tab'; | ||
Tab.defaultProps = DEFAULT_PROPS; | ||
TabPanel.defaultProps = { | ||
var _excluded = ["children", "className", "forceRender", "id", "selected", "selectedClassName", "tabId"]; | ||
var DEFAULT_CLASS = 'react-tabs__tab-panel'; | ||
var defaultProps = { | ||
className: DEFAULT_CLASS, | ||
@@ -945,3 +818,3 @@ forceRender: false, | ||
}; | ||
TabPanel.propTypes = { | ||
var propTypes = { | ||
children: PropTypes__default["default"].node, | ||
@@ -958,3 +831,26 @@ className: PropTypes__default["default"].oneOfType([PropTypes__default["default"].string, PropTypes__default["default"].array, PropTypes__default["default"].object]), | ||
} ; | ||
var TabPanel = function TabPanel(props) { | ||
var _cx; | ||
var children = props.children, | ||
className = props.className, | ||
forceRender = props.forceRender, | ||
id = props.id, | ||
selected = props.selected, | ||
selectedClassName = props.selectedClassName, | ||
tabId = props.tabId, | ||
attributes = _objectWithoutPropertiesLoose(props, _excluded); | ||
return /*#__PURE__*/React__default["default"].createElement("div", _extends({}, attributes, { | ||
className: cx(className, (_cx = {}, _cx[selectedClassName] = selected, _cx)), | ||
role: "tabpanel", | ||
id: id, | ||
"aria-labelledby": tabId | ||
}), forceRender || selected ? children : null); | ||
}; | ||
TabPanel.tabsRole = 'TabPanel'; | ||
TabPanel.propTypes = propTypes ; | ||
TabPanel.defaultProps = defaultProps; | ||
@@ -961,0 +857,0 @@ exports.Tab = Tab; |
@@ -1,2 +0,2 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ReactTabs={},e.React)}(this,(function(e,t){"use strict";function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var r=n(t);function a(){return a=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},a.apply(this,arguments)}function s(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,o(e,t)}function o(e,t){return o=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},o(e,t)}function l(e,t){if(null==e)return{};var n,r,a={},s=Object.keys(e);for(r=0;r<s.length;r++)n=s[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}function i(e){return function(t){return!!t.type&&t.type.tabsRole===e}}var d=i("Tab"),c=i("TabList"),u=i("TabPanel");function f(e,n){return t.Children.map(e,(function(e){return null===e?null:function(e){return d(e)||c(e)||u(e)}(e)?n(e):e.props&&e.props.children&&"object"==typeof e.props.children?t.cloneElement(e,a({},e.props,{children:f(e.props.children,n)})):e}))}function p(e,n){return t.Children.forEach(e,(function(e){null!==e&&(d(e)||u(e)?n(e):e.props&&e.props.children&&"object"==typeof e.props.children&&(c(e)&&n(e),p(e.props.children,n)))}))}function b(e){var t,n,r="";if("string"==typeof e||"number"==typeof e)r+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;t<e.length;t++)e[t]&&(n=b(e[t]))&&(r&&(r+=" "),r+=n);else for(t in e)e[t]&&(r&&(r+=" "),r+=t);return r}function h(){for(var e,t,n=0,r="";n<arguments.length;)(e=arguments[n++])&&(t=b(e))&&(r&&(r+=" "),r+=t);return r}var m=0;function v(){return"react-tabs-"+m++}function y(e){var t=0;return p(e,(function(e){d(e)&&t++})),t}var T,C=["children","className","disabledTabClassName","domRef","focus","forceRenderTabPanel","onSelect","selectedIndex","selectedTabClassName","selectedTabPanelClassName","environment","disableUpDownKeys"];function g(e){return e&&"getAttribute"in e}function N(e){return g(e)&&e.getAttribute("data-rttab")}function I(e){return g(e)&&"true"===e.getAttribute("aria-disabled")}var x=function(e){function n(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).tabNodes=[],t.handleKeyDown=function(e){var n=t.props,r=n.direction,a=n.disableUpDownKeys;if(t.isTabFromContainer(e.target)){var s=t.props.selectedIndex,o=!1,l=!1;32!==e.keyCode&&13!==e.keyCode||(o=!0,l=!1,t.handleClick(e)),37===e.keyCode||!a&&38===e.keyCode?(s="rtl"===r?t.getNextTab(s):t.getPrevTab(s),o=!0,l=!0):39===e.keyCode||!a&&40===e.keyCode?(s="rtl"===r?t.getPrevTab(s):t.getNextTab(s),o=!0,l=!0):35===e.keyCode?(s=t.getLastTab(),o=!0,l=!0):36===e.keyCode&&(s=t.getFirstTab(),o=!0,l=!0),o&&e.preventDefault(),l&&t.setSelected(s,e)}},t.handleClick=function(e){var n=e.target;do{if(t.isTabFromContainer(n)){if(I(n))return;var r=[].slice.call(n.parentNode.children).filter(N).indexOf(n);return void t.setSelected(r,e)}}while(null!=(n=n.parentNode))},t}s(n,e);var o=n.prototype;return o.setSelected=function(e,t){if(!(e<0||e>=this.getTabsCount())){var n=this.props;(0,n.onSelect)(e,n.selectedIndex,t)}},o.getNextTab=function(e){for(var t=this.getTabsCount(),n=e+1;n<t;n++)if(!I(this.getTab(n)))return n;for(var r=0;r<e;r++)if(!I(this.getTab(r)))return r;return e},o.getPrevTab=function(e){for(var t=e;t--;)if(!I(this.getTab(t)))return t;for(t=this.getTabsCount();t-- >e;)if(!I(this.getTab(t)))return t;return e},o.getFirstTab=function(){for(var e=this.getTabsCount(),t=0;t<e;t++)if(!I(this.getTab(t)))return t;return null},o.getLastTab=function(){for(var e=this.getTabsCount();e--;)if(!I(this.getTab(e)))return e;return null},o.getTabsCount=function(){return y(this.props.children)},o.getPanelsCount=function(){return function(e){var t=0;return p(e,(function(e){u(e)&&t++})),t}(this.props.children)},o.getTab=function(e){return this.tabNodes["tabs-"+e]},o.getChildren=function(){var e=this,n=0,a=this.props,s=a.children,o=a.disabledTabClassName,l=a.focus,i=a.forceRenderTabPanel,p=a.selectedIndex,b=a.selectedTabClassName,h=a.selectedTabPanelClassName,m=a.environment;this.tabIds=this.tabIds||[],this.panelIds=this.panelIds||[];for(var y=this.tabIds.length-this.getTabsCount();y++<0;)this.tabIds.push(v()),this.panelIds.push(v());return f(s,(function(a){var s=a;if(c(a)){var v=0,y=!1;null==T&&function(e){var t=e||("undefined"!=typeof window?window:void 0);try{T=!(void 0===t||!t.document||!t.document.activeElement)}catch(e){T=!1}}(m),T&&(y=r.default.Children.toArray(a.props.children).filter(d).some((function(t,n){var r=m||("undefined"!=typeof window?window:void 0);return r&&r.document.activeElement===e.getTab(n)}))),s=t.cloneElement(a,{children:f(a.props.children,(function(n){var r="tabs-"+v,a=p===v,s={tabRef:function(t){e.tabNodes[r]=t},id:e.tabIds[v],panelId:e.panelIds[v],selected:a,focus:a&&(l||y)};return b&&(s.selectedClassName=b),o&&(s.disabledClassName=o),v++,t.cloneElement(n,s)}))})}else if(u(a)){var C={id:e.panelIds[n],tabId:e.tabIds[n],selected:p===n};i&&(C.forceRender=i),h&&(C.selectedClassName=h),n++,s=t.cloneElement(a,C)}return s}))},o.isTabFromContainer=function(e){if(!N(e))return!1;var t=e.parentElement;do{if(t===this.node)return!0;if(t.getAttribute("data-rttabs"))break;t=t.parentElement}while(t);return!1},o.render=function(){var e=this,t=this.props;t.children;var n=t.className;t.disabledTabClassName;var s=t.domRef;t.focus,t.forceRenderTabPanel,t.onSelect,t.selectedIndex,t.selectedTabClassName,t.selectedTabPanelClassName,t.environment,t.disableUpDownKeys;var o=l(t,C);return r.default.createElement("div",a({},o,{className:h(n),onClick:this.handleClick,onKeyDown:this.handleKeyDown,ref:function(t){e.node=t,s&&s(t)},"data-rttabs":!0}),this.getChildren())},n}(t.Component);x.defaultProps={className:"react-tabs",focus:!1};var P=["children","defaultIndex","defaultFocus"],w=function(e){function t(n){var r;return(r=e.call(this,n)||this).handleSelected=function(e,t,n){var a=r.props.onSelect,s=r.state.mode;if("function"!=typeof a||!1!==a(e,t,n)){var o={focus:"keydown"===n.type};1===s&&(o.selectedIndex=e),r.setState(o)}},r.state=t.copyPropsToState(r.props,{},n.defaultFocus),r}return s(t,e),t.getDerivedStateFromProps=function(e,n){return t.copyPropsToState(e,n)},t.getModeFromProps=function(e){return null===e.selectedIndex?1:0},t.copyPropsToState=function(e,n,r){void 0===r&&(r=!1);var a={focus:r,mode:t.getModeFromProps(e)};if(1===a.mode){var s=Math.max(0,y(e.children)-1),o=null;o=null!=n.selectedIndex?Math.min(n.selectedIndex,s):e.defaultIndex||0,a.selectedIndex=o}return a},t.prototype.render=function(){var e=this.props,t=e.children;e.defaultIndex,e.defaultFocus;var n=l(e,P),a=this.state,s=a.focus,o=a.selectedIndex;return n.focus=s,n.onSelect=this.handleSelected,null!=o&&(n.selectedIndex=o),r.default.createElement(x,n,t)},t}(t.Component);w.defaultProps={defaultFocus:!1,forceRenderTabPanel:!1,selectedIndex:null,defaultIndex:null,environment:null,disableUpDownKeys:!1},w.tabsRole="Tabs";var R=["children","className"],k=function(e){function t(){return e.apply(this,arguments)||this}return s(t,e),t.prototype.render=function(){var e=this.props,t=e.children,n=e.className,s=l(e,R);return r.default.createElement("ul",a({},s,{className:h(n),role:"tablist"}),t)},t}(t.Component);k.defaultProps={className:"react-tabs__tab-list"},k.tabsRole="TabList";var _=["children","className","disabled","disabledClassName","focus","id","panelId","selected","selectedClassName","tabIndex","tabRef"],F="react-tabs__tab",S=function(e){function t(){return e.apply(this,arguments)||this}s(t,e);var n=t.prototype;return n.componentDidMount=function(){this.checkFocus()},n.componentDidUpdate=function(){this.checkFocus()},n.checkFocus=function(){var e=this.props,t=e.selected,n=e.focus;t&&n&&this.node.focus()},n.render=function(){var e,t=this,n=this.props,s=n.children,o=n.className,i=n.disabled,d=n.disabledClassName;n.focus;var c=n.id,u=n.panelId,f=n.selected,p=n.selectedClassName,b=n.tabIndex,m=n.tabRef,v=l(n,_);return r.default.createElement("li",a({},v,{className:h(o,(e={},e[p]=f,e[d]=i,e)),ref:function(e){t.node=e,m&&m(e)},role:"tab",id:c,"aria-selected":f?"true":"false","aria-disabled":i?"true":"false","aria-controls":u,tabIndex:b||(f?"0":null),"data-rttab":!0}),s)},t}(t.Component);S.defaultProps={className:F,disabledClassName:"react-tabs__tab--disabled",focus:!1,id:null,panelId:null,selected:!1,selectedClassName:"react-tabs__tab--selected"},S.tabsRole="Tab";var E=["children","className","forceRender","id","selected","selectedClassName","tabId"],j="react-tabs__tab-panel",D=function(e){function t(){return e.apply(this,arguments)||this}return s(t,e),t.prototype.render=function(){var e,t=this.props,n=t.children,s=t.className,o=t.forceRender,i=t.id,d=t.selected,c=t.selectedClassName,u=t.tabId,f=l(t,E);return r.default.createElement("div",a({},f,{className:h(s,(e={},e[c]=d,e)),role:"tabpanel",id:i,"aria-labelledby":u}),o||d?n:null)},t}(t.Component);D.defaultProps={className:j,forceRender:!1,selectedClassName:j+"--selected"},D.tabsRole="TabPanel",e.Tab=S,e.TabList=k,e.TabPanel=D,e.Tabs=w,e.resetIdCounter=function(){m=0},Object.defineProperty(e,"__esModule",{value:!0})})); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ReactTabs={},e.React)}(this,(function(e,t){"use strict";function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var r=n(t);function a(){return a=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},a.apply(this,arguments)}function l(e,t){if(null==e)return{};var n,r,a={},l=Object.keys(e);for(r=0;r<l.length;r++)n=l[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}function s(e){return function(t){return!!t.type&&t.type.tabsRole===e}}var c=s("Tab"),u=s("TabList"),d=s("TabPanel");function o(e,n){return t.Children.map(e,(function(e){return null===e?null:function(e){return c(e)||u(e)||d(e)}(e)?n(e):e.props&&e.props.children&&"object"==typeof e.props.children?t.cloneElement(e,a({},e.props,{children:o(e.props.children,n)})):e}))}function i(e,n){return t.Children.forEach(e,(function(e){null!==e&&(c(e)||d(e)?n(e):e.props&&e.props.children&&"object"==typeof e.props.children&&(u(e)&&n(e),i(e.props.children,n)))}))}function f(e){var t,n,r="";if("string"==typeof e||"number"==typeof e)r+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;t<e.length;t++)e[t]&&(n=f(e[t]))&&(r&&(r+=" "),r+=n);else for(t in e)e[t]&&(r&&(r+=" "),r+=t);return r}function b(){for(var e,t,n=0,r="";n<arguments.length;)(e=arguments[n++])&&(t=f(e))&&(r&&(r+=" "),r+=t);return r}var p=0;function m(){return"react-tabs-"+p++}function v(e){var t=0;return i(e,(function(e){c(e)&&t++})),t}var h,N=["children","className","disabledTabClassName","domRef","focus","forceRenderTabPanel","onSelect","selectedIndex","selectedTabClassName","selectedTabPanelClassName","environment","disableUpDownKeys"];function y(e){return e&&"getAttribute"in e}function C(e){return y(e)&&e.getAttribute("data-rttab")}function T(e){return y(e)&&"true"===e.getAttribute("aria-disabled")}var R=function(e){var n=t.useRef([]),s=t.useRef([]),i=t.useRef([]),f=t.useRef();function p(t,n){t<0||t>=I()||(0,e.onSelect)(t,e.selectedIndex,n)}function y(e){for(var t=I(),n=e+1;n<t;n++)if(!T(x(n)))return n;for(var r=0;r<e;r++)if(!T(x(r)))return r;return e}function R(e){for(var t=e;t--;)if(!T(x(t)))return t;for(t=I();t-- >e;)if(!T(x(t)))return t;return e}function I(){return v(e.children)}function x(e){return n.current["tabs-"+e]}function E(e){var t=e.target;do{if(P(t)){if(T(t))return;return void p([].slice.call(t.parentNode.children).filter(C).indexOf(t),e)}}while(null!=(t=t.parentNode))}function P(e){if(!C(e))return!1;var t=e.parentElement;do{if(t===f.current)return!0;if(t.getAttribute("data-rttabs"))break;t=t.parentElement}while(t);return!1}e.children;var w=e.className;e.disabledTabClassName;var g=e.domRef;e.focus,e.forceRenderTabPanel,e.onSelect,e.selectedIndex,e.selectedTabClassName,e.selectedTabPanelClassName,e.environment,e.disableUpDownKeys;var _=l(e,N);return r.default.createElement("div",a({},_,{className:b(w),onClick:E,onKeyDown:function(t){var n=e.direction,r=e.disableUpDownKeys;if(P(t.target)){var a=e.selectedIndex,l=!1,s=!1;32!==t.keyCode&&13!==t.keyCode||(l=!0,s=!1,E(t)),37===t.keyCode||!r&&38===t.keyCode?(a="rtl"===n?y(a):R(a),l=!0,s=!0):39===t.keyCode||!r&&40===t.keyCode?(a="rtl"===n?R(a):y(a),l=!0,s=!0):35===t.keyCode?(a=function(){for(var e=I();e--;)if(!T(x(e)))return e;return null}(),l=!0,s=!0):36===t.keyCode&&(a=function(){for(var e=I(),t=0;t<e;t++)if(!T(x(t)))return t;return null}(),l=!0,s=!0),l&&t.preventDefault(),s&&p(a,t)}},ref:function(e){f.current=e,g&&g(e)},"data-rttabs":!0}),function(){var a=0,l=e.children,f=e.disabledTabClassName,b=e.focus,p=e.forceRenderTabPanel,v=e.selectedIndex,N=e.selectedTabClassName,y=e.selectedTabPanelClassName,C=e.environment;s.current=s.current||[],i.current=i.current||[];for(var T=s.current.length-I();T++<0;)s.current.push(m()),i.current.push(m());return o(l,(function(e){var l=e;if(u(e)){var m=0,T=!1;null==h&&function(e){var t=e||("undefined"!=typeof window?window:void 0);try{h=!(void 0===t||!t.document||!t.document.activeElement)}catch(e){h=!1}}(C),h&&(T=r.default.Children.toArray(e.props.children).filter(c).some((function(e,t){var n=C||("undefined"!=typeof window?window:void 0);return n&&n.document.activeElement===x(t)}))),l=t.cloneElement(e,{children:o(e.props.children,(function(e){var r="tabs-"+m,a=v===m,l={tabRef:function(e){n.current[r]=e},id:s.current[m],panelId:i.current[m],selected:a,focus:a&&(b||T)};return N&&(l.selectedClassName=N),f&&(l.disabledClassName=f),m++,t.cloneElement(e,l)}))})}else if(d(e)){var R={id:i.current[a],tabId:s.current[a],selected:v===a};p&&(R.forceRender=p),y&&(R.selectedClassName=y),a++,l=t.cloneElement(e,R)}return l}))}())};R.defaultProps={className:"react-tabs",focus:!1};var I=function(e){var n=e.children,l=e.defaultFocus,s=e.defaultIndex,c=e.onSelect,u=t.useState(l),d=u[0],o=u[1],i=t.useState(function(e){return null===e.selectedIndex?1:0}(e)),f=i[0],b=t.useState(1===f?s||0:null),p=b[0],m=b[1];if(t.useEffect((function(){o(!1)}),[]),1===f){var h=v(n);t.useEffect((function(){if(null!=p){var e=Math.max(0,h-1);m(Math.min(p,e))}}),[h])}var N=a({},e);return N.focus=d,N.onSelect=function(e,t,n){"function"==typeof c&&!1===c(e,t,n)||(o(!0),1===f&&m(e))},null!=p&&(N.selectedIndex=p),delete N.defaultFocus,delete N.defaultIndex,r.default.createElement(R,N,n)};I.defaultProps={defaultFocus:!1,forceRenderTabPanel:!1,selectedIndex:null,defaultIndex:null,environment:null,disableUpDownKeys:!1},I.tabsRole="Tabs";var x=["children","className"],E=function(e){var t=e.children,n=e.className,s=l(e,x);return r.default.createElement("ul",a({},s,{className:b(n),role:"tablist"}),t)};E.tabsRole="TabList",E.defaultProps={className:"react-tabs__tab-list"};var P=["children","className","disabled","disabledClassName","focus","id","panelId","selected","selectedClassName","tabIndex","tabRef"],w="react-tabs__tab",g={className:w,disabledClassName:"react-tabs__tab--disabled",focus:!1,id:null,panelId:null,selected:!1,selectedClassName:"react-tabs__tab--selected"},_=function(e){var n,s=t.useRef();t.useEffect((function(){!function(){var t=e.selected,n=e.focus;t&&n&&s.current.focus()}()}));var c=e.children,u=e.className,d=e.disabled,o=e.disabledClassName;e.focus;var i=e.id,f=e.panelId,p=e.selected,m=e.selectedClassName,v=e.tabIndex,h=e.tabRef,N=l(e,P);return r.default.createElement("li",a({},N,{className:b(u,(n={},n[m]=p,n[o]=d,n)),ref:function(e){s.current=e,h&&h(e)},role:"tab",id:i,"aria-selected":p?"true":"false","aria-disabled":d?"true":"false","aria-controls":f,tabIndex:v||(p?"0":null),"data-rttab":!0}),c)};_.tabsRole="Tab",_.defaultProps=g;var k=["children","className","forceRender","id","selected","selectedClassName","tabId"],j="react-tabs__tab-panel",S={className:j,forceRender:!1,selectedClassName:j+"--selected"},A=function(e){var t,n=e.children,s=e.className,c=e.forceRender,u=e.id,d=e.selected,o=e.selectedClassName,i=e.tabId,f=l(e,k);return r.default.createElement("div",a({},f,{className:b(s,(t={},t[o]=d,t)),role:"tabpanel",id:u,"aria-labelledby":i}),c||d?n:null)};A.tabsRole="TabPanel",A.defaultProps=S,e.Tab=_,e.TabList=E,e.TabPanel=A,e.Tabs=I,e.resetIdCounter=function(){p=0},Object.defineProperty(e,"__esModule",{value:!0})})); | ||
//# sourceMappingURL=react-tabs.production.min.js.map |
@@ -7,76 +7,7 @@ var _excluded = ["children", "className", "disabled", "disabledClassName", "focus", "id", "panelId", "selected", "selectedClassName", "tabIndex", "tabRef"]; | ||
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
import PropTypes from 'prop-types'; | ||
import React, { Component } from 'react'; | ||
import React, { useEffect, useRef } from 'react'; | ||
import cx from 'clsx'; | ||
var DEFAULT_CLASS = 'react-tabs__tab'; | ||
var Tab = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(Tab, _Component); | ||
function Tab() { | ||
return _Component.apply(this, arguments) || this; | ||
} | ||
var _proto = Tab.prototype; | ||
_proto.componentDidMount = function componentDidMount() { | ||
this.checkFocus(); | ||
}; | ||
_proto.componentDidUpdate = function componentDidUpdate() { | ||
this.checkFocus(); | ||
}; | ||
_proto.checkFocus = function checkFocus() { | ||
var _this$props = this.props, | ||
selected = _this$props.selected, | ||
focus = _this$props.focus; | ||
if (selected && focus) { | ||
this.node.focus(); | ||
} | ||
}; | ||
_proto.render = function render() { | ||
var _cx, | ||
_this = this; | ||
var _this$props2 = this.props, | ||
children = _this$props2.children, | ||
className = _this$props2.className, | ||
disabled = _this$props2.disabled, | ||
disabledClassName = _this$props2.disabledClassName, | ||
focus = _this$props2.focus, | ||
id = _this$props2.id, | ||
panelId = _this$props2.panelId, | ||
selected = _this$props2.selected, | ||
selectedClassName = _this$props2.selectedClassName, | ||
tabIndex = _this$props2.tabIndex, | ||
tabRef = _this$props2.tabRef, | ||
attributes = _objectWithoutPropertiesLoose(_this$props2, _excluded); | ||
return /*#__PURE__*/React.createElement("li", _extends({}, attributes, { | ||
className: cx(className, (_cx = {}, _cx[selectedClassName] = selected, _cx[disabledClassName] = disabled, _cx)), | ||
ref: function ref(node) { | ||
_this.node = node; | ||
if (tabRef) tabRef(node); | ||
}, | ||
role: "tab", | ||
id: id, | ||
"aria-selected": selected ? 'true' : 'false', | ||
"aria-disabled": disabled ? 'true' : 'false', | ||
"aria-controls": panelId, | ||
tabIndex: tabIndex || (selected ? '0' : null), | ||
"data-rttab": true | ||
}), children); | ||
}; | ||
return Tab; | ||
}(Component); | ||
Tab.defaultProps = { | ||
var DEFAULT_PROPS = { | ||
className: DEFAULT_CLASS, | ||
@@ -90,4 +21,3 @@ disabledClassName: DEFAULT_CLASS + "--disabled", | ||
}; | ||
export { Tab as default }; | ||
Tab.propTypes = process.env.NODE_ENV !== "production" ? { | ||
var propTypes = process.env.NODE_ENV !== "production" ? { | ||
children: PropTypes.oneOfType([PropTypes.array, PropTypes.object, PropTypes.string]), | ||
@@ -107,5 +37,55 @@ className: PropTypes.oneOfType([PropTypes.string, PropTypes.array, PropTypes.object]), | ||
selectedClassName: PropTypes.string, | ||
tabRef: PropTypes.func // private | ||
tabRef: PropTypes.func | ||
} : {}; | ||
} : {}; | ||
Tab.tabsRole = 'Tab'; | ||
var Tab = function Tab(props) { | ||
var _cx; | ||
var nodeRef = useRef(); | ||
var checkFocus = function checkFocus() { | ||
var selected = props.selected, | ||
focus = props.focus; | ||
if (selected && focus) { | ||
nodeRef.current.focus(); | ||
} | ||
}; | ||
useEffect(function () { | ||
checkFocus(); | ||
}); | ||
var children = props.children, | ||
className = props.className, | ||
disabled = props.disabled, | ||
disabledClassName = props.disabledClassName, | ||
focus = props.focus, | ||
id = props.id, | ||
panelId = props.panelId, | ||
selected = props.selected, | ||
selectedClassName = props.selectedClassName, | ||
tabIndex = props.tabIndex, | ||
tabRef = props.tabRef, | ||
attributes = _objectWithoutPropertiesLoose(props, _excluded); | ||
return /*#__PURE__*/React.createElement("li", _extends({}, attributes, { | ||
className: cx(className, (_cx = {}, _cx[selectedClassName] = selected, _cx[disabledClassName] = disabled, _cx)), | ||
ref: function ref(node) { | ||
nodeRef.current = node; | ||
if (tabRef) tabRef(node); | ||
}, | ||
role: "tab", | ||
id: id, | ||
"aria-selected": selected ? 'true' : 'false', | ||
"aria-disabled": disabled ? 'true' : 'false', | ||
"aria-controls": panelId, | ||
tabIndex: tabIndex || (selected ? '0' : null), | ||
"data-rttab": true | ||
}), children); | ||
}; | ||
Tab.propTypes = process.env.NODE_ENV !== "production" ? propTypes : {}; | ||
Tab.tabsRole = 'Tab'; | ||
Tab.defaultProps = DEFAULT_PROPS; | ||
export default Tab; |
@@ -7,42 +7,27 @@ var _excluded = ["children", "className"]; | ||
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
import PropTypes from 'prop-types'; | ||
import React, { Component } from 'react'; | ||
import React from 'react'; | ||
import cx from 'clsx'; | ||
var TabList = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(TabList, _Component); | ||
function TabList() { | ||
return _Component.apply(this, arguments) || this; | ||
} | ||
var _proto = TabList.prototype; | ||
_proto.render = function render() { | ||
var _this$props = this.props, | ||
children = _this$props.children, | ||
className = _this$props.className, | ||
attributes = _objectWithoutPropertiesLoose(_this$props, _excluded); | ||
return /*#__PURE__*/React.createElement("ul", _extends({}, attributes, { | ||
className: cx(className), | ||
role: "tablist" | ||
}), children); | ||
}; | ||
return TabList; | ||
}(Component); | ||
TabList.defaultProps = { | ||
var defaultProps = { | ||
className: 'react-tabs__tab-list' | ||
}; | ||
export { TabList as default }; | ||
TabList.propTypes = process.env.NODE_ENV !== "production" ? { | ||
var propTypes = process.env.NODE_ENV !== "production" ? { | ||
children: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), | ||
className: PropTypes.oneOfType([PropTypes.string, PropTypes.array, PropTypes.object]) | ||
} : {}; | ||
TabList.tabsRole = 'TabList'; | ||
var TabList = function TabList(props) { | ||
var children = props.children, | ||
className = props.className, | ||
attributes = _objectWithoutPropertiesLoose(props, _excluded); | ||
return /*#__PURE__*/React.createElement("ul", _extends({}, attributes, { | ||
className: cx(className), | ||
role: "tablist" | ||
}), children); | ||
}; | ||
TabList.tabsRole = 'TabList'; | ||
TabList.propTypes = process.env.NODE_ENV !== "production" ? propTypes : {}; | ||
TabList.defaultProps = defaultProps; | ||
export default TabList; |
@@ -7,45 +7,7 @@ var _excluded = ["children", "className", "forceRender", "id", "selected", "selectedClassName", "tabId"]; | ||
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
import PropTypes from 'prop-types'; | ||
import React, { Component } from 'react'; | ||
import React from 'react'; | ||
import cx from 'clsx'; | ||
var DEFAULT_CLASS = 'react-tabs__tab-panel'; | ||
var TabPanel = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(TabPanel, _Component); | ||
function TabPanel() { | ||
return _Component.apply(this, arguments) || this; | ||
} | ||
var _proto = TabPanel.prototype; | ||
_proto.render = function render() { | ||
var _cx; | ||
var _this$props = this.props, | ||
children = _this$props.children, | ||
className = _this$props.className, | ||
forceRender = _this$props.forceRender, | ||
id = _this$props.id, | ||
selected = _this$props.selected, | ||
selectedClassName = _this$props.selectedClassName, | ||
tabId = _this$props.tabId, | ||
attributes = _objectWithoutPropertiesLoose(_this$props, _excluded); | ||
return /*#__PURE__*/React.createElement("div", _extends({}, attributes, { | ||
className: cx(className, (_cx = {}, _cx[selectedClassName] = selected, _cx)), | ||
role: "tabpanel", | ||
id: id, | ||
"aria-labelledby": tabId | ||
}), forceRender || selected ? children : null); | ||
}; | ||
return TabPanel; | ||
}(Component); | ||
TabPanel.defaultProps = { | ||
var defaultProps = { | ||
className: DEFAULT_CLASS, | ||
@@ -55,4 +17,3 @@ forceRender: false, | ||
}; | ||
export { TabPanel as default }; | ||
TabPanel.propTypes = process.env.NODE_ENV !== "production" ? { | ||
var propTypes = process.env.NODE_ENV !== "production" ? { | ||
children: PropTypes.node, | ||
@@ -69,2 +30,26 @@ className: PropTypes.oneOfType([PropTypes.string, PropTypes.array, PropTypes.object]), | ||
} : {}; | ||
TabPanel.tabsRole = 'TabPanel'; | ||
var TabPanel = function TabPanel(props) { | ||
var _cx; | ||
var children = props.children, | ||
className = props.className, | ||
forceRender = props.forceRender, | ||
id = props.id, | ||
selected = props.selected, | ||
selectedClassName = props.selectedClassName, | ||
tabId = props.tabId, | ||
attributes = _objectWithoutPropertiesLoose(props, _excluded); | ||
return /*#__PURE__*/React.createElement("div", _extends({}, attributes, { | ||
className: cx(className, (_cx = {}, _cx[selectedClassName] = selected, _cx)), | ||
role: "tabpanel", | ||
id: id, | ||
"aria-labelledby": tabId | ||
}), forceRender || selected ? children : null); | ||
}; | ||
TabPanel.tabsRole = 'TabPanel'; | ||
TabPanel.propTypes = process.env.NODE_ENV !== "production" ? propTypes : {}; | ||
TabPanel.defaultProps = defaultProps; | ||
export default TabPanel; |
@@ -1,11 +0,5 @@ | ||
var _excluded = ["children", "defaultIndex", "defaultFocus"]; | ||
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } | ||
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } | ||
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
import PropTypes from 'prop-types'; | ||
import React, { Component } from 'react'; | ||
import React, { useEffect, useState } from 'react'; | ||
import { childrenPropType, onSelectPropType, selectedIndexPropType } from '../helpers/propTypes'; | ||
@@ -16,127 +10,113 @@ import UncontrolledTabs from './UncontrolledTabs'; | ||
var MODE_UNCONTROLLED = 1; | ||
var propTypes = process.env.NODE_ENV !== "production" ? { | ||
children: childrenPropType, | ||
direction: PropTypes.oneOf(['rtl', 'ltr']), | ||
className: PropTypes.oneOfType([PropTypes.string, PropTypes.array, PropTypes.object]), | ||
defaultFocus: PropTypes.bool, | ||
defaultIndex: PropTypes.number, | ||
disabledTabClassName: PropTypes.string, | ||
disableUpDownKeys: PropTypes.bool, | ||
domRef: PropTypes.func, | ||
forceRenderTabPanel: PropTypes.bool, | ||
onSelect: onSelectPropType, | ||
selectedIndex: selectedIndexPropType, | ||
selectedTabClassName: PropTypes.string, | ||
selectedTabPanelClassName: PropTypes.string, | ||
environment: PropTypes.object | ||
} : {}; | ||
var defaultProps = { | ||
defaultFocus: false, | ||
forceRenderTabPanel: false, | ||
selectedIndex: null, | ||
defaultIndex: null, | ||
environment: null, | ||
disableUpDownKeys: false | ||
}; | ||
var Tabs = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(Tabs, _Component); | ||
var getModeFromProps = function getModeFromProps(props) { | ||
return props.selectedIndex === null ? MODE_UNCONTROLLED : MODE_CONTROLLED; | ||
}; | ||
function Tabs(props) { | ||
var _this; | ||
var checkForIllegalModeChange = function checkForIllegalModeChange(props, mode) { | ||
if (process.env.NODE_ENV !== 'production' && mode != undefined && mode !== getModeFromProps(props)) { | ||
throw new Error("Switching between controlled mode (by using `selectedIndex`) and uncontrolled mode is not supported in `Tabs`.\nFor more information about controlled and uncontrolled mode of react-tabs see https://github.com/reactjs/react-tabs#controlled-vs-uncontrolled-mode."); | ||
} | ||
}; | ||
/** | ||
* State: | ||
* mode: Initialized only once from props and never changes | ||
* selectedIndex: null if controlled mode, otherwise initialized with prop defaultIndex, changed on selection of tabs, has effect to ensure it never gets out of bound | ||
* focus: Because we never remove focus from the Tabs this state is only used to indicate that we should focus the current tab. | ||
* It is initialized from the prop defaultFocus, and after the first render it is reset back to false. Later it can become true again when using keys to navigate the tabs. | ||
*/ | ||
_this = _Component.call(this, props) || this; | ||
_this.handleSelected = function (index, last, event) { | ||
var onSelect = _this.props.onSelect; | ||
var mode = _this.state.mode; // Call change event handler | ||
var Tabs = function Tabs(props) { | ||
var children = props.children, | ||
defaultFocus = props.defaultFocus, | ||
defaultIndex = props.defaultIndex, | ||
onSelect = props.onSelect; | ||
if (typeof onSelect === 'function') { | ||
// Check if the change event handler cancels the tab change | ||
if (onSelect(index, last, event) === false) return; | ||
} | ||
var _useState = useState(defaultFocus), | ||
focus = _useState[0], | ||
setFocus = _useState[1]; | ||
var state = { | ||
// Set focus if the change was triggered from the keyboard | ||
focus: event.type === 'keydown' | ||
}; | ||
var _useState2 = useState(getModeFromProps(props)), | ||
mode = _useState2[0]; | ||
if (mode === MODE_UNCONTROLLED) { | ||
// Update selected index | ||
state.selectedIndex = index; | ||
} | ||
var _useState3 = useState(mode === MODE_UNCONTROLLED ? defaultIndex || 0 : null), | ||
selectedIndex = _useState3[0], | ||
setSelectedIndex = _useState3[1]; | ||
_this.setState(state); | ||
}; | ||
useEffect(function () { | ||
// Reset focus after initial render, see comment above | ||
setFocus(false); | ||
}, []); | ||
_this.state = Tabs.copyPropsToState(_this.props, {}, props.defaultFocus); | ||
return _this; | ||
if (mode === MODE_UNCONTROLLED) { | ||
// Ensure that we handle removed tabs and don't let selectedIndex get out of bounds | ||
var tabsCount = getTabsCount(children); | ||
useEffect(function () { | ||
if (selectedIndex != null) { | ||
var maxTabIndex = Math.max(0, tabsCount - 1); | ||
setSelectedIndex(Math.min(selectedIndex, maxTabIndex)); | ||
} | ||
}, [tabsCount]); | ||
} | ||
Tabs.getDerivedStateFromProps = function getDerivedStateFromProps(props, state) { | ||
return Tabs.copyPropsToState(props, state); | ||
}; | ||
checkForIllegalModeChange(props, mode); | ||
Tabs.getModeFromProps = function getModeFromProps(props) { | ||
return props.selectedIndex === null ? MODE_UNCONTROLLED : MODE_CONTROLLED; | ||
}; | ||
var handleSelected = function handleSelected(index, last, event) { | ||
// Call change event handler | ||
if (typeof onSelect === 'function') { | ||
// Check if the change event handler cancels the tab change | ||
if (onSelect(index, last, event) === false) return; | ||
} // Always set focus on tabs | ||
// preserve the existing selectedIndex from state. | ||
// If the state has not selectedIndex, default to the defaultIndex or 0 | ||
Tabs.copyPropsToState = function copyPropsToState(props, state, focus) { | ||
if (focus === void 0) { | ||
focus = false; | ||
} | ||
if (process.env.NODE_ENV !== 'production' && state.mode !== undefined && state.mode !== Tabs.getModeFromProps(props)) { | ||
throw new Error("Switching between controlled mode (by using `selectedIndex`) and uncontrolled mode is not supported in `Tabs`.\nFor more information about controlled and uncontrolled mode of react-tabs see https://github.com/reactjs/react-tabs#controlled-vs-uncontrolled-mode."); | ||
} | ||
setFocus(true); | ||
var newState = { | ||
focus: focus, | ||
mode: Tabs.getModeFromProps(props) | ||
}; | ||
if (newState.mode === MODE_UNCONTROLLED) { | ||
var maxTabIndex = Math.max(0, getTabsCount(props.children) - 1); | ||
var selectedIndex = null; | ||
if (state.selectedIndex != null) { | ||
selectedIndex = Math.min(state.selectedIndex, maxTabIndex); | ||
} else { | ||
selectedIndex = props.defaultIndex || 0; | ||
} | ||
newState.selectedIndex = selectedIndex; | ||
if (mode === MODE_UNCONTROLLED) { | ||
// Update selected index | ||
setSelectedIndex(index); | ||
} | ||
return newState; | ||
}; | ||
var _proto = Tabs.prototype; | ||
var subProps = _extends({}, props); | ||
_proto.render = function render() { | ||
var _this$props = this.props, | ||
children = _this$props.children, | ||
defaultIndex = _this$props.defaultIndex, | ||
defaultFocus = _this$props.defaultFocus, | ||
props = _objectWithoutPropertiesLoose(_this$props, _excluded); | ||
subProps.focus = focus; | ||
subProps.onSelect = handleSelected; | ||
var _this$state = this.state, | ||
focus = _this$state.focus, | ||
selectedIndex = _this$state.selectedIndex; | ||
props.focus = focus; | ||
props.onSelect = this.handleSelected; | ||
if (selectedIndex != null) { | ||
subProps.selectedIndex = selectedIndex; | ||
} | ||
if (selectedIndex != null) { | ||
props.selectedIndex = selectedIndex; | ||
} | ||
delete subProps.defaultFocus; | ||
delete subProps.defaultIndex; | ||
return /*#__PURE__*/React.createElement(UncontrolledTabs, subProps, children); | ||
}; | ||
return /*#__PURE__*/React.createElement(UncontrolledTabs, props, children); | ||
}; | ||
return Tabs; | ||
}(Component); | ||
Tabs.defaultProps = { | ||
defaultFocus: false, | ||
forceRenderTabPanel: false, | ||
selectedIndex: null, | ||
defaultIndex: null, | ||
environment: null, | ||
disableUpDownKeys: false | ||
}; | ||
export { Tabs as default }; | ||
Tabs.propTypes = process.env.NODE_ENV !== "production" ? { | ||
children: childrenPropType, | ||
direction: PropTypes.oneOf(['rtl', 'ltr']), | ||
className: PropTypes.oneOfType([PropTypes.string, PropTypes.array, PropTypes.object]), | ||
defaultFocus: PropTypes.bool, | ||
defaultIndex: PropTypes.number, | ||
disabledTabClassName: PropTypes.string, | ||
disableUpDownKeys: PropTypes.bool, | ||
domRef: PropTypes.func, | ||
forceRenderTabPanel: PropTypes.bool, | ||
onSelect: onSelectPropType, | ||
selectedIndex: selectedIndexPropType, | ||
selectedTabClassName: PropTypes.string, | ||
selectedTabPanelClassName: PropTypes.string, | ||
environment: PropTypes.object | ||
} : {}; | ||
Tabs.tabsRole = 'Tabs'; | ||
Tabs.propTypes = process.env.NODE_ENV !== "production" ? propTypes : {}; | ||
Tabs.defaultProps = defaultProps; | ||
Tabs.tabsRole = 'Tabs'; | ||
export default Tabs; |
@@ -7,12 +7,8 @@ var _excluded = ["children", "className", "disabledTabClassName", "domRef", "focus", "forceRenderTabPanel", "onSelect", "selectedIndex", "selectedTabClassName", "selectedTabPanelClassName", "environment", "disableUpDownKeys"]; | ||
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
import PropTypes from 'prop-types'; | ||
import React, { cloneElement, Component } from 'react'; | ||
import React, { cloneElement, useRef } from 'react'; | ||
import cx from 'clsx'; | ||
import uuid from '../helpers/uuid'; | ||
import { childrenPropType } from '../helpers/propTypes'; | ||
import { getPanelsCount as _getPanelsCount, getTabsCount as _getTabsCount } from '../helpers/count'; | ||
import { getTabsCount as getTabsCountHelper } from '../helpers/count'; | ||
import { deepMap } from '../helpers/childrenDeepMap'; | ||
@@ -51,114 +47,43 @@ import { isTabList, isTabPanel, isTab } from '../helpers/elementTypes'; | ||
var UncontrolledTabs = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(UncontrolledTabs, _Component); | ||
var defaultProps = { | ||
className: 'react-tabs', | ||
focus: false | ||
}; | ||
var propTypes = process.env.NODE_ENV !== "production" ? { | ||
children: childrenPropType, | ||
direction: PropTypes.oneOf(['rtl', 'ltr']), | ||
className: PropTypes.oneOfType([PropTypes.string, PropTypes.array, PropTypes.object]), | ||
disabledTabClassName: PropTypes.string, | ||
disableUpDownKeys: PropTypes.bool, | ||
domRef: PropTypes.func, | ||
focus: PropTypes.bool, | ||
forceRenderTabPanel: PropTypes.bool, | ||
onSelect: PropTypes.func.isRequired, | ||
selectedIndex: PropTypes.number.isRequired, | ||
selectedTabClassName: PropTypes.string, | ||
selectedTabPanelClassName: PropTypes.string, | ||
environment: PropTypes.object | ||
} : {}; | ||
function UncontrolledTabs() { | ||
var _this; | ||
var UncontrolledTabs = function UncontrolledTabs(props) { | ||
var tabNodes = useRef([]); | ||
var tabIds = useRef([]); | ||
var panelIds = useRef([]); | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
var _ref = useRef(); | ||
_this = _Component.call.apply(_Component, [this].concat(args)) || this; | ||
_this.tabNodes = []; | ||
_this.handleKeyDown = function (e) { | ||
var _this$props = _this.props, | ||
direction = _this$props.direction, | ||
disableUpDownKeys = _this$props.disableUpDownKeys; | ||
if (_this.isTabFromContainer(e.target)) { | ||
var index = _this.props.selectedIndex; | ||
var preventDefault = false; | ||
var useSelectedIndex = false; | ||
if (e.keyCode === 32 || e.keyCode === 13) { | ||
preventDefault = true; | ||
useSelectedIndex = false; | ||
_this.handleClick(e); | ||
} | ||
if (e.keyCode === 37 || !disableUpDownKeys && e.keyCode === 38) { | ||
// Select next tab to the left, validate if up arrow is not disabled | ||
if (direction === 'rtl') { | ||
index = _this.getNextTab(index); | ||
} else { | ||
index = _this.getPrevTab(index); | ||
} | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 39 || !disableUpDownKeys && e.keyCode === 40) { | ||
// Select next tab to the right, validate if down arrow is not disabled | ||
if (direction === 'rtl') { | ||
index = _this.getPrevTab(index); | ||
} else { | ||
index = _this.getNextTab(index); | ||
} | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 35) { | ||
// Select last tab (End key) | ||
index = _this.getLastTab(); | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 36) { | ||
// Select first tab (Home key) | ||
index = _this.getFirstTab(); | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} // This prevents scrollbars from moving around | ||
if (preventDefault) { | ||
e.preventDefault(); | ||
} // Only use the selected index in the state if we're not using the tabbed index | ||
if (useSelectedIndex) { | ||
_this.setSelected(index, e); | ||
} | ||
} | ||
}; | ||
_this.handleClick = function (e) { | ||
var node = e.target; | ||
do { | ||
if (_this.isTabFromContainer(node)) { | ||
if (isTabDisabled(node)) { | ||
return; | ||
} | ||
var index = [].slice.call(node.parentNode.children).filter(isTabNode).indexOf(node); | ||
_this.setSelected(index, e); | ||
return; | ||
} | ||
} while ((node = node.parentNode) != null); | ||
}; | ||
return _this; | ||
} | ||
var _proto = UncontrolledTabs.prototype; | ||
_proto.setSelected = function setSelected(index, event) { | ||
function setSelected(index, event) { | ||
// Check index boundary | ||
if (index < 0 || index >= this.getTabsCount()) return; | ||
var _this$props2 = this.props, | ||
onSelect = _this$props2.onSelect, | ||
selectedIndex = _this$props2.selectedIndex; // Call change event handler | ||
if (index < 0 || index >= getTabsCount()) return; | ||
var onSelect = props.onSelect, | ||
selectedIndex = props.selectedIndex; // Call change event handler | ||
onSelect(index, selectedIndex, event); | ||
}; | ||
} | ||
_proto.getNextTab = function getNextTab(index) { | ||
var count = this.getTabsCount(); // Look for non-disabled tab from index to the last tab on the right | ||
function getNextTab(index) { | ||
var count = getTabsCount(); // Look for non-disabled tab from index to the last tab on the right | ||
for (var i = index + 1; i < count; i++) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -170,3 +95,3 @@ } | ||
for (var _i = 0; _i < index; _i++) { | ||
if (!isTabDisabled(this.getTab(_i))) { | ||
if (!isTabDisabled(getTab(_i))) { | ||
return _i; | ||
@@ -178,9 +103,9 @@ } | ||
return index; | ||
}; | ||
} | ||
_proto.getPrevTab = function getPrevTab(index) { | ||
function getPrevTab(index) { | ||
var i = index; // Look for non-disabled tab from index to first tab on the left | ||
while (i--) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -191,6 +116,6 @@ } | ||
i = this.getTabsCount(); | ||
i = getTabsCount(); | ||
while (i-- > index) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -202,9 +127,9 @@ } | ||
return index; | ||
}; | ||
} | ||
_proto.getFirstTab = function getFirstTab() { | ||
var count = this.getTabsCount(); // Look for non disabled tab from the first tab | ||
function getFirstTab() { | ||
var count = getTabsCount(); // Look for non disabled tab from the first tab | ||
for (var i = 0; i < count; i++) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -215,9 +140,9 @@ } | ||
return null; | ||
}; | ||
} | ||
_proto.getLastTab = function getLastTab() { | ||
var i = this.getTabsCount(); // Look for non disabled tab from the last tab | ||
function getLastTab() { | ||
var i = getTabsCount(); // Look for non disabled tab from the last tab | ||
while (i--) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -228,34 +153,26 @@ } | ||
return null; | ||
}; | ||
} | ||
_proto.getTabsCount = function getTabsCount() { | ||
var children = this.props.children; | ||
return _getTabsCount(children); | ||
}; | ||
function getTabsCount() { | ||
var children = props.children; | ||
return getTabsCountHelper(children); | ||
} | ||
_proto.getPanelsCount = function getPanelsCount() { | ||
var children = this.props.children; | ||
return _getPanelsCount(children); | ||
}; | ||
function getTab(index) { | ||
return tabNodes.current["tabs-" + index]; | ||
} | ||
_proto.getTab = function getTab(index) { | ||
return this.tabNodes["tabs-" + index]; | ||
}; | ||
_proto.getChildren = function getChildren() { | ||
var _this2 = this; | ||
function getChildren() { | ||
var index = 0; | ||
var _this$props3 = this.props, | ||
children = _this$props3.children, | ||
disabledTabClassName = _this$props3.disabledTabClassName, | ||
focus = _this$props3.focus, | ||
forceRenderTabPanel = _this$props3.forceRenderTabPanel, | ||
selectedIndex = _this$props3.selectedIndex, | ||
selectedTabClassName = _this$props3.selectedTabClassName, | ||
selectedTabPanelClassName = _this$props3.selectedTabPanelClassName, | ||
environment = _this$props3.environment; | ||
this.tabIds = this.tabIds || []; | ||
this.panelIds = this.panelIds || []; | ||
var diff = this.tabIds.length - this.getTabsCount(); // Add ids if new tabs have been added | ||
var children = props.children, | ||
disabledTabClassName = props.disabledTabClassName, | ||
focus = props.focus, | ||
forceRenderTabPanel = props.forceRenderTabPanel, | ||
selectedIndex = props.selectedIndex, | ||
selectedTabClassName = props.selectedTabClassName, | ||
selectedTabPanelClassName = props.selectedTabPanelClassName, | ||
environment = props.environment; | ||
tabIds.current = tabIds.current || []; | ||
panelIds.current = panelIds.current || []; | ||
var diff = tabIds.current.length - getTabsCount(); // Add ids if new tabs have been added | ||
// Don't bother removing ids, just keep them in case they are added again | ||
@@ -265,4 +182,4 @@ // This is more efficient, and keeps the uuid counter under control | ||
while (diff++ < 0) { | ||
this.tabIds.push(uuid()); | ||
this.panelIds.push(uuid()); | ||
tabIds.current.push(uuid()); | ||
panelIds.current.push(uuid()); | ||
} // Map children to dynamically setup refs | ||
@@ -287,3 +204,3 @@ | ||
var env = environment || (typeof window !== 'undefined' ? window : undefined); | ||
return env && env.document.activeElement === _this2.getTab(i); | ||
return env && env.document.activeElement === getTab(i); | ||
}); | ||
@@ -298,6 +215,6 @@ } | ||
tabRef: function tabRef(node) { | ||
_this2.tabNodes[key] = node; | ||
tabNodes.current[key] = node; | ||
}, | ||
id: _this2.tabIds[listIndex], | ||
panelId: _this2.panelIds[listIndex], | ||
id: tabIds.current[listIndex], | ||
panelId: panelIds.current[listIndex], | ||
selected: selected, | ||
@@ -313,11 +230,11 @@ focus: selected && (focus || wasTabFocused) | ||
} else if (isTabPanel(child)) { | ||
var props = { | ||
id: _this2.panelIds[index], | ||
tabId: _this2.tabIds[index], | ||
var _props = { | ||
id: panelIds.current[index], | ||
tabId: tabIds.current[index], | ||
selected: selectedIndex === index | ||
}; | ||
if (forceRenderTabPanel) props.forceRender = forceRenderTabPanel; | ||
if (selectedTabPanelClassName) props.selectedClassName = selectedTabPanelClassName; | ||
if (forceRenderTabPanel) _props.forceRender = forceRenderTabPanel; | ||
if (selectedTabPanelClassName) _props.selectedClassName = selectedTabPanelClassName; | ||
index++; | ||
result = /*#__PURE__*/cloneElement(child, props); | ||
result = /*#__PURE__*/cloneElement(child, _props); | ||
} | ||
@@ -327,4 +244,78 @@ | ||
}); | ||
}; | ||
} | ||
function handleKeyDown(e) { | ||
var direction = props.direction, | ||
disableUpDownKeys = props.disableUpDownKeys; | ||
if (isTabFromContainer(e.target)) { | ||
var index = props.selectedIndex; | ||
var preventDefault = false; | ||
var useSelectedIndex = false; | ||
if (e.keyCode === 32 || e.keyCode === 13) { | ||
preventDefault = true; | ||
useSelectedIndex = false; | ||
handleClick(e); | ||
} | ||
if (e.keyCode === 37 || !disableUpDownKeys && e.keyCode === 38) { | ||
// Select next tab to the left, validate if up arrow is not disabled | ||
if (direction === 'rtl') { | ||
index = getNextTab(index); | ||
} else { | ||
index = getPrevTab(index); | ||
} | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 39 || !disableUpDownKeys && e.keyCode === 40) { | ||
// Select next tab to the right, validate if down arrow is not disabled | ||
if (direction === 'rtl') { | ||
index = getPrevTab(index); | ||
} else { | ||
index = getNextTab(index); | ||
} | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 35) { | ||
// Select last tab (End key) | ||
index = getLastTab(); | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 36) { | ||
// Select first tab (Home key) | ||
index = getFirstTab(); | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} // This prevents scrollbars from moving around | ||
if (preventDefault) { | ||
e.preventDefault(); | ||
} // Only use the selected index in the state if we're not using the tabbed index | ||
if (useSelectedIndex) { | ||
setSelected(index, e); | ||
} | ||
} | ||
} | ||
function handleClick(e) { | ||
var node = e.target; | ||
do { | ||
if (isTabFromContainer(node)) { | ||
if (isTabDisabled(node)) { | ||
return; | ||
} | ||
var index = [].slice.call(node.parentNode.children).filter(isTabNode).indexOf(node); | ||
setSelected(index, e); | ||
return; | ||
} | ||
} while ((node = node.parentNode) != null); | ||
} | ||
/** | ||
@@ -335,3 +326,5 @@ * Determine if a node from event.target is a Tab element for the current Tabs container. | ||
*/ | ||
_proto.isTabFromContainer = function isTabFromContainer(node) { | ||
function isTabFromContainer(node) { | ||
// return immediately if the clicked element is not a Tab. | ||
@@ -346,3 +339,3 @@ if (!isTabNode(node)) { | ||
do { | ||
if (nodeAncestor === this.node) return true; | ||
if (nodeAncestor === _ref.current) return true; | ||
if (nodeAncestor.getAttribute('data-rttabs')) break; | ||
@@ -353,57 +346,32 @@ nodeAncestor = nodeAncestor.parentElement; | ||
return false; | ||
}; | ||
} | ||
_proto.render = function render() { | ||
var _this3 = this; | ||
var children = props.children, | ||
className = props.className, | ||
disabledTabClassName = props.disabledTabClassName, | ||
domRef = props.domRef, | ||
focus = props.focus, | ||
forceRenderTabPanel = props.forceRenderTabPanel, | ||
onSelect = props.onSelect, | ||
selectedIndex = props.selectedIndex, | ||
selectedTabClassName = props.selectedTabClassName, | ||
selectedTabPanelClassName = props.selectedTabPanelClassName, | ||
environment = props.environment, | ||
disableUpDownKeys = props.disableUpDownKeys, | ||
attributes = _objectWithoutPropertiesLoose(props, _excluded); | ||
// Delete all known props, so they don't get added to DOM | ||
var _this$props4 = this.props, | ||
children = _this$props4.children, | ||
className = _this$props4.className, | ||
disabledTabClassName = _this$props4.disabledTabClassName, | ||
domRef = _this$props4.domRef, | ||
focus = _this$props4.focus, | ||
forceRenderTabPanel = _this$props4.forceRenderTabPanel, | ||
onSelect = _this$props4.onSelect, | ||
selectedIndex = _this$props4.selectedIndex, | ||
selectedTabClassName = _this$props4.selectedTabClassName, | ||
selectedTabPanelClassName = _this$props4.selectedTabPanelClassName, | ||
environment = _this$props4.environment, | ||
disableUpDownKeys = _this$props4.disableUpDownKeys, | ||
attributes = _objectWithoutPropertiesLoose(_this$props4, _excluded); | ||
return /*#__PURE__*/React.createElement("div", _extends({}, attributes, { | ||
className: cx(className), | ||
onClick: handleClick, | ||
onKeyDown: handleKeyDown, | ||
ref: function ref(node) { | ||
_ref.current = node; | ||
if (domRef) domRef(node); | ||
}, | ||
"data-rttabs": true | ||
}), getChildren()); | ||
}; | ||
return /*#__PURE__*/React.createElement("div", _extends({}, attributes, { | ||
className: cx(className), | ||
onClick: this.handleClick, | ||
onKeyDown: this.handleKeyDown, | ||
ref: function ref(node) { | ||
_this3.node = node; | ||
if (domRef) domRef(node); | ||
}, | ||
"data-rttabs": true | ||
}), this.getChildren()); | ||
}; | ||
return UncontrolledTabs; | ||
}(Component); | ||
UncontrolledTabs.defaultProps = { | ||
className: 'react-tabs', | ||
focus: false | ||
}; | ||
export { UncontrolledTabs as default }; | ||
UncontrolledTabs.propTypes = process.env.NODE_ENV !== "production" ? { | ||
children: childrenPropType, | ||
direction: PropTypes.oneOf(['rtl', 'ltr']), | ||
className: PropTypes.oneOfType([PropTypes.string, PropTypes.array, PropTypes.object]), | ||
disabledTabClassName: PropTypes.string, | ||
disableUpDownKeys: PropTypes.bool, | ||
domRef: PropTypes.func, | ||
focus: PropTypes.bool, | ||
forceRenderTabPanel: PropTypes.bool, | ||
onSelect: PropTypes.func.isRequired, | ||
selectedIndex: PropTypes.number.isRequired, | ||
selectedTabClassName: PropTypes.string, | ||
selectedTabPanelClassName: PropTypes.string, | ||
environment: PropTypes.object | ||
} : {}; | ||
UncontrolledTabs.defaultProps = defaultProps; | ||
UncontrolledTabs.propTypes = process.env.NODE_ENV !== "production" ? propTypes : {}; | ||
export default UncontrolledTabs; |
import { deepForEach } from './childrenDeepMap'; | ||
import { isTab, isTabPanel } from './elementTypes'; | ||
import { isTab } from './elementTypes'; | ||
export function getTabsCount(children) { | ||
@@ -9,9 +9,2 @@ var tabCount = 0; | ||
return tabCount; | ||
} | ||
export function getPanelsCount(children) { | ||
var panelCount = 0; | ||
deepForEach(children, function (child) { | ||
if (isTabPanel(child)) panelCount++; | ||
}); | ||
return panelCount; | ||
} |
@@ -24,74 +24,4 @@ "use strict"; | ||
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
var DEFAULT_CLASS = 'react-tabs__tab'; | ||
var Tab = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(Tab, _Component); | ||
function Tab() { | ||
return _Component.apply(this, arguments) || this; | ||
} | ||
var _proto = Tab.prototype; | ||
_proto.componentDidMount = function componentDidMount() { | ||
this.checkFocus(); | ||
}; | ||
_proto.componentDidUpdate = function componentDidUpdate() { | ||
this.checkFocus(); | ||
}; | ||
_proto.checkFocus = function checkFocus() { | ||
var _this$props = this.props, | ||
selected = _this$props.selected, | ||
focus = _this$props.focus; | ||
if (selected && focus) { | ||
this.node.focus(); | ||
} | ||
}; | ||
_proto.render = function render() { | ||
var _cx, | ||
_this = this; | ||
var _this$props2 = this.props, | ||
children = _this$props2.children, | ||
className = _this$props2.className, | ||
disabled = _this$props2.disabled, | ||
disabledClassName = _this$props2.disabledClassName, | ||
focus = _this$props2.focus, | ||
id = _this$props2.id, | ||
panelId = _this$props2.panelId, | ||
selected = _this$props2.selected, | ||
selectedClassName = _this$props2.selectedClassName, | ||
tabIndex = _this$props2.tabIndex, | ||
tabRef = _this$props2.tabRef, | ||
attributes = _objectWithoutPropertiesLoose(_this$props2, _excluded); | ||
return /*#__PURE__*/_react["default"].createElement("li", _extends({}, attributes, { | ||
className: (0, _clsx["default"])(className, (_cx = {}, _cx[selectedClassName] = selected, _cx[disabledClassName] = disabled, _cx)), | ||
ref: function ref(node) { | ||
_this.node = node; | ||
if (tabRef) tabRef(node); | ||
}, | ||
role: "tab", | ||
id: id, | ||
"aria-selected": selected ? 'true' : 'false', | ||
"aria-disabled": disabled ? 'true' : 'false', | ||
"aria-controls": panelId, | ||
tabIndex: tabIndex || (selected ? '0' : null), | ||
"data-rttab": true | ||
}), children); | ||
}; | ||
return Tab; | ||
}(_react.Component); | ||
exports["default"] = Tab; | ||
Tab.defaultProps = { | ||
var DEFAULT_PROPS = { | ||
className: DEFAULT_CLASS, | ||
@@ -105,3 +35,3 @@ disabledClassName: DEFAULT_CLASS + "--disabled", | ||
}; | ||
Tab.propTypes = process.env.NODE_ENV !== "production" ? { | ||
var propTypes = process.env.NODE_ENV !== "production" ? { | ||
children: _propTypes["default"].oneOfType([_propTypes["default"].array, _propTypes["default"].object, _propTypes["default"].string]), | ||
@@ -121,5 +51,56 @@ className: _propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].array, _propTypes["default"].object]), | ||
selectedClassName: _propTypes["default"].string, | ||
tabRef: _propTypes["default"].func // private | ||
tabRef: _propTypes["default"].func | ||
} : {}; | ||
} : {}; | ||
Tab.tabsRole = 'Tab'; | ||
var Tab = function Tab(props) { | ||
var _cx; | ||
var nodeRef = (0, _react.useRef)(); | ||
var checkFocus = function checkFocus() { | ||
var selected = props.selected, | ||
focus = props.focus; | ||
if (selected && focus) { | ||
nodeRef.current.focus(); | ||
} | ||
}; | ||
(0, _react.useEffect)(function () { | ||
checkFocus(); | ||
}); | ||
var children = props.children, | ||
className = props.className, | ||
disabled = props.disabled, | ||
disabledClassName = props.disabledClassName, | ||
focus = props.focus, | ||
id = props.id, | ||
panelId = props.panelId, | ||
selected = props.selected, | ||
selectedClassName = props.selectedClassName, | ||
tabIndex = props.tabIndex, | ||
tabRef = props.tabRef, | ||
attributes = _objectWithoutPropertiesLoose(props, _excluded); | ||
return /*#__PURE__*/_react["default"].createElement("li", _extends({}, attributes, { | ||
className: (0, _clsx["default"])(className, (_cx = {}, _cx[selectedClassName] = selected, _cx[disabledClassName] = disabled, _cx)), | ||
ref: function ref(node) { | ||
nodeRef.current = node; | ||
if (tabRef) tabRef(node); | ||
}, | ||
role: "tab", | ||
id: id, | ||
"aria-selected": selected ? 'true' : 'false', | ||
"aria-disabled": disabled ? 'true' : 'false', | ||
"aria-controls": panelId, | ||
tabIndex: tabIndex || (selected ? '0' : null), | ||
"data-rttab": true | ||
}), children); | ||
}; | ||
Tab.propTypes = process.env.NODE_ENV !== "production" ? propTypes : {}; | ||
Tab.tabsRole = 'Tab'; | ||
Tab.defaultProps = DEFAULT_PROPS; | ||
var _default = Tab; | ||
exports["default"] = _default; |
@@ -8,3 +8,3 @@ "use strict"; | ||
var _react = _interopRequireWildcard(require("react")); | ||
var _react = _interopRequireDefault(require("react")); | ||
@@ -15,6 +15,2 @@ var _clsx = _interopRequireDefault(require("clsx")); | ||
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } | ||
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } | ||
@@ -26,38 +22,25 @@ | ||
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
var TabList = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(TabList, _Component); | ||
function TabList() { | ||
return _Component.apply(this, arguments) || this; | ||
} | ||
var _proto = TabList.prototype; | ||
_proto.render = function render() { | ||
var _this$props = this.props, | ||
children = _this$props.children, | ||
className = _this$props.className, | ||
attributes = _objectWithoutPropertiesLoose(_this$props, _excluded); | ||
return /*#__PURE__*/_react["default"].createElement("ul", _extends({}, attributes, { | ||
className: (0, _clsx["default"])(className), | ||
role: "tablist" | ||
}), children); | ||
}; | ||
return TabList; | ||
}(_react.Component); | ||
exports["default"] = TabList; | ||
TabList.defaultProps = { | ||
var defaultProps = { | ||
className: 'react-tabs__tab-list' | ||
}; | ||
TabList.propTypes = process.env.NODE_ENV !== "production" ? { | ||
var propTypes = process.env.NODE_ENV !== "production" ? { | ||
children: _propTypes["default"].oneOfType([_propTypes["default"].object, _propTypes["default"].array]), | ||
className: _propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].array, _propTypes["default"].object]) | ||
} : {}; | ||
TabList.tabsRole = 'TabList'; | ||
var TabList = function TabList(props) { | ||
var children = props.children, | ||
className = props.className, | ||
attributes = _objectWithoutPropertiesLoose(props, _excluded); | ||
return /*#__PURE__*/_react["default"].createElement("ul", _extends({}, attributes, { | ||
className: (0, _clsx["default"])(className), | ||
role: "tablist" | ||
}), children); | ||
}; | ||
TabList.tabsRole = 'TabList'; | ||
TabList.propTypes = process.env.NODE_ENV !== "production" ? propTypes : {}; | ||
TabList.defaultProps = defaultProps; | ||
var _default = TabList; | ||
exports["default"] = _default; |
@@ -8,3 +8,3 @@ "use strict"; | ||
var _react = _interopRequireWildcard(require("react")); | ||
var _react = _interopRequireDefault(require("react")); | ||
@@ -15,6 +15,2 @@ var _clsx = _interopRequireDefault(require("clsx")); | ||
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } | ||
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } | ||
@@ -26,43 +22,4 @@ | ||
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
var DEFAULT_CLASS = 'react-tabs__tab-panel'; | ||
var TabPanel = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(TabPanel, _Component); | ||
function TabPanel() { | ||
return _Component.apply(this, arguments) || this; | ||
} | ||
var _proto = TabPanel.prototype; | ||
_proto.render = function render() { | ||
var _cx; | ||
var _this$props = this.props, | ||
children = _this$props.children, | ||
className = _this$props.className, | ||
forceRender = _this$props.forceRender, | ||
id = _this$props.id, | ||
selected = _this$props.selected, | ||
selectedClassName = _this$props.selectedClassName, | ||
tabId = _this$props.tabId, | ||
attributes = _objectWithoutPropertiesLoose(_this$props, _excluded); | ||
return /*#__PURE__*/_react["default"].createElement("div", _extends({}, attributes, { | ||
className: (0, _clsx["default"])(className, (_cx = {}, _cx[selectedClassName] = selected, _cx)), | ||
role: "tabpanel", | ||
id: id, | ||
"aria-labelledby": tabId | ||
}), forceRender || selected ? children : null); | ||
}; | ||
return TabPanel; | ||
}(_react.Component); | ||
exports["default"] = TabPanel; | ||
TabPanel.defaultProps = { | ||
var defaultProps = { | ||
className: DEFAULT_CLASS, | ||
@@ -72,3 +29,3 @@ forceRender: false, | ||
}; | ||
TabPanel.propTypes = process.env.NODE_ENV !== "production" ? { | ||
var propTypes = process.env.NODE_ENV !== "production" ? { | ||
children: _propTypes["default"].node, | ||
@@ -85,2 +42,27 @@ className: _propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].array, _propTypes["default"].object]), | ||
} : {}; | ||
TabPanel.tabsRole = 'TabPanel'; | ||
var TabPanel = function TabPanel(props) { | ||
var _cx; | ||
var children = props.children, | ||
className = props.className, | ||
forceRender = props.forceRender, | ||
id = props.id, | ||
selected = props.selected, | ||
selectedClassName = props.selectedClassName, | ||
tabId = props.tabId, | ||
attributes = _objectWithoutPropertiesLoose(props, _excluded); | ||
return /*#__PURE__*/_react["default"].createElement("div", _extends({}, attributes, { | ||
className: (0, _clsx["default"])(className, (_cx = {}, _cx[selectedClassName] = selected, _cx)), | ||
role: "tabpanel", | ||
id: id, | ||
"aria-labelledby": tabId | ||
}), forceRender || selected ? children : null); | ||
}; | ||
TabPanel.tabsRole = 'TabPanel'; | ||
TabPanel.propTypes = process.env.NODE_ENV !== "production" ? propTypes : {}; | ||
TabPanel.defaultProps = defaultProps; | ||
var _default = TabPanel; | ||
exports["default"] = _default; |
@@ -16,4 +16,2 @@ "use strict"; | ||
var _excluded = ["children", "defaultIndex", "defaultFocus"]; | ||
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } | ||
@@ -25,135 +23,118 @@ | ||
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } | ||
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } | ||
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
var MODE_CONTROLLED = 0; | ||
var MODE_UNCONTROLLED = 1; | ||
var propTypes = process.env.NODE_ENV !== "production" ? { | ||
children: _propTypes2.childrenPropType, | ||
direction: _propTypes["default"].oneOf(['rtl', 'ltr']), | ||
className: _propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].array, _propTypes["default"].object]), | ||
defaultFocus: _propTypes["default"].bool, | ||
defaultIndex: _propTypes["default"].number, | ||
disabledTabClassName: _propTypes["default"].string, | ||
disableUpDownKeys: _propTypes["default"].bool, | ||
domRef: _propTypes["default"].func, | ||
forceRenderTabPanel: _propTypes["default"].bool, | ||
onSelect: _propTypes2.onSelectPropType, | ||
selectedIndex: _propTypes2.selectedIndexPropType, | ||
selectedTabClassName: _propTypes["default"].string, | ||
selectedTabPanelClassName: _propTypes["default"].string, | ||
environment: _propTypes["default"].object | ||
} : {}; | ||
var defaultProps = { | ||
defaultFocus: false, | ||
forceRenderTabPanel: false, | ||
selectedIndex: null, | ||
defaultIndex: null, | ||
environment: null, | ||
disableUpDownKeys: false | ||
}; | ||
var Tabs = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(Tabs, _Component); | ||
var getModeFromProps = function getModeFromProps(props) { | ||
return props.selectedIndex === null ? MODE_UNCONTROLLED : MODE_CONTROLLED; | ||
}; | ||
function Tabs(props) { | ||
var _this; | ||
var checkForIllegalModeChange = function checkForIllegalModeChange(props, mode) { | ||
if (process.env.NODE_ENV !== 'production' && mode != undefined && mode !== getModeFromProps(props)) { | ||
throw new Error("Switching between controlled mode (by using `selectedIndex`) and uncontrolled mode is not supported in `Tabs`.\nFor more information about controlled and uncontrolled mode of react-tabs see https://github.com/reactjs/react-tabs#controlled-vs-uncontrolled-mode."); | ||
} | ||
}; | ||
/** | ||
* State: | ||
* mode: Initialized only once from props and never changes | ||
* selectedIndex: null if controlled mode, otherwise initialized with prop defaultIndex, changed on selection of tabs, has effect to ensure it never gets out of bound | ||
* focus: Because we never remove focus from the Tabs this state is only used to indicate that we should focus the current tab. | ||
* It is initialized from the prop defaultFocus, and after the first render it is reset back to false. Later it can become true again when using keys to navigate the tabs. | ||
*/ | ||
_this = _Component.call(this, props) || this; | ||
_this.handleSelected = function (index, last, event) { | ||
var onSelect = _this.props.onSelect; | ||
var mode = _this.state.mode; // Call change event handler | ||
var Tabs = function Tabs(props) { | ||
var children = props.children, | ||
defaultFocus = props.defaultFocus, | ||
defaultIndex = props.defaultIndex, | ||
onSelect = props.onSelect; | ||
if (typeof onSelect === 'function') { | ||
// Check if the change event handler cancels the tab change | ||
if (onSelect(index, last, event) === false) return; | ||
} | ||
var _useState = (0, _react.useState)(defaultFocus), | ||
focus = _useState[0], | ||
setFocus = _useState[1]; | ||
var state = { | ||
// Set focus if the change was triggered from the keyboard | ||
focus: event.type === 'keydown' | ||
}; | ||
var _useState2 = (0, _react.useState)(getModeFromProps(props)), | ||
mode = _useState2[0]; | ||
if (mode === MODE_UNCONTROLLED) { | ||
// Update selected index | ||
state.selectedIndex = index; | ||
} | ||
var _useState3 = (0, _react.useState)(mode === MODE_UNCONTROLLED ? defaultIndex || 0 : null), | ||
selectedIndex = _useState3[0], | ||
setSelectedIndex = _useState3[1]; | ||
_this.setState(state); | ||
}; | ||
(0, _react.useEffect)(function () { | ||
// Reset focus after initial render, see comment above | ||
setFocus(false); | ||
}, []); | ||
_this.state = Tabs.copyPropsToState(_this.props, {}, props.defaultFocus); | ||
return _this; | ||
if (mode === MODE_UNCONTROLLED) { | ||
// Ensure that we handle removed tabs and don't let selectedIndex get out of bounds | ||
var tabsCount = (0, _count.getTabsCount)(children); | ||
(0, _react.useEffect)(function () { | ||
if (selectedIndex != null) { | ||
var maxTabIndex = Math.max(0, tabsCount - 1); | ||
setSelectedIndex(Math.min(selectedIndex, maxTabIndex)); | ||
} | ||
}, [tabsCount]); | ||
} | ||
Tabs.getDerivedStateFromProps = function getDerivedStateFromProps(props, state) { | ||
return Tabs.copyPropsToState(props, state); | ||
}; | ||
checkForIllegalModeChange(props, mode); | ||
Tabs.getModeFromProps = function getModeFromProps(props) { | ||
return props.selectedIndex === null ? MODE_UNCONTROLLED : MODE_CONTROLLED; | ||
}; | ||
var handleSelected = function handleSelected(index, last, event) { | ||
// Call change event handler | ||
if (typeof onSelect === 'function') { | ||
// Check if the change event handler cancels the tab change | ||
if (onSelect(index, last, event) === false) return; | ||
} // Always set focus on tabs | ||
// preserve the existing selectedIndex from state. | ||
// If the state has not selectedIndex, default to the defaultIndex or 0 | ||
Tabs.copyPropsToState = function copyPropsToState(props, state, focus) { | ||
if (focus === void 0) { | ||
focus = false; | ||
} | ||
if (process.env.NODE_ENV !== 'production' && state.mode !== undefined && state.mode !== Tabs.getModeFromProps(props)) { | ||
throw new Error("Switching between controlled mode (by using `selectedIndex`) and uncontrolled mode is not supported in `Tabs`.\nFor more information about controlled and uncontrolled mode of react-tabs see https://github.com/reactjs/react-tabs#controlled-vs-uncontrolled-mode."); | ||
} | ||
setFocus(true); | ||
var newState = { | ||
focus: focus, | ||
mode: Tabs.getModeFromProps(props) | ||
}; | ||
if (newState.mode === MODE_UNCONTROLLED) { | ||
var maxTabIndex = Math.max(0, (0, _count.getTabsCount)(props.children) - 1); | ||
var selectedIndex = null; | ||
if (state.selectedIndex != null) { | ||
selectedIndex = Math.min(state.selectedIndex, maxTabIndex); | ||
} else { | ||
selectedIndex = props.defaultIndex || 0; | ||
} | ||
newState.selectedIndex = selectedIndex; | ||
if (mode === MODE_UNCONTROLLED) { | ||
// Update selected index | ||
setSelectedIndex(index); | ||
} | ||
return newState; | ||
}; | ||
var _proto = Tabs.prototype; | ||
var subProps = _extends({}, props); | ||
_proto.render = function render() { | ||
var _this$props = this.props, | ||
children = _this$props.children, | ||
defaultIndex = _this$props.defaultIndex, | ||
defaultFocus = _this$props.defaultFocus, | ||
props = _objectWithoutPropertiesLoose(_this$props, _excluded); | ||
subProps.focus = focus; | ||
subProps.onSelect = handleSelected; | ||
var _this$state = this.state, | ||
focus = _this$state.focus, | ||
selectedIndex = _this$state.selectedIndex; | ||
props.focus = focus; | ||
props.onSelect = this.handleSelected; | ||
if (selectedIndex != null) { | ||
subProps.selectedIndex = selectedIndex; | ||
} | ||
if (selectedIndex != null) { | ||
props.selectedIndex = selectedIndex; | ||
} | ||
delete subProps.defaultFocus; | ||
delete subProps.defaultIndex; | ||
return /*#__PURE__*/_react["default"].createElement(_UncontrolledTabs["default"], subProps, children); | ||
}; | ||
return /*#__PURE__*/_react["default"].createElement(_UncontrolledTabs["default"], props, children); | ||
}; | ||
return Tabs; | ||
}(_react.Component); | ||
exports["default"] = Tabs; | ||
Tabs.defaultProps = { | ||
defaultFocus: false, | ||
forceRenderTabPanel: false, | ||
selectedIndex: null, | ||
defaultIndex: null, | ||
environment: null, | ||
disableUpDownKeys: false | ||
}; | ||
Tabs.propTypes = process.env.NODE_ENV !== "production" ? { | ||
children: _propTypes2.childrenPropType, | ||
direction: _propTypes["default"].oneOf(['rtl', 'ltr']), | ||
className: _propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].array, _propTypes["default"].object]), | ||
defaultFocus: _propTypes["default"].bool, | ||
defaultIndex: _propTypes["default"].number, | ||
disabledTabClassName: _propTypes["default"].string, | ||
disableUpDownKeys: _propTypes["default"].bool, | ||
domRef: _propTypes["default"].func, | ||
forceRenderTabPanel: _propTypes["default"].bool, | ||
onSelect: _propTypes2.onSelectPropType, | ||
selectedIndex: _propTypes2.selectedIndexPropType, | ||
selectedTabClassName: _propTypes["default"].string, | ||
selectedTabPanelClassName: _propTypes["default"].string, | ||
environment: _propTypes["default"].object | ||
} : {}; | ||
Tabs.tabsRole = 'Tabs'; | ||
Tabs.propTypes = process.env.NODE_ENV !== "production" ? propTypes : {}; | ||
Tabs.defaultProps = defaultProps; | ||
Tabs.tabsRole = 'Tabs'; | ||
var _default = Tabs; | ||
exports["default"] = _default; |
@@ -34,6 +34,2 @@ "use strict"; | ||
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
function isNode(node) { | ||
@@ -69,114 +65,43 @@ return node && 'getAttribute' in node; | ||
var UncontrolledTabs = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(UncontrolledTabs, _Component); | ||
var defaultProps = { | ||
className: 'react-tabs', | ||
focus: false | ||
}; | ||
var propTypes = process.env.NODE_ENV !== "production" ? { | ||
children: _propTypes2.childrenPropType, | ||
direction: _propTypes["default"].oneOf(['rtl', 'ltr']), | ||
className: _propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].array, _propTypes["default"].object]), | ||
disabledTabClassName: _propTypes["default"].string, | ||
disableUpDownKeys: _propTypes["default"].bool, | ||
domRef: _propTypes["default"].func, | ||
focus: _propTypes["default"].bool, | ||
forceRenderTabPanel: _propTypes["default"].bool, | ||
onSelect: _propTypes["default"].func.isRequired, | ||
selectedIndex: _propTypes["default"].number.isRequired, | ||
selectedTabClassName: _propTypes["default"].string, | ||
selectedTabPanelClassName: _propTypes["default"].string, | ||
environment: _propTypes["default"].object | ||
} : {}; | ||
function UncontrolledTabs() { | ||
var _this; | ||
var UncontrolledTabs = function UncontrolledTabs(props) { | ||
var tabNodes = (0, _react.useRef)([]); | ||
var tabIds = (0, _react.useRef)([]); | ||
var panelIds = (0, _react.useRef)([]); | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
var _ref = (0, _react.useRef)(); | ||
_this = _Component.call.apply(_Component, [this].concat(args)) || this; | ||
_this.tabNodes = []; | ||
_this.handleKeyDown = function (e) { | ||
var _this$props = _this.props, | ||
direction = _this$props.direction, | ||
disableUpDownKeys = _this$props.disableUpDownKeys; | ||
if (_this.isTabFromContainer(e.target)) { | ||
var index = _this.props.selectedIndex; | ||
var preventDefault = false; | ||
var useSelectedIndex = false; | ||
if (e.keyCode === 32 || e.keyCode === 13) { | ||
preventDefault = true; | ||
useSelectedIndex = false; | ||
_this.handleClick(e); | ||
} | ||
if (e.keyCode === 37 || !disableUpDownKeys && e.keyCode === 38) { | ||
// Select next tab to the left, validate if up arrow is not disabled | ||
if (direction === 'rtl') { | ||
index = _this.getNextTab(index); | ||
} else { | ||
index = _this.getPrevTab(index); | ||
} | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 39 || !disableUpDownKeys && e.keyCode === 40) { | ||
// Select next tab to the right, validate if down arrow is not disabled | ||
if (direction === 'rtl') { | ||
index = _this.getPrevTab(index); | ||
} else { | ||
index = _this.getNextTab(index); | ||
} | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 35) { | ||
// Select last tab (End key) | ||
index = _this.getLastTab(); | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 36) { | ||
// Select first tab (Home key) | ||
index = _this.getFirstTab(); | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} // This prevents scrollbars from moving around | ||
if (preventDefault) { | ||
e.preventDefault(); | ||
} // Only use the selected index in the state if we're not using the tabbed index | ||
if (useSelectedIndex) { | ||
_this.setSelected(index, e); | ||
} | ||
} | ||
}; | ||
_this.handleClick = function (e) { | ||
var node = e.target; | ||
do { | ||
if (_this.isTabFromContainer(node)) { | ||
if (isTabDisabled(node)) { | ||
return; | ||
} | ||
var index = [].slice.call(node.parentNode.children).filter(isTabNode).indexOf(node); | ||
_this.setSelected(index, e); | ||
return; | ||
} | ||
} while ((node = node.parentNode) != null); | ||
}; | ||
return _this; | ||
} | ||
var _proto = UncontrolledTabs.prototype; | ||
_proto.setSelected = function setSelected(index, event) { | ||
function setSelected(index, event) { | ||
// Check index boundary | ||
if (index < 0 || index >= this.getTabsCount()) return; | ||
var _this$props2 = this.props, | ||
onSelect = _this$props2.onSelect, | ||
selectedIndex = _this$props2.selectedIndex; // Call change event handler | ||
if (index < 0 || index >= getTabsCount()) return; | ||
var onSelect = props.onSelect, | ||
selectedIndex = props.selectedIndex; // Call change event handler | ||
onSelect(index, selectedIndex, event); | ||
}; | ||
} | ||
_proto.getNextTab = function getNextTab(index) { | ||
var count = this.getTabsCount(); // Look for non-disabled tab from index to the last tab on the right | ||
function getNextTab(index) { | ||
var count = getTabsCount(); // Look for non-disabled tab from index to the last tab on the right | ||
for (var i = index + 1; i < count; i++) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -188,3 +113,3 @@ } | ||
for (var _i = 0; _i < index; _i++) { | ||
if (!isTabDisabled(this.getTab(_i))) { | ||
if (!isTabDisabled(getTab(_i))) { | ||
return _i; | ||
@@ -196,9 +121,9 @@ } | ||
return index; | ||
}; | ||
} | ||
_proto.getPrevTab = function getPrevTab(index) { | ||
function getPrevTab(index) { | ||
var i = index; // Look for non-disabled tab from index to first tab on the left | ||
while (i--) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -209,6 +134,6 @@ } | ||
i = this.getTabsCount(); | ||
i = getTabsCount(); | ||
while (i-- > index) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -220,9 +145,9 @@ } | ||
return index; | ||
}; | ||
} | ||
_proto.getFirstTab = function getFirstTab() { | ||
var count = this.getTabsCount(); // Look for non disabled tab from the first tab | ||
function getFirstTab() { | ||
var count = getTabsCount(); // Look for non disabled tab from the first tab | ||
for (var i = 0; i < count; i++) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -233,9 +158,9 @@ } | ||
return null; | ||
}; | ||
} | ||
_proto.getLastTab = function getLastTab() { | ||
var i = this.getTabsCount(); // Look for non disabled tab from the last tab | ||
function getLastTab() { | ||
var i = getTabsCount(); // Look for non disabled tab from the last tab | ||
while (i--) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -246,34 +171,26 @@ } | ||
return null; | ||
}; | ||
} | ||
_proto.getTabsCount = function getTabsCount() { | ||
var children = this.props.children; | ||
function getTabsCount() { | ||
var children = props.children; | ||
return (0, _count.getTabsCount)(children); | ||
}; | ||
} | ||
_proto.getPanelsCount = function getPanelsCount() { | ||
var children = this.props.children; | ||
return (0, _count.getPanelsCount)(children); | ||
}; | ||
function getTab(index) { | ||
return tabNodes.current["tabs-" + index]; | ||
} | ||
_proto.getTab = function getTab(index) { | ||
return this.tabNodes["tabs-" + index]; | ||
}; | ||
_proto.getChildren = function getChildren() { | ||
var _this2 = this; | ||
function getChildren() { | ||
var index = 0; | ||
var _this$props3 = this.props, | ||
children = _this$props3.children, | ||
disabledTabClassName = _this$props3.disabledTabClassName, | ||
focus = _this$props3.focus, | ||
forceRenderTabPanel = _this$props3.forceRenderTabPanel, | ||
selectedIndex = _this$props3.selectedIndex, | ||
selectedTabClassName = _this$props3.selectedTabClassName, | ||
selectedTabPanelClassName = _this$props3.selectedTabPanelClassName, | ||
environment = _this$props3.environment; | ||
this.tabIds = this.tabIds || []; | ||
this.panelIds = this.panelIds || []; | ||
var diff = this.tabIds.length - this.getTabsCount(); // Add ids if new tabs have been added | ||
var children = props.children, | ||
disabledTabClassName = props.disabledTabClassName, | ||
focus = props.focus, | ||
forceRenderTabPanel = props.forceRenderTabPanel, | ||
selectedIndex = props.selectedIndex, | ||
selectedTabClassName = props.selectedTabClassName, | ||
selectedTabPanelClassName = props.selectedTabPanelClassName, | ||
environment = props.environment; | ||
tabIds.current = tabIds.current || []; | ||
panelIds.current = panelIds.current || []; | ||
var diff = tabIds.current.length - getTabsCount(); // Add ids if new tabs have been added | ||
// Don't bother removing ids, just keep them in case they are added again | ||
@@ -283,4 +200,4 @@ // This is more efficient, and keeps the uuid counter under control | ||
while (diff++ < 0) { | ||
this.tabIds.push((0, _uuid["default"])()); | ||
this.panelIds.push((0, _uuid["default"])()); | ||
tabIds.current.push((0, _uuid["default"])()); | ||
panelIds.current.push((0, _uuid["default"])()); | ||
} // Map children to dynamically setup refs | ||
@@ -305,3 +222,3 @@ | ||
var env = environment || (typeof window !== 'undefined' ? window : undefined); | ||
return env && env.document.activeElement === _this2.getTab(i); | ||
return env && env.document.activeElement === getTab(i); | ||
}); | ||
@@ -316,6 +233,6 @@ } | ||
tabRef: function tabRef(node) { | ||
_this2.tabNodes[key] = node; | ||
tabNodes.current[key] = node; | ||
}, | ||
id: _this2.tabIds[listIndex], | ||
panelId: _this2.panelIds[listIndex], | ||
id: tabIds.current[listIndex], | ||
panelId: panelIds.current[listIndex], | ||
selected: selected, | ||
@@ -331,11 +248,11 @@ focus: selected && (focus || wasTabFocused) | ||
} else if ((0, _elementTypes.isTabPanel)(child)) { | ||
var props = { | ||
id: _this2.panelIds[index], | ||
tabId: _this2.tabIds[index], | ||
var _props = { | ||
id: panelIds.current[index], | ||
tabId: tabIds.current[index], | ||
selected: selectedIndex === index | ||
}; | ||
if (forceRenderTabPanel) props.forceRender = forceRenderTabPanel; | ||
if (selectedTabPanelClassName) props.selectedClassName = selectedTabPanelClassName; | ||
if (forceRenderTabPanel) _props.forceRender = forceRenderTabPanel; | ||
if (selectedTabPanelClassName) _props.selectedClassName = selectedTabPanelClassName; | ||
index++; | ||
result = /*#__PURE__*/(0, _react.cloneElement)(child, props); | ||
result = /*#__PURE__*/(0, _react.cloneElement)(child, _props); | ||
} | ||
@@ -345,4 +262,78 @@ | ||
}); | ||
}; | ||
} | ||
function handleKeyDown(e) { | ||
var direction = props.direction, | ||
disableUpDownKeys = props.disableUpDownKeys; | ||
if (isTabFromContainer(e.target)) { | ||
var index = props.selectedIndex; | ||
var preventDefault = false; | ||
var useSelectedIndex = false; | ||
if (e.keyCode === 32 || e.keyCode === 13) { | ||
preventDefault = true; | ||
useSelectedIndex = false; | ||
handleClick(e); | ||
} | ||
if (e.keyCode === 37 || !disableUpDownKeys && e.keyCode === 38) { | ||
// Select next tab to the left, validate if up arrow is not disabled | ||
if (direction === 'rtl') { | ||
index = getNextTab(index); | ||
} else { | ||
index = getPrevTab(index); | ||
} | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 39 || !disableUpDownKeys && e.keyCode === 40) { | ||
// Select next tab to the right, validate if down arrow is not disabled | ||
if (direction === 'rtl') { | ||
index = getPrevTab(index); | ||
} else { | ||
index = getNextTab(index); | ||
} | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 35) { | ||
// Select last tab (End key) | ||
index = getLastTab(); | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} else if (e.keyCode === 36) { | ||
// Select first tab (Home key) | ||
index = getFirstTab(); | ||
preventDefault = true; | ||
useSelectedIndex = true; | ||
} // This prevents scrollbars from moving around | ||
if (preventDefault) { | ||
e.preventDefault(); | ||
} // Only use the selected index in the state if we're not using the tabbed index | ||
if (useSelectedIndex) { | ||
setSelected(index, e); | ||
} | ||
} | ||
} | ||
function handleClick(e) { | ||
var node = e.target; | ||
do { | ||
if (isTabFromContainer(node)) { | ||
if (isTabDisabled(node)) { | ||
return; | ||
} | ||
var index = [].slice.call(node.parentNode.children).filter(isTabNode).indexOf(node); | ||
setSelected(index, e); | ||
return; | ||
} | ||
} while ((node = node.parentNode) != null); | ||
} | ||
/** | ||
@@ -353,3 +344,5 @@ * Determine if a node from event.target is a Tab element for the current Tabs container. | ||
*/ | ||
_proto.isTabFromContainer = function isTabFromContainer(node) { | ||
function isTabFromContainer(node) { | ||
// return immediately if the clicked element is not a Tab. | ||
@@ -364,3 +357,3 @@ if (!isTabNode(node)) { | ||
do { | ||
if (nodeAncestor === this.node) return true; | ||
if (nodeAncestor === _ref.current) return true; | ||
if (nodeAncestor.getAttribute('data-rttabs')) break; | ||
@@ -371,57 +364,33 @@ nodeAncestor = nodeAncestor.parentElement; | ||
return false; | ||
}; | ||
} | ||
_proto.render = function render() { | ||
var _this3 = this; | ||
var children = props.children, | ||
className = props.className, | ||
disabledTabClassName = props.disabledTabClassName, | ||
domRef = props.domRef, | ||
focus = props.focus, | ||
forceRenderTabPanel = props.forceRenderTabPanel, | ||
onSelect = props.onSelect, | ||
selectedIndex = props.selectedIndex, | ||
selectedTabClassName = props.selectedTabClassName, | ||
selectedTabPanelClassName = props.selectedTabPanelClassName, | ||
environment = props.environment, | ||
disableUpDownKeys = props.disableUpDownKeys, | ||
attributes = _objectWithoutPropertiesLoose(props, _excluded); | ||
// Delete all known props, so they don't get added to DOM | ||
var _this$props4 = this.props, | ||
children = _this$props4.children, | ||
className = _this$props4.className, | ||
disabledTabClassName = _this$props4.disabledTabClassName, | ||
domRef = _this$props4.domRef, | ||
focus = _this$props4.focus, | ||
forceRenderTabPanel = _this$props4.forceRenderTabPanel, | ||
onSelect = _this$props4.onSelect, | ||
selectedIndex = _this$props4.selectedIndex, | ||
selectedTabClassName = _this$props4.selectedTabClassName, | ||
selectedTabPanelClassName = _this$props4.selectedTabPanelClassName, | ||
environment = _this$props4.environment, | ||
disableUpDownKeys = _this$props4.disableUpDownKeys, | ||
attributes = _objectWithoutPropertiesLoose(_this$props4, _excluded); | ||
return /*#__PURE__*/_react["default"].createElement("div", _extends({}, attributes, { | ||
className: (0, _clsx["default"])(className), | ||
onClick: handleClick, | ||
onKeyDown: handleKeyDown, | ||
ref: function ref(node) { | ||
_ref.current = node; | ||
if (domRef) domRef(node); | ||
}, | ||
"data-rttabs": true | ||
}), getChildren()); | ||
}; | ||
return /*#__PURE__*/_react["default"].createElement("div", _extends({}, attributes, { | ||
className: (0, _clsx["default"])(className), | ||
onClick: this.handleClick, | ||
onKeyDown: this.handleKeyDown, | ||
ref: function ref(node) { | ||
_this3.node = node; | ||
if (domRef) domRef(node); | ||
}, | ||
"data-rttabs": true | ||
}), this.getChildren()); | ||
}; | ||
return UncontrolledTabs; | ||
}(_react.Component); | ||
exports["default"] = UncontrolledTabs; | ||
UncontrolledTabs.defaultProps = { | ||
className: 'react-tabs', | ||
focus: false | ||
}; | ||
UncontrolledTabs.propTypes = process.env.NODE_ENV !== "production" ? { | ||
children: _propTypes2.childrenPropType, | ||
direction: _propTypes["default"].oneOf(['rtl', 'ltr']), | ||
className: _propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].array, _propTypes["default"].object]), | ||
disabledTabClassName: _propTypes["default"].string, | ||
disableUpDownKeys: _propTypes["default"].bool, | ||
domRef: _propTypes["default"].func, | ||
focus: _propTypes["default"].bool, | ||
forceRenderTabPanel: _propTypes["default"].bool, | ||
onSelect: _propTypes["default"].func.isRequired, | ||
selectedIndex: _propTypes["default"].number.isRequired, | ||
selectedTabClassName: _propTypes["default"].string, | ||
selectedTabPanelClassName: _propTypes["default"].string, | ||
environment: _propTypes["default"].object | ||
} : {}; | ||
UncontrolledTabs.defaultProps = defaultProps; | ||
UncontrolledTabs.propTypes = process.env.NODE_ENV !== "production" ? propTypes : {}; | ||
var _default = UncontrolledTabs; | ||
exports["default"] = _default; |
"use strict"; | ||
exports.__esModule = true; | ||
exports.getPanelsCount = getPanelsCount; | ||
exports.getTabsCount = getTabsCount; | ||
@@ -17,10 +16,2 @@ | ||
return tabCount; | ||
} | ||
function getPanelsCount(children) { | ||
var panelCount = 0; | ||
(0, _childrenDeepMap.deepForEach)(children, function (child) { | ||
if ((0, _elementTypes.isTabPanel)(child)) panelCount++; | ||
}); | ||
return panelCount; | ||
} |
{ | ||
"name": "react-tabs", | ||
"version": "3.2.3", | ||
"version": "4.0.0", | ||
"description": "An accessible and easy tab component for ReactJS", | ||
@@ -18,5 +18,4 @@ "main": "lib/index.js", | ||
"prepublishOnly": "yarn run build", | ||
"release": "semantic-release --branches main", | ||
"test": "cross-env BABEL_OUTPUT=commonjs jest", | ||
"start": "webpack serve --allowed-hosts all --static-directory examples --port 8000", | ||
"start": "webpack serve", | ||
"website": "run-s website:clean website:build website:redirect", | ||
@@ -54,45 +53,39 @@ "website:clean": "rimraf examples/dist", | ||
"devDependencies": { | ||
"@babel/cli": "7.15.7", | ||
"@babel/core": "7.15.8", | ||
"@babel/eslint-parser": "7.15.8", | ||
"@babel/plugin-external-helpers": "7.14.5", | ||
"@babel/plugin-proposal-class-properties": "7.14.5", | ||
"@babel/plugin-proposal-object-rest-spread": "7.15.6", | ||
"@babel/plugin-syntax-dynamic-import": "7.8.3", | ||
"@babel/preset-env": "7.15.8", | ||
"@babel/preset-react": "7.14.5", | ||
"@testing-library/dom": "8.10.1", | ||
"@testing-library/jest-dom": "5.14.1", | ||
"@testing-library/react": "12.1.2", | ||
"@babel/cli": "7.17.6", | ||
"@babel/core": "7.17.5", | ||
"@babel/eslint-parser": "7.17.0", | ||
"@babel/preset-env": "7.16.11", | ||
"@babel/preset-react": "7.16.7", | ||
"@testing-library/dom": "8.11.3", | ||
"@testing-library/jest-dom": "5.16.2", | ||
"@testing-library/react": "12.1.3", | ||
"@testing-library/user-event": "13.5.0", | ||
"babel-jest": "27.3.1", | ||
"babel-jest": "27.5.1", | ||
"babel-loader": "8.2.3", | ||
"babel-plugin-transform-react-remove-prop-types": "0.4.24", | ||
"cross-env": "7.0.3", | ||
"css-loader": "6.5.0", | ||
"enzyme": "3.11.0", | ||
"eslint": "7.32.0", | ||
"eslint-config-prettier": "8.3.0", | ||
"eslint-plugin-import": "2.25.2", | ||
"eslint-plugin-jsx-a11y": "6.4.1", | ||
"css-loader": "6.6.0", | ||
"eslint": "8.10.0", | ||
"eslint-config-prettier": "8.4.0", | ||
"eslint-plugin-import": "2.25.4", | ||
"eslint-plugin-jsx-a11y": "6.5.1", | ||
"eslint-plugin-prettier": "4.0.0", | ||
"eslint-plugin-react": "7.26.1", | ||
"file-loader": "6.2.0", | ||
"eslint-plugin-react": "7.29.2", | ||
"hoist-non-react-statics": "3.3.2", | ||
"html-loader": "2.1.2", | ||
"html-loader": "3.1.0", | ||
"html-webpack-plugin": "5.5.0", | ||
"jest": "27.3.1", | ||
"jest-environment-jsdom": "27.3.1", | ||
"jest": "27.5.1", | ||
"jest-environment-jsdom": "27.5.1", | ||
"less": "4.1.2", | ||
"less-loader": "10.2.0", | ||
"mini-css-extract-plugin": "2.4.3", | ||
"mini-css-extract-plugin": "2.5.3", | ||
"npm-run-all": "4.1.5", | ||
"prettier": "2.4.1", | ||
"prettier": "2.5.1", | ||
"react": "17.0.2", | ||
"react-dom": "17.0.2", | ||
"react-live": "2.3.0", | ||
"react-modal": "3.14.3", | ||
"react-live": "2.4.1", | ||
"react-modal": "3.14.4", | ||
"react-test-renderer": "17.0.2", | ||
"rimraf": "3.0.2", | ||
"rollup": "2.58.3", | ||
"rollup": "2.68.0", | ||
"rollup-plugin-babel": "4.4.0", | ||
@@ -104,6 +97,5 @@ "rollup-plugin-commonjs": "10.1.0", | ||
"rollup-plugin-terser": "7.0.2", | ||
"semantic-release": "18.0.0", | ||
"webpack": "5.60.0", | ||
"webpack-cli": "4.9.1", | ||
"webpack-dev-server": "4.4.0" | ||
"webpack": "5.69.1", | ||
"webpack-cli": "4.9.2", | ||
"webpack-dev-server": "4.7.4" | ||
}, | ||
@@ -110,0 +102,0 @@ "dependencies": { |
@@ -1,2 +0,2 @@ | ||
# react-tabs [![npm version](https://img.shields.io/npm/v/react-tabs.svg)](https://www.npmjs.com/package/react-tabs) | ||
# react-tabs [![npm version](https://img.shields.io/npm/v/react-tabs.svg)](https://www.npmjs.com/package/react-tabs) [![codecov](https://codecov.io/gh/reactjs/react-tabs/branch/main/graph/badge.svg?token=XnEVrthAub)](https://codecov.io/gh/reactjs/react-tabs) | ||
@@ -356,2 +356,3 @@ An accessible and easy tab component for ReactJS. | ||
#### Set `tabsRole` | ||
In case you want to create your own component wrapping the ones that the library provides, you have to set its `tabsRole`. This value is used inside react-tabs to check the role of a component inside `<Tabs />`. | ||
@@ -364,7 +365,13 @@ | ||
#### Pass through properties | ||
Note: Because of how react-tabs works internally (it uses cloning to opaquely control various parts of the tab state), you need to pass any incoming props to the component you're wrapping. The easiest way to do this is to use the rest and spread operators, e.g. see `{...otherProps}` below. | ||
``` javascript | ||
import { Tabs, TabList, Tab, TabPanel } from 'react-tabs'; | ||
const CustomTab = ({ children }) => ( | ||
<Tab> | ||
// All custom elements should pass through other props | ||
const CustomTab = ({ children, ...otherProps }) => ( | ||
<Tab {...otherProps}> | ||
<h1>{children}</h1> | ||
@@ -388,18 +395,4 @@ </Tab> | ||
This works for custom tabs, but will not suffice for something like a TabPanel. Because of how react-tabs works internally (it uses cloning to opaquely control various parts of the tab state), you need to pass any incoming props to the component you're wrapping. The easiest way to do this is to use the rest and spread operators, e.g.: | ||
``` javascript | ||
const CustomTabPanel = ({ children, myCustomProp, ...otherProps }) => ( | ||
<TabPanel {...otherProps}> | ||
<h1>{children}</h1> | ||
{myCustomProp && `myCustomProp: ${myCustomProp}`} | ||
</TabPanel> | ||
) | ||
CustomTabPanel.tabsRole = 'TabPanel' | ||
``` | ||
## License | ||
MIT |
@@ -267,2 +267,31 @@ import { format } from 'util'; | ||
test('should throw when mode of component changes', () => { | ||
const { rerender } = render( | ||
<Tabs defaultIndex={1} onSelect={() => {}}> | ||
<TabList> | ||
<Tab>Foo</Tab> | ||
<Tab>Foo2</Tab> | ||
</TabList> | ||
<TabPanel>Foo</TabPanel> | ||
<TabPanel>Foo2</TabPanel> | ||
</Tabs>, | ||
); | ||
try { | ||
rerender( | ||
<Tabs selectedIndex={1} onSelect={() => {}}> | ||
<TabList> | ||
<Tab>Foo</Tab> | ||
<Tab>Foo2</Tab> | ||
</TabList> | ||
<TabPanel>Foo</TabPanel> | ||
<TabPanel>Foo2</TabPanel> | ||
</Tabs>, | ||
); | ||
} catch (e) { | ||
expect(e.message).toContain( | ||
'Switching between controlled mode (by using `selectedIndex`) and uncontrolled mode is not supported in `Tabs`.', | ||
); | ||
} | ||
}); | ||
test('should result with warning when defaultIndex and selectedIndex set', () => { | ||
@@ -269,0 +298,0 @@ expect(() => |
import PropTypes from 'prop-types'; | ||
import React, { Component } from 'react'; | ||
import React, { useEffect, useRef } from 'react'; | ||
import cx from 'clsx'; | ||
const DEFAULT_CLASS = 'react-tabs__tab'; | ||
const DEFAULT_PROPS = { | ||
className: DEFAULT_CLASS, | ||
disabledClassName: `${DEFAULT_CLASS}--disabled`, | ||
focus: false, | ||
id: null, | ||
panelId: null, | ||
selected: false, | ||
selectedClassName: `${DEFAULT_CLASS}--selected`, | ||
}; | ||
export default class Tab extends Component { | ||
static defaultProps = { | ||
className: DEFAULT_CLASS, | ||
disabledClassName: `${DEFAULT_CLASS}--disabled`, | ||
focus: false, | ||
id: null, | ||
panelId: null, | ||
selected: false, | ||
selectedClassName: `${DEFAULT_CLASS}--selected`, | ||
}; | ||
const propTypes = { | ||
children: PropTypes.oneOfType([ | ||
PropTypes.array, | ||
PropTypes.object, | ||
PropTypes.string, | ||
]), | ||
className: PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.array, | ||
PropTypes.object, | ||
]), | ||
disabled: PropTypes.bool, | ||
tabIndex: PropTypes.string, | ||
disabledClassName: PropTypes.string, | ||
focus: PropTypes.bool, // private | ||
id: PropTypes.string, // private | ||
panelId: PropTypes.string, // private | ||
selected: PropTypes.bool, // private | ||
selectedClassName: PropTypes.string, | ||
tabRef: PropTypes.func, | ||
}; | ||
static propTypes = { | ||
children: PropTypes.oneOfType([ | ||
PropTypes.array, | ||
PropTypes.object, | ||
PropTypes.string, | ||
]), | ||
className: PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.array, | ||
PropTypes.object, | ||
]), | ||
disabled: PropTypes.bool, | ||
tabIndex: PropTypes.string, | ||
disabledClassName: PropTypes.string, | ||
focus: PropTypes.bool, // private | ||
id: PropTypes.string, // private | ||
panelId: PropTypes.string, // private | ||
selected: PropTypes.bool, // private | ||
selectedClassName: PropTypes.string, | ||
tabRef: PropTypes.func, // private | ||
}; | ||
componentDidMount() { | ||
this.checkFocus(); | ||
} | ||
componentDidUpdate() { | ||
this.checkFocus(); | ||
} | ||
checkFocus() { | ||
const { selected, focus } = this.props; | ||
const Tab = (props) => { | ||
let nodeRef = useRef(); | ||
const checkFocus = () => { | ||
const { selected, focus } = props; | ||
if (selected && focus) { | ||
this.node.focus(); | ||
nodeRef.current.focus(); | ||
} | ||
} | ||
}; | ||
useEffect(() => { | ||
checkFocus(); | ||
}); | ||
const { | ||
children, | ||
className, | ||
disabled, | ||
disabledClassName, | ||
focus, // unused | ||
id, | ||
panelId, | ||
selected, | ||
selectedClassName, | ||
tabIndex, | ||
tabRef, | ||
...attributes | ||
} = props; | ||
render() { | ||
const { | ||
children, | ||
className, | ||
disabled, | ||
disabledClassName, | ||
focus, // unused | ||
id, | ||
panelId, | ||
selected, | ||
selectedClassName, | ||
tabIndex, | ||
tabRef, | ||
...attributes | ||
} = this.props; | ||
return ( | ||
<li | ||
{...attributes} | ||
className={cx(className, { | ||
[selectedClassName]: selected, | ||
[disabledClassName]: disabled, | ||
})} | ||
ref={(node) => { | ||
nodeRef.current = node; | ||
if (tabRef) tabRef(node); | ||
}} | ||
role="tab" | ||
id={id} | ||
aria-selected={selected ? 'true' : 'false'} | ||
aria-disabled={disabled ? 'true' : 'false'} | ||
aria-controls={panelId} | ||
tabIndex={tabIndex || (selected ? '0' : null)} | ||
data-rttab | ||
> | ||
{children} | ||
</li> | ||
); | ||
}; | ||
Tab.propTypes = propTypes; | ||
return ( | ||
<li | ||
{...attributes} | ||
className={cx(className, { | ||
[selectedClassName]: selected, | ||
[disabledClassName]: disabled, | ||
})} | ||
ref={(node) => { | ||
this.node = node; | ||
if (tabRef) tabRef(node); | ||
}} | ||
role="tab" | ||
id={id} | ||
aria-selected={selected ? 'true' : 'false'} | ||
aria-disabled={disabled ? 'true' : 'false'} | ||
aria-controls={panelId} | ||
tabIndex={tabIndex || (selected ? '0' : null)} | ||
data-rttab | ||
> | ||
{children} | ||
</li> | ||
); | ||
} | ||
} | ||
Tab.tabsRole = 'Tab'; | ||
Tab.defaultProps = DEFAULT_PROPS; | ||
export default Tab; |
import PropTypes from 'prop-types'; | ||
import React, { Component } from 'react'; | ||
import React from 'react'; | ||
import cx from 'clsx'; | ||
export default class TabList extends Component { | ||
static defaultProps = { | ||
className: 'react-tabs__tab-list', | ||
}; | ||
const defaultProps = { | ||
className: 'react-tabs__tab-list', | ||
}; | ||
const propTypes = { | ||
children: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), | ||
className: PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.array, | ||
PropTypes.object, | ||
]), | ||
}; | ||
const TabList = (props) => { | ||
const { children, className, ...attributes } = props; | ||
static propTypes = { | ||
children: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), | ||
className: PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.array, | ||
PropTypes.object, | ||
]), | ||
}; | ||
return ( | ||
<ul {...attributes} className={cx(className)} role="tablist"> | ||
{children} | ||
</ul> | ||
); | ||
}; | ||
render() { | ||
const { children, className, ...attributes } = this.props; | ||
return ( | ||
<ul {...attributes} className={cx(className)} role="tablist"> | ||
{children} | ||
</ul> | ||
); | ||
} | ||
} | ||
TabList.tabsRole = 'TabList'; | ||
TabList.propTypes = propTypes; | ||
TabList.defaultProps = defaultProps; | ||
export default TabList; |
import PropTypes from 'prop-types'; | ||
import React, { Component } from 'react'; | ||
import React from 'react'; | ||
import cx from 'clsx'; | ||
const DEFAULT_CLASS = 'react-tabs__tab-panel'; | ||
const defaultProps = { | ||
className: DEFAULT_CLASS, | ||
forceRender: false, | ||
selectedClassName: `${DEFAULT_CLASS}--selected`, | ||
}; | ||
const propTypes = { | ||
children: PropTypes.node, | ||
className: PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.array, | ||
PropTypes.object, | ||
]), | ||
forceRender: PropTypes.bool, | ||
id: PropTypes.string, // private | ||
selected: PropTypes.bool, // private | ||
selectedClassName: PropTypes.string, | ||
tabId: PropTypes.string, // private | ||
}; | ||
const TabPanel = (props) => { | ||
const { | ||
children, | ||
className, | ||
forceRender, | ||
id, | ||
selected, | ||
selectedClassName, | ||
tabId, | ||
...attributes | ||
} = props; | ||
export default class TabPanel extends Component { | ||
static defaultProps = { | ||
className: DEFAULT_CLASS, | ||
forceRender: false, | ||
selectedClassName: `${DEFAULT_CLASS}--selected`, | ||
}; | ||
return ( | ||
<div | ||
{...attributes} | ||
className={cx(className, { | ||
[selectedClassName]: selected, | ||
})} | ||
role="tabpanel" | ||
id={id} | ||
aria-labelledby={tabId} | ||
> | ||
{forceRender || selected ? children : null} | ||
</div> | ||
); | ||
}; | ||
static propTypes = { | ||
children: PropTypes.node, | ||
className: PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.array, | ||
PropTypes.object, | ||
]), | ||
forceRender: PropTypes.bool, | ||
id: PropTypes.string, // private | ||
selected: PropTypes.bool, // private | ||
selectedClassName: PropTypes.string, | ||
tabId: PropTypes.string, // private | ||
}; | ||
render() { | ||
const { | ||
children, | ||
className, | ||
forceRender, | ||
id, | ||
selected, | ||
selectedClassName, | ||
tabId, | ||
...attributes | ||
} = this.props; | ||
return ( | ||
<div | ||
{...attributes} | ||
className={cx(className, { | ||
[selectedClassName]: selected, | ||
})} | ||
role="tabpanel" | ||
id={id} | ||
aria-labelledby={tabId} | ||
> | ||
{forceRender || selected ? children : null} | ||
</div> | ||
); | ||
} | ||
} | ||
TabPanel.tabsRole = 'TabPanel'; | ||
TabPanel.propTypes = propTypes; | ||
TabPanel.defaultProps = defaultProps; | ||
export default TabPanel; |
import PropTypes from 'prop-types'; | ||
import React, { Component } from 'react'; | ||
import React, { useEffect, useState } from 'react'; | ||
import { | ||
@@ -13,52 +13,83 @@ childrenPropType, | ||
const MODE_UNCONTROLLED = 1; | ||
const propTypes = { | ||
children: childrenPropType, | ||
direction: PropTypes.oneOf(['rtl', 'ltr']), | ||
className: PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.array, | ||
PropTypes.object, | ||
]), | ||
defaultFocus: PropTypes.bool, | ||
defaultIndex: PropTypes.number, | ||
disabledTabClassName: PropTypes.string, | ||
disableUpDownKeys: PropTypes.bool, | ||
domRef: PropTypes.func, | ||
forceRenderTabPanel: PropTypes.bool, | ||
onSelect: onSelectPropType, | ||
selectedIndex: selectedIndexPropType, | ||
selectedTabClassName: PropTypes.string, | ||
selectedTabPanelClassName: PropTypes.string, | ||
environment: PropTypes.object, | ||
}; | ||
const defaultProps = { | ||
defaultFocus: false, | ||
forceRenderTabPanel: false, | ||
selectedIndex: null, | ||
defaultIndex: null, | ||
environment: null, | ||
disableUpDownKeys: false, | ||
}; | ||
export default class Tabs extends Component { | ||
static defaultProps = { | ||
defaultFocus: false, | ||
forceRenderTabPanel: false, | ||
selectedIndex: null, | ||
defaultIndex: null, | ||
environment: null, | ||
disableUpDownKeys: false, | ||
}; | ||
const getModeFromProps = (props) => { | ||
return props.selectedIndex === null ? MODE_UNCONTROLLED : MODE_CONTROLLED; | ||
}; | ||
static propTypes = { | ||
children: childrenPropType, | ||
direction: PropTypes.oneOf(['rtl', 'ltr']), | ||
className: PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.array, | ||
PropTypes.object, | ||
]), | ||
defaultFocus: PropTypes.bool, | ||
defaultIndex: PropTypes.number, | ||
disabledTabClassName: PropTypes.string, | ||
disableUpDownKeys: PropTypes.bool, | ||
domRef: PropTypes.func, | ||
forceRenderTabPanel: PropTypes.bool, | ||
onSelect: onSelectPropType, | ||
selectedIndex: selectedIndexPropType, | ||
selectedTabClassName: PropTypes.string, | ||
selectedTabPanelClassName: PropTypes.string, | ||
environment: PropTypes.object, | ||
}; | ||
const checkForIllegalModeChange = (props, mode) => { | ||
if ( | ||
process.env.NODE_ENV !== 'production' && | ||
mode != undefined && | ||
mode !== getModeFromProps(props) | ||
) { | ||
throw new Error( | ||
`Switching between controlled mode (by using \`selectedIndex\`) and uncontrolled mode is not supported in \`Tabs\`. | ||
For more information about controlled and uncontrolled mode of react-tabs see https://github.com/reactjs/react-tabs#controlled-vs-uncontrolled-mode.`, | ||
); | ||
} | ||
}; | ||
constructor(props) { | ||
super(props); | ||
/** | ||
* State: | ||
* mode: Initialized only once from props and never changes | ||
* selectedIndex: null if controlled mode, otherwise initialized with prop defaultIndex, changed on selection of tabs, has effect to ensure it never gets out of bound | ||
* focus: Because we never remove focus from the Tabs this state is only used to indicate that we should focus the current tab. | ||
* It is initialized from the prop defaultFocus, and after the first render it is reset back to false. Later it can become true again when using keys to navigate the tabs. | ||
*/ | ||
const Tabs = (props) => { | ||
const { children, defaultFocus, defaultIndex, onSelect } = props; | ||
this.state = Tabs.copyPropsToState(this.props, {}, props.defaultFocus); | ||
} | ||
const [focus, setFocus] = useState(defaultFocus); | ||
const [mode] = useState(getModeFromProps(props)); | ||
const [selectedIndex, setSelectedIndex] = useState( | ||
mode === MODE_UNCONTROLLED ? defaultIndex || 0 : null, | ||
); | ||
static getDerivedStateFromProps(props, state) { | ||
return Tabs.copyPropsToState(props, state); | ||
} | ||
useEffect(() => { | ||
// Reset focus after initial render, see comment above | ||
setFocus(false); | ||
}, []); | ||
static getModeFromProps(props) { | ||
return props.selectedIndex === null ? MODE_UNCONTROLLED : MODE_CONTROLLED; | ||
if (mode === MODE_UNCONTROLLED) { | ||
// Ensure that we handle removed tabs and don't let selectedIndex get out of bounds | ||
const tabsCount = getTabsCount(children); | ||
useEffect(() => { | ||
if (selectedIndex != null) { | ||
const maxTabIndex = Math.max(0, tabsCount - 1); | ||
setSelectedIndex(Math.min(selectedIndex, maxTabIndex)); | ||
} | ||
}, [tabsCount]); | ||
} | ||
handleSelected = (index, last, event) => { | ||
const { onSelect } = this.props; | ||
const { mode } = this.state; | ||
checkForIllegalModeChange(props, mode); | ||
const handleSelected = (index, last, event) => { | ||
// Call change event handler | ||
@@ -70,64 +101,28 @@ if (typeof onSelect === 'function') { | ||
const state = { | ||
// Set focus if the change was triggered from the keyboard | ||
focus: event.type === 'keydown', | ||
}; | ||
// Always set focus on tabs | ||
setFocus(true); | ||
if (mode === MODE_UNCONTROLLED) { | ||
// Update selected index | ||
state.selectedIndex = index; | ||
setSelectedIndex(index); | ||
} | ||
this.setState(state); | ||
}; | ||
// preserve the existing selectedIndex from state. | ||
// If the state has not selectedIndex, default to the defaultIndex or 0 | ||
static copyPropsToState(props, state, focus = false) { | ||
if ( | ||
process.env.NODE_ENV !== 'production' && | ||
state.mode !== undefined && | ||
state.mode !== Tabs.getModeFromProps(props) | ||
) { | ||
throw new Error( | ||
`Switching between controlled mode (by using \`selectedIndex\`) and uncontrolled mode is not supported in \`Tabs\`. | ||
For more information about controlled and uncontrolled mode of react-tabs see https://github.com/reactjs/react-tabs#controlled-vs-uncontrolled-mode.`, | ||
); | ||
} | ||
let subProps = { ...props }; | ||
const newState = { | ||
focus, | ||
mode: Tabs.getModeFromProps(props), | ||
}; | ||
subProps.focus = focus; | ||
subProps.onSelect = handleSelected; | ||
if (newState.mode === MODE_UNCONTROLLED) { | ||
const maxTabIndex = Math.max(0, getTabsCount(props.children) - 1); | ||
let selectedIndex = null; | ||
if (state.selectedIndex != null) { | ||
selectedIndex = Math.min(state.selectedIndex, maxTabIndex); | ||
} else { | ||
selectedIndex = props.defaultIndex || 0; | ||
} | ||
newState.selectedIndex = selectedIndex; | ||
} | ||
return newState; | ||
if (selectedIndex != null) { | ||
subProps.selectedIndex = selectedIndex; | ||
} | ||
delete subProps.defaultFocus; | ||
delete subProps.defaultIndex; | ||
return <UncontrolledTabs {...subProps}>{children}</UncontrolledTabs>; | ||
}; | ||
render() { | ||
const { children, defaultIndex, defaultFocus, ...props } = this.props; | ||
const { focus, selectedIndex } = this.state; | ||
Tabs.propTypes = propTypes; | ||
Tabs.defaultProps = defaultProps; | ||
Tabs.tabsRole = 'Tabs'; | ||
props.focus = focus; | ||
props.onSelect = this.handleSelected; | ||
if (selectedIndex != null) { | ||
props.selectedIndex = selectedIndex; | ||
} | ||
return <UncontrolledTabs {...props}>{children}</UncontrolledTabs>; | ||
} | ||
} | ||
Tabs.tabsRole = 'Tabs'; | ||
export default Tabs; |
import PropTypes from 'prop-types'; | ||
import React, { cloneElement, Component } from 'react'; | ||
import React, { cloneElement, useRef } from 'react'; | ||
import cx from 'clsx'; | ||
import uuid from '../helpers/uuid'; | ||
import { childrenPropType } from '../helpers/propTypes'; | ||
import { getPanelsCount, getTabsCount } from '../helpers/count'; | ||
import { getTabsCount as getTabsCountHelper } from '../helpers/count'; | ||
import { deepMap } from '../helpers/childrenDeepMap'; | ||
@@ -44,35 +44,39 @@ import { isTabList, isTabPanel, isTab } from '../helpers/elementTypes'; | ||
} | ||
export default class UncontrolledTabs extends Component { | ||
static defaultProps = { | ||
className: 'react-tabs', | ||
focus: false, | ||
}; | ||
static propTypes = { | ||
children: childrenPropType, | ||
direction: PropTypes.oneOf(['rtl', 'ltr']), | ||
className: PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.array, | ||
PropTypes.object, | ||
]), | ||
disabledTabClassName: PropTypes.string, | ||
disableUpDownKeys: PropTypes.bool, | ||
domRef: PropTypes.func, | ||
focus: PropTypes.bool, | ||
forceRenderTabPanel: PropTypes.bool, | ||
onSelect: PropTypes.func.isRequired, | ||
selectedIndex: PropTypes.number.isRequired, | ||
selectedTabClassName: PropTypes.string, | ||
selectedTabPanelClassName: PropTypes.string, | ||
environment: PropTypes.object, | ||
}; | ||
const defaultProps = { | ||
className: 'react-tabs', | ||
focus: false, | ||
}; | ||
tabNodes = []; | ||
const propTypes = { | ||
children: childrenPropType, | ||
direction: PropTypes.oneOf(['rtl', 'ltr']), | ||
className: PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.array, | ||
PropTypes.object, | ||
]), | ||
disabledTabClassName: PropTypes.string, | ||
disableUpDownKeys: PropTypes.bool, | ||
domRef: PropTypes.func, | ||
focus: PropTypes.bool, | ||
forceRenderTabPanel: PropTypes.bool, | ||
onSelect: PropTypes.func.isRequired, | ||
selectedIndex: PropTypes.number.isRequired, | ||
selectedTabClassName: PropTypes.string, | ||
selectedTabPanelClassName: PropTypes.string, | ||
environment: PropTypes.object, | ||
}; | ||
setSelected(index, event) { | ||
const UncontrolledTabs = (props) => { | ||
let tabNodes = useRef([]); | ||
let tabIds = useRef([]); | ||
let panelIds = useRef([]); | ||
const ref = useRef(); | ||
function setSelected(index, event) { | ||
// Check index boundary | ||
if (index < 0 || index >= this.getTabsCount()) return; | ||
if (index < 0 || index >= getTabsCount()) return; | ||
const { onSelect, selectedIndex } = this.props; | ||
const { onSelect, selectedIndex } = props; | ||
@@ -83,8 +87,8 @@ // Call change event handler | ||
getNextTab(index) { | ||
const count = this.getTabsCount(); | ||
function getNextTab(index) { | ||
const count = getTabsCount(); | ||
// Look for non-disabled tab from index to the last tab on the right | ||
for (let i = index + 1; i < count; i++) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -96,3 +100,3 @@ } | ||
for (let i = 0; i < index; i++) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -106,3 +110,3 @@ } | ||
getPrevTab(index) { | ||
function getPrevTab(index) { | ||
let i = index; | ||
@@ -112,3 +116,3 @@ | ||
while (i--) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -119,5 +123,5 @@ } | ||
// If no tab found, continue searching from last tab on right to index | ||
i = this.getTabsCount(); | ||
i = getTabsCount(); | ||
while (i-- > index) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -131,8 +135,8 @@ } | ||
getFirstTab() { | ||
const count = this.getTabsCount(); | ||
function getFirstTab() { | ||
const count = getTabsCount(); | ||
// Look for non disabled tab from the first tab | ||
for (let i = 0; i < count; i++) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -145,8 +149,8 @@ } | ||
getLastTab() { | ||
let i = this.getTabsCount(); | ||
function getLastTab() { | ||
let i = getTabsCount(); | ||
// Look for non disabled tab from the last tab | ||
while (i--) { | ||
if (!isTabDisabled(this.getTab(i))) { | ||
if (!isTabDisabled(getTab(i))) { | ||
return i; | ||
@@ -159,17 +163,12 @@ } | ||
getTabsCount() { | ||
const { children } = this.props; | ||
return getTabsCount(children); | ||
function getTabsCount() { | ||
const { children } = props; | ||
return getTabsCountHelper(children); | ||
} | ||
getPanelsCount() { | ||
const { children } = this.props; | ||
return getPanelsCount(children); | ||
function getTab(index) { | ||
return tabNodes.current[`tabs-${index}`]; | ||
} | ||
getTab(index) { | ||
return this.tabNodes[`tabs-${index}`]; | ||
} | ||
getChildren() { | ||
function getChildren() { | ||
let index = 0; | ||
@@ -185,7 +184,7 @@ const { | ||
environment, | ||
} = this.props; | ||
} = props; | ||
this.tabIds = this.tabIds || []; | ||
this.panelIds = this.panelIds || []; | ||
let diff = this.tabIds.length - this.getTabsCount(); | ||
tabIds.current = tabIds.current || []; | ||
panelIds.current = panelIds.current || []; | ||
let diff = tabIds.current.length - getTabsCount(); | ||
@@ -196,4 +195,4 @@ // Add ids if new tabs have been added | ||
while (diff++ < 0) { | ||
this.tabIds.push(uuid()); | ||
this.panelIds.push(uuid()); | ||
tabIds.current.push(uuid()); | ||
panelIds.current.push(uuid()); | ||
} | ||
@@ -224,3 +223,3 @@ | ||
(typeof window !== 'undefined' ? window : undefined); | ||
return env && env.document.activeElement === this.getTab(i); | ||
return env && env.document.activeElement === getTab(i); | ||
}); | ||
@@ -236,6 +235,6 @@ } | ||
tabRef: (node) => { | ||
this.tabNodes[key] = node; | ||
tabNodes.current[key] = node; | ||
}, | ||
id: this.tabIds[listIndex], | ||
panelId: this.panelIds[listIndex], | ||
id: tabIds.current[listIndex], | ||
panelId: panelIds.current[listIndex], | ||
selected, | ||
@@ -257,4 +256,4 @@ focus: selected && (focus || wasTabFocused), | ||
const props = { | ||
id: this.panelIds[index], | ||
tabId: this.tabIds[index], | ||
id: panelIds.current[index], | ||
tabId: tabIds.current[index], | ||
selected: selectedIndex === index, | ||
@@ -276,6 +275,6 @@ }; | ||
handleKeyDown = (e) => { | ||
const { direction, disableUpDownKeys } = this.props; | ||
if (this.isTabFromContainer(e.target)) { | ||
let { selectedIndex: index } = this.props; | ||
function handleKeyDown(e) { | ||
const { direction, disableUpDownKeys } = props; | ||
if (isTabFromContainer(e.target)) { | ||
let { selectedIndex: index } = props; | ||
let preventDefault = false; | ||
@@ -287,3 +286,3 @@ let useSelectedIndex = false; | ||
useSelectedIndex = false; | ||
this.handleClick(e); | ||
handleClick(e); | ||
} | ||
@@ -294,5 +293,5 @@ | ||
if (direction === 'rtl') { | ||
index = this.getNextTab(index); | ||
index = getNextTab(index); | ||
} else { | ||
index = this.getPrevTab(index); | ||
index = getPrevTab(index); | ||
} | ||
@@ -304,5 +303,5 @@ preventDefault = true; | ||
if (direction === 'rtl') { | ||
index = this.getPrevTab(index); | ||
index = getPrevTab(index); | ||
} else { | ||
index = this.getNextTab(index); | ||
index = getNextTab(index); | ||
} | ||
@@ -313,3 +312,3 @@ preventDefault = true; | ||
// Select last tab (End key) | ||
index = this.getLastTab(); | ||
index = getLastTab(); | ||
preventDefault = true; | ||
@@ -319,3 +318,3 @@ useSelectedIndex = true; | ||
// Select first tab (Home key) | ||
index = this.getFirstTab(); | ||
index = getFirstTab(); | ||
preventDefault = true; | ||
@@ -332,11 +331,11 @@ useSelectedIndex = true; | ||
if (useSelectedIndex) { | ||
this.setSelected(index, e); | ||
setSelected(index, e); | ||
} | ||
} | ||
}; | ||
} | ||
handleClick = (e) => { | ||
function handleClick(e) { | ||
let node = e.target; | ||
do { | ||
if (this.isTabFromContainer(node)) { | ||
if (isTabFromContainer(node)) { | ||
if (isTabDisabled(node)) { | ||
@@ -350,7 +349,7 @@ return; | ||
.indexOf(node); | ||
this.setSelected(index, e); | ||
setSelected(index, e); | ||
return; | ||
} | ||
} while ((node = node.parentNode) != null); | ||
}; | ||
} | ||
@@ -362,3 +361,3 @@ /** | ||
*/ | ||
isTabFromContainer(node) { | ||
function isTabFromContainer(node) { | ||
// return immediately if the clicked element is not a Tab. | ||
@@ -372,3 +371,3 @@ if (!isTabNode(node)) { | ||
do { | ||
if (nodeAncestor === this.node) return true; | ||
if (nodeAncestor === ref.current) return true; | ||
if (nodeAncestor.getAttribute('data-rttabs')) break; | ||
@@ -381,37 +380,35 @@ | ||
} | ||
render() { | ||
// Delete all known props, so they don't get added to DOM | ||
const { | ||
children, // unused | ||
className, | ||
disabledTabClassName, // unused | ||
domRef, | ||
focus, // unused | ||
forceRenderTabPanel, // unused | ||
onSelect, // unused | ||
selectedIndex, // unused | ||
selectedTabClassName, // unused | ||
selectedTabPanelClassName, // unused | ||
environment, // unused | ||
disableUpDownKeys, // unused | ||
...attributes | ||
} = this.props; | ||
return ( | ||
<div | ||
{...attributes} | ||
className={cx(className)} | ||
onClick={this.handleClick} | ||
onKeyDown={this.handleKeyDown} | ||
ref={(node) => { | ||
this.node = node; | ||
if (domRef) domRef(node); | ||
}} | ||
data-rttabs | ||
> | ||
{this.getChildren()} | ||
</div> | ||
); | ||
} | ||
} | ||
const { | ||
children, // unused | ||
className, | ||
disabledTabClassName, // unused | ||
domRef, | ||
focus, // unused | ||
forceRenderTabPanel, // unused | ||
onSelect, // unused | ||
selectedIndex, // unused | ||
selectedTabClassName, // unused | ||
selectedTabPanelClassName, // unused | ||
environment, // unused | ||
disableUpDownKeys, // unused | ||
...attributes | ||
} = props; | ||
return ( | ||
<div | ||
{...attributes} | ||
className={cx(className)} | ||
onClick={handleClick} | ||
onKeyDown={handleKeyDown} | ||
ref={(node) => { | ||
ref.current = node; | ||
if (domRef) domRef(node); | ||
}} | ||
data-rttabs | ||
> | ||
{getChildren()} | ||
</div> | ||
); | ||
}; | ||
UncontrolledTabs.defaultProps = defaultProps; | ||
UncontrolledTabs.propTypes = propTypes; | ||
export default UncontrolledTabs; |
import { deepForEach } from './childrenDeepMap'; | ||
import { isTab, isTabPanel } from './elementTypes'; | ||
import { isTab } from './elementTypes'; | ||
@@ -12,10 +12,1 @@ export function getTabsCount(children) { | ||
} | ||
export function getPanelsCount(children) { | ||
let panelCount = 0; | ||
deepForEach(children, (child) => { | ||
if (isTabPanel(child)) panelCount++; | ||
}); | ||
return panelCount; | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
46
281715
3719
396
23