UNPKG

@douyinfe/semi-ui

Version:

A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.

344 lines (343 loc) 14.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _pick2 = _interopRequireDefault(require("lodash/pick")); var _isEmpty2 = _interopRequireDefault(require("lodash/isEmpty")); var _react = _interopRequireDefault(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _classnames = _interopRequireDefault(require("classnames")); var _constants = require("@douyinfe/semi-foundation/lib/cjs/tabs/constants"); var _getDataAttr = _interopRequireDefault(require("@douyinfe/semi-foundation/lib/cjs/utils/getDataAttr")); var _overflowList = _interopRequireDefault(require("../overflowList")); var _dropdown = _interopRequireDefault(require("../dropdown")); var _button = _interopRequireDefault(require("../button")); var _semiIcons = require("@douyinfe/semi-icons"); var _uuid = require("@douyinfe/semi-foundation/lib/cjs/utils/uuid"); var _TabItem = _interopRequireDefault(require("./TabItem")); var _localeConsumer = _interopRequireDefault(require("../locale/localeConsumer")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } var __rest = void 0 && (void 0).__rest || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; class TabBar extends _react.default.Component { constructor(props) { var _this; super(props); _this = this; this.handleItemClick = (itemKey, e) => { this.props.onTabClick(itemKey, e); }; this.handleKeyDown = (event, itemKey, closable) => { this.props.handleKeyDown(event, itemKey, closable); }; this.renderTabItem = panel => { const { size, type, deleteTabItem, handleKeyDown, tabPosition } = this.props; const isSelected = this._isActive(panel.itemKey); return /*#__PURE__*/_react.default.createElement(_TabItem.default, Object.assign({}, (0, _pick2.default)(panel, ['disabled', 'icon', 'itemKey', 'tab', 'closable']), { key: this._getBarItemKeyByItemKey(panel.itemKey), selected: isSelected, size: size, type: type, tabPosition: tabPosition, handleKeyDown: handleKeyDown, deleteTabItem: deleteTabItem, onClick: this.handleItemClick })); }; this.scrollTabItemIntoViewByKey = function (key) { let logicalPosition = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'nearest'; const tabItem = document.querySelector(`[data-uuid="${_this.state.uuid}"] .${_constants.cssClasses.TABS_TAB}[data-scrollkey="${key}"]`); tabItem === null || tabItem === void 0 ? void 0 : tabItem.scrollIntoView({ behavior: 'smooth', block: logicalPosition, inline: logicalPosition }); }; this.scrollActiveTabItemIntoView = logicalPosition => { const key = this._getBarItemKeyByItemKey(this.props.activeKey); this.scrollTabItemIntoViewByKey(key, logicalPosition); }; this.renderTabComponents = list => list.map(panel => this.renderTabItem(panel)); this.handleArrowClick = (items, pos) => { const lastItem = pos === 'start' ? items.pop() : items.shift(); if (!lastItem) { return; } const key = this._getBarItemKeyByItemKey(lastItem.itemKey); this.scrollTabItemIntoViewByKey(key); }; this.renderCollapse = (items, icon, pos) => { var _a; const arrowCls = (0, _classnames.default)({ [`${_constants.cssClasses.TABS_BAR}-arrow-${pos}`]: pos, [`${_constants.cssClasses.TABS_BAR}-arrow`]: true }); if ((0, _isEmpty2.default)(items)) { return /*#__PURE__*/_react.default.createElement("div", { role: "presentation", className: arrowCls }, /*#__PURE__*/_react.default.createElement(_button.default, { disabled: true, icon: icon, theme: "borderless" })); } const { dropdownClassName, dropdownStyle, showRestInDropdown, dropdownProps } = this.props; const { rePosKey } = this.state; const disabled = !items.length; const menu = /*#__PURE__*/_react.default.createElement(_dropdown.default.Menu, null, items.map(panel => { const { icon: i, tab, itemKey } = panel; const panelIcon = i ? this.renderIcon(panel.icon) : null; return /*#__PURE__*/_react.default.createElement(_dropdown.default.Item, { key: itemKey, onClick: e => this.handleItemClick(itemKey, e), active: this._isActive(itemKey) }, panelIcon, tab); })); const button = /*#__PURE__*/_react.default.createElement("div", { role: "presentation", className: arrowCls, onClick: e => this.handleArrowClick(items, pos) }, /*#__PURE__*/_react.default.createElement(_button.default, { disabled: disabled, icon: icon, theme: "borderless" })); const dropdownCls = (0, _classnames.default)(dropdownClassName, { [`${_constants.cssClasses.TABS_BAR}-dropdown`]: true }); const customDropdownProps = (_a = dropdownProps === null || dropdownProps === void 0 ? void 0 : dropdownProps[pos]) !== null && _a !== void 0 ? _a : {}; return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, showRestInDropdown ? (/*#__PURE__*/_react.default.createElement(_dropdown.default, Object.assign({ className: dropdownCls, clickToHide: true, clickTriggerToHide: true, key: `${rePosKey}-${pos}`, position: pos === 'start' ? 'bottomLeft' : 'bottomRight', render: disabled ? null : menu, showTick: true, style: dropdownStyle, trigger: 'hover', disableFocusListener // prevent the panel from popping up again after clicking : true }, customDropdownProps), button)) : button); }; this.renderOverflow = items => items.map((item, index) => { const pos = index === 0 ? 'start' : 'end'; const icon = index === 0 ? /*#__PURE__*/_react.default.createElement(_semiIcons.IconChevronLeft, null) : /*#__PURE__*/_react.default.createElement(_semiIcons.IconChevronRight, null); const overflowNode = this.renderCollapse(item, icon, pos); if (this.props.renderArrow) { return this.props.renderArrow(item, pos, () => this.handleArrowClick(item, pos), overflowNode); } return overflowNode; }); this.renderCollapsedTab = () => { const { list } = this.props; const renderedList = list.map(item => { const { itemKey } = item; return Object.assign({ key: this._getBarItemKeyByItemKey(itemKey), active: this._isActive(itemKey) }, item); }); return /*#__PURE__*/_react.default.createElement(_overflowList.default, { items: renderedList, overflowRenderDirection: this.props.arrowPosition, wrapperStyle: this.props.visibleTabsStyle, overflowRenderer: this.renderOverflow, renderMode: "scroll", className: `${_constants.cssClasses.TABS_BAR}-overflow-list`, visibleItemRenderer: this.renderTabItem, onVisibleStateChange: visibleMap => { var _a, _b; const visibleMapWithItemKey = new Map(); visibleMap.forEach((v, k) => { visibleMapWithItemKey.set(this._getItemKeyByBarItemKey(k), v); }); (_b = (_a = this.props).onVisibleTabsChange) === null || _b === void 0 ? void 0 : _b.call(_a, visibleMapWithItemKey); } }); }; this.renderWithMoreTrigger = () => { const { list, more } = this.props; let tabElements = []; let moreTrigger = /*#__PURE__*/_react.default.createElement("div", { className: (0, _classnames.default)({ [`${_constants.cssClasses.TABS_BAR}-more-trigger`]: true, [`${_constants.cssClasses.TABS_BAR}-more-trigger-${this.props.type}`]: true }) }, /*#__PURE__*/_react.default.createElement(_localeConsumer.default, { componentName: "Tabs" }, (locale, localeCode) => (/*#__PURE__*/_react.default.createElement("div", { className: `${_constants.cssClasses.TABS_BAR}-more-trigger-content` }, /*#__PURE__*/_react.default.createElement("div", null, locale.more), /*#__PURE__*/_react.default.createElement(_semiIcons.IconChevronDown, { className: `${_constants.cssClasses.TABS_BAR}-more-trigger-content-icon` }))))); let keepCount; if (typeof more === "number") { keepCount = list.length - Math.min(more, list.length); tabElements = list.slice(0, keepCount).map(panel => this.renderTabItem(panel)); } else if (typeof more === 'object') { keepCount = list.length - Math.min(more.count, list.length); tabElements = list.slice(0, keepCount).map(panel => this.renderTabItem(panel)); if (more.render) { moreTrigger = more.render(); } } else if (more !== undefined) { throw new Error("[Semi Tabs]: invalid tab props format: more"); } return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, tabElements, this.renderMoreDropdown(list.slice(keepCount), more === null || more === void 0 ? void 0 : more['dropdownProps'], moreTrigger)); }; this.renderMoreDropdown = (panels, dropDownProps, trigger) => { return /*#__PURE__*/_react.default.createElement(_dropdown.default, Object.assign({ trigger: 'hover', showTick: true, position: 'bottomLeft', className: `${_constants.cssClasses.TABS_BAR}-more-dropdown-${this.props.type}`, clickToHide: true, menu: panels.map(panel => ({ node: 'item', name: panel.tab, icon: panel.icon, onClick: e => this.props.onTabClick(panel.itemKey, e), active: this.props.activeKey === panel.itemKey })) }, dropDownProps), trigger); }; this._isActive = key => key === this.props.activeKey; this._getBarItemKeyByItemKey = key => `${key}-bar`; this._getItemKeyByBarItemKey = key => key.replace(/-bar$/, ""); this.state = { endInd: props.list.length, rePosKey: 0, startInd: 0, uuid: '', currentVisibleItems: [] }; } componentDidMount() { this.setState({ uuid: (0, _uuid.getUuidv4)() }, () => { // Perform the scroll in the setState callback to ensure the uuid is updated to the DOM if (this.props.collapsible) { // Add a small delay to ensure the DOM is fully rendered requestAnimationFrame(() => { this.scrollActiveTabItemIntoView(); }); } }); } componentDidUpdate(prevProps) { if (prevProps.activeKey !== this.props.activeKey) { if (this.props.collapsible) { this.scrollActiveTabItemIntoView(); } } } renderIcon(icon) { return /*#__PURE__*/_react.default.createElement("span", null, icon); } renderExtra() { const { tabBarExtraContent, type, size } = this.props; const tabBarExtraContentDefaultStyle = { float: 'right' }; const tabBarExtraContentStyle = tabBarExtraContent && tabBarExtraContent.props ? tabBarExtraContent.props.style : {}; const extraCls = (0, _classnames.default)(_constants.cssClasses.TABS_BAR_EXTRA, { [`${_constants.cssClasses.TABS_BAR}-${type}-extra`]: type, [`${_constants.cssClasses.TABS_BAR}-${type}-extra-${size}`]: size }); if (tabBarExtraContent) { const tabBarStyle = Object.assign(Object.assign({}, tabBarExtraContentDefaultStyle), tabBarExtraContentStyle); return /*#__PURE__*/_react.default.createElement("div", { className: extraCls, style: tabBarStyle, "x-semi-prop": "tabBarExtraContent" }, tabBarExtraContent); } return null; } render() { const _a = this.props, { type, style, className, list, tabPosition, more, collapsible } = _a, restProps = __rest(_a, ["type", "style", "className", "list", "tabPosition", "more", "collapsible"]); const classNames = (0, _classnames.default)(className, { [_constants.cssClasses.TABS_BAR]: true, [_constants.cssClasses.TABS_BAR_LINE]: type === 'line', [_constants.cssClasses.TABS_BAR_CARD]: type === 'card', [_constants.cssClasses.TABS_BAR_BUTTON]: type === 'button', [_constants.cssClasses.TABS_BAR_SLASH]: type === 'slash', [`${_constants.cssClasses.TABS_BAR}-${tabPosition}`]: tabPosition, [`${_constants.cssClasses.TABS_BAR}-collapse`]: collapsible }); const extra = this.renderExtra(); const contents = collapsible ? this.renderCollapsedTab() : more ? this.renderWithMoreTrigger() : this.renderTabComponents(list); return /*#__PURE__*/_react.default.createElement("div", Object.assign({ role: "tablist", "aria-orientation": tabPosition === "left" ? "vertical" : "horizontal", className: classNames, style: style }, (0, _getDataAttr.default)(restProps), { "data-uuid": this.state.uuid }), contents, extra); } } TabBar.propTypes = { activeKey: _propTypes.default.string, className: _propTypes.default.string, collapsible: _propTypes.default.bool, list: _propTypes.default.array, onTabClick: _propTypes.default.func, size: _propTypes.default.oneOf(_constants.strings.SIZE), style: _propTypes.default.object, tabBarExtraContent: _propTypes.default.node, tabPosition: _propTypes.default.oneOf(_constants.strings.POSITION_MAP), type: _propTypes.default.oneOf(_constants.strings.TYPE_MAP), closable: _propTypes.default.bool, deleteTabItem: _propTypes.default.func, more: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.object]) }; var _default = exports.default = TabBar;