metadata-based-explorer1
Version:
Box UI Elements
388 lines (321 loc) • 15.5 kB
JavaScript
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import * as React from 'react';
import classNames from 'classnames';
import omit from 'lodash/omit';
import uniqueId from 'lodash/uniqueId';
import IconPageBack from '../../icons/general/IconPageBack';
import IconPageForward from '../../icons/general/IconPageForward';
import LinkButton from '../link/LinkButton';
import './Tabs.scss';
export var TAB_KEY = 'Tab';
export var TAB_PANEL_ROLE = 'tabpanel';
var TabViewPrimitive =
/*#__PURE__*/
function (_React$Component) {
_inherits(TabViewPrimitive, _React$Component);
function TabViewPrimitive(props) {
var _this;
_classCallCheck(this, TabViewPrimitive);
_this = _possibleConstructorReturn(this, _getPrototypeOf(TabViewPrimitive).call(this, props));
_defineProperty(_assertThisInitialized(_this), "onClickTab", function (tabIndex) {
var _this$props = _this.props,
onTabFocus = _this$props.onTabFocus,
onTabSelect = _this$props.onTabSelect;
if (onTabSelect) {
onTabSelect(tabIndex);
}
onTabFocus(tabIndex);
});
_defineProperty(_assertThisInitialized(_this), "getLastElementsAnchorPoint", function () {
if (_this.tabsElements.length === 0) {
return 0;
}
var lastTabElement = _this.tabsElements[_this.tabsElements.length - 1];
return lastTabElement.offsetLeft + lastTabElement.offsetWidth;
});
_defineProperty(_assertThisInitialized(_this), "getTabsContainerOffsetLeft", function () {
if (!_this.tabsContainer) {
return 0;
}
var tabsContainerOffsetLeft = _this.state.tabsContainerOffsetLeft;
var viewportOffset = parseInt(tabsContainerOffsetLeft, 10) * -1;
viewportOffset = viewportOffset || 0;
return viewportOffset;
});
_defineProperty(_assertThisInitialized(_this), "getTabsContainerWidth", function () {
return _this.tabsContainer ? parseInt(_this.tabsContainer.offsetWidth, 10) : 0;
});
_defineProperty(_assertThisInitialized(_this), "scrollToTab", function (tabIndex) {
if (!_this.props.isDynamic || _this.tabsContainer === null || _this.tabsElements.length === 0 || tabIndex < 0 || tabIndex > _this.tabsElements.length - 1) {
return;
}
var tabElementOfInterest = _this.tabsElements[tabIndex];
var lastElementsAnchorPoint = _this.getLastElementsAnchorPoint(); // if tabs don't overflow at all, no need to scroll
var tabsContainerWidth = _this.getTabsContainerWidth();
if (lastElementsAnchorPoint <= tabsContainerWidth) {
_this.setState({
tabsContainerOffsetLeft: 0
});
return;
} // do not scroll any more if we will go past the rightmost anchor
var newOffset = Math.min(lastElementsAnchorPoint - tabsContainerWidth, tabElementOfInterest.offsetLeft); // move the viewport
var newViewportOffset = -1 * newOffset;
_this.setState({
tabsContainerOffsetLeft: newViewportOffset
});
});
_defineProperty(_assertThisInitialized(_this), "isRightArrowVisible", function () {
if (!_this.tabsContainer) {
return false;
}
var tabsContainerOffsetLeft = _this.getTabsContainerOffsetLeft();
var lastElementsAnchorPoint = _this.getLastElementsAnchorPoint();
var tabsContainerWidth = _this.getTabsContainerWidth();
return tabsContainerOffsetLeft + tabsContainerWidth < lastElementsAnchorPoint;
});
_defineProperty(_assertThisInitialized(_this), "isLeftArrowVisible", function () {
var _this$props2 = _this.props,
focusedIndex = _this$props2.focusedIndex,
selectedIndex = _this$props2.selectedIndex;
var tabsContainerOffsetLeft = _this.getTabsContainerOffsetLeft();
return tabsContainerOffsetLeft !== 0 && (selectedIndex !== 0 || focusedIndex !== 0);
});
_defineProperty(_assertThisInitialized(_this), "focusOnTabElement", function (focusedIndex) {
if (focusedIndex + 1 > _this.tabsElements.length || focusedIndex < 0) {
return;
}
_this.tabsElements[focusedIndex].focus();
});
_defineProperty(_assertThisInitialized(_this), "tabsElements", []);
_defineProperty(_assertThisInitialized(_this), "tabsContainer", null);
_defineProperty(_assertThisInitialized(_this), "handleKeyDown", function (event) {
var _this$props3 = _this.props,
children = _this$props3.children,
focusedIndex = _this$props3.focusedIndex,
onTabFocus = _this$props3.onTabFocus,
resetFocusedTab = _this$props3.resetFocusedTab,
resetActiveTab = _this$props3.resetActiveTab;
var childrenCount = React.Children.count(children);
switch (event.key) {
case 'ArrowRight':
onTabFocus(_this.calculateNextIndex(focusedIndex, childrenCount));
event.preventDefault();
event.stopPropagation();
break;
case 'ArrowLeft':
onTabFocus(_this.calculatePrevIndex(focusedIndex, childrenCount));
event.preventDefault();
event.stopPropagation();
break;
case 'Escape':
resetActiveTab();
break;
case TAB_KEY:
resetFocusedTab();
break;
default:
break;
}
});
_defineProperty(_assertThisInitialized(_this), "calculateNextIndex", function (currentIndex, childrenCount) {
return (currentIndex + 1) % childrenCount;
});
_defineProperty(_assertThisInitialized(_this), "calculatePrevIndex", function (currentIndex, childrenCount) {
return (currentIndex - 1 + childrenCount) % childrenCount;
});
_this.tabviewID = uniqueId('tabview');
_this.state = {
tabsContainerOffsetLeft: 0
};
return _this;
}
_createClass(TabViewPrimitive, [{
key: "componentDidMount",
value: function componentDidMount() {
var _this$props4 = this.props,
isDynamic = _this$props4.isDynamic,
focusedIndex = _this$props4.focusedIndex;
if (isDynamic) {
// set initial tabsContainerOffsetLeft state after first mounting
this.scrollToTab(focusedIndex);
}
}
}, {
key: "componentWillReceiveProps",
value: function componentWillReceiveProps(nextProps) {
var focusedIndex = nextProps.focusedIndex,
isDynamic = nextProps.isDynamic,
selectedIndex = nextProps.selectedIndex;
if (isDynamic) {
if (focusedIndex !== this.props.focusedIndex) {
this.scrollToTab(focusedIndex);
} else {
// update tabsContainerOffsetLeft state when receiving a new prop
this.scrollToTab(selectedIndex);
}
}
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate(prevProps) {
var focusedIndex = prevProps.focusedIndex;
if (focusedIndex !== this.props.focusedIndex) {
// have to focus after render otherwise, the focus will be lost
this.focusOnTabElement(this.props.focusedIndex);
}
}
}, {
key: "renderTabs",
/* eslint-disable jsx-a11y/no-noninteractive-element-to-interactive-role */
value: function renderTabs() {
var _this2 = this;
var _this$props5 = this.props,
children = _this$props5.children,
selectedIndex = _this$props5.selectedIndex,
isDynamic = _this$props5.isDynamic;
var tabsContainerOffsetLeft = this.state.tabsContainerOffsetLeft;
var style = isDynamic ? {
left: "".concat(tabsContainerOffsetLeft, "px")
} : {};
return React.createElement("nav", {
className: "tabs",
role: "tablist",
ref: function ref(_ref2) {
_this2.tabsContainer = _ref2;
},
style: style,
onKeyDown: !isDynamic ? this.handleKeyDown : null
}, React.Children.map(children, function (tab, i) {
var buttonProps = omit(tab.props, ['className', 'children', 'title']);
var classes = classNames('btn-plain', 'tab', i === selectedIndex ? 'is-selected' : '');
var ariaControls = "".concat(_this2.tabviewID, "-panel-").concat(i + 1);
var ariaSelected = i === selectedIndex;
var id = "".concat(_this2.tabviewID, "-tab-").concat(i + 1);
var href = tab.props.href;
var component = tab.props.component;
var refProp = tab.props.refProp;
var tabIndex = i === selectedIndex ? '0' : '-1';
if (href) {
return React.createElement(LinkButton, {
className: classes,
"aria-controls": ariaControls,
"aria-selected": ariaSelected,
id: id,
role: "tab",
href: href,
linkRef: function linkRef(ref) {
_this2.tabsElements[i] = ref;
},
refProp: refProp,
tabIndex: tabIndex,
to: href,
component: component
}, React.createElement("div", {
className: "tab-title"
}, tab.props.title), React.createElement("div", {
className: "tab-underline"
}));
}
return React.createElement("button", _extends({
className: classes,
"aria-controls": ariaControls,
"aria-selected": ariaSelected,
onClick: function onClick() {
return _this2.onClickTab(i);
},
role: "tab",
type: "button",
id: id,
ref: function ref(_ref) {
_this2.tabsElements[i] = _ref;
},
tabIndex: tabIndex
}, buttonProps), React.createElement("div", {
className: "tab-title"
}, tab.props.title), React.createElement("div", {
className: "tab-underline"
}));
}));
}
/* eslint-enable jsx-a11y/no-noninteractive-element-to-interactive-role */
}, {
key: "renderDynamicTabs",
value: function renderDynamicTabs() {
var _this$props6 = this.props,
onTabFocus = _this$props6.onTabFocus,
focusedIndex = _this$props6.focusedIndex;
return (// eslint-disable-next-line jsx-a11y/no-static-element-interactions
React.createElement("div", {
className: "dynamic-tabs-bar",
onKeyDown: this.handleKeyDown
}, React.createElement("button", {
className: classNames('btn-plain svg-container left-arrow', {
hidden: !this.isLeftArrowVisible()
}),
onClick: function onClick() {
return onTabFocus(focusedIndex - 1);
},
type: "button",
tabIndex: "-1"
}, React.createElement(IconPageBack, null)), React.createElement("div", {
className: "dynamic-tabs-wrapper"
}, this.renderTabs()), React.createElement("button", {
className: classNames('btn-plain svg-container right-arrow', {
hidden: !this.isRightArrowVisible()
}),
onClick: function onClick() {
return onTabFocus(focusedIndex + 1);
},
type: "button",
tabIndex: "-1"
}, React.createElement(IconPageForward, null)))
);
}
}, {
key: "render",
value: function render() {
var _this3 = this;
var _this$props7 = this.props,
children = _this$props7.children,
_this$props7$classNam = _this$props7.className,
className = _this$props7$classNam === void 0 ? '' : _this$props7$classNam,
_this$props7$isDynami = _this$props7.isDynamic,
isDynamic = _this$props7$isDynami === void 0 ? false : _this$props7$isDynami,
onKeyUp = _this$props7.onKeyUp,
selectedIndex = _this$props7.selectedIndex;
return (// eslint-disable-next-line jsx-a11y/no-static-element-interactions
React.createElement("div", {
className: "tab-view ".concat(classNames(className, {
'dynamic-tabs': isDynamic
})),
onKeyUp: onKeyUp
}, !isDynamic ? this.renderTabs() : this.renderDynamicTabs(), React.createElement("div", {
className: "tab-panels"
}, React.Children.toArray(children).map(function (child, i) {
return React.createElement("div", {
key: i,
id: "".concat(_this3.tabviewID, "-panel-").concat(i),
"aria-labelledby": "".concat(_this3.tabviewID, "-tab-").concat(i + 1),
"aria-hidden": selectedIndex !== i,
className: "tab-panel ".concat(i === selectedIndex ? 'is-selected' : ''),
role: TAB_PANEL_ROLE // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
,
tabIndex: "0"
}, child.props.children);
})))
);
}
}]);
return TabViewPrimitive;
}(React.Component);
export default TabViewPrimitive;