@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
JavaScript
"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;