UNPKG

@arco-design/web-react

Version:

Arco Design React UI Library.

330 lines (329 loc) 19.8 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var react_1 = __importStar(require("react")); var throttle_1 = __importDefault(require("lodash/throttle")); var is_1 = require("../../_util/is"); var resizeObserver_1 = __importDefault(require("../../_util/resizeObserver")); var dropdown_icon_1 = __importDefault(require("./dropdown-icon")); var tab_nav_icon_1 = __importDefault(require("./tab-nav-icon")); var tab_title_1 = __importDefault(require("./tab-title")); var IconPlus_1 = __importDefault(require("../../../icon/react-icon-cjs/IconPlus")); var classNames_1 = __importDefault(require("../../_util/classNames")); var style_1 = require("../../_util/style"); var utils_1 = require("../utils"); var tabs_1 = require("../tabs"); var tab_ink_1 = __importDefault(require("./tab-ink")); var icon_hover_1 = __importDefault(require("../../_class/icon-hover")); var useDomSize_1 = __importDefault(require("../hook/useDomSize")); var useHeaderScroll_1 = __importDefault(require("../hook/useHeaderScroll")); var ConfigProvider_1 = require("../../ConfigProvider"); var DIRECTION_VERTICAL = 'vertical'; var ALIGN_RIGHT = 'right'; var ALIGN_LEFT = 'left'; var SCROLL_MAP = { delete: true, add: true, }; var getHeaderStyle = function (_a) { var direction = _a.direction, _b = _a.align, align = _b === void 0 ? ALIGN_LEFT : _b, headerOffset = _a.headerOffset; var value = "translateX(" + -headerOffset + "px)"; if (align === ALIGN_RIGHT) { value = "translateX(" + headerOffset + "px)"; } if (direction === DIRECTION_VERTICAL) { value = "translateY(" + -headerOffset + "px)"; } return (0, style_1.setTransformStyle)(value); }; var getCurrentHeaderOffset = function (_a) { var direction = _a.direction, _b = _a.align, align = _b === void 0 ? ALIGN_LEFT : _b, headerDom = _a.headerDom, headerWrapperDom = _a.headerWrapperDom; var diffStyle = (0, utils_1.getRectDiff)(headerDom, headerWrapperDom); if (direction === DIRECTION_VERTICAL) return -diffStyle.top; if (align === ALIGN_RIGHT) return diffStyle.right; return -diffStyle.left; }; var TabHeader = react_1.default.forwardRef(function (props, ref) { var _a, _b; var ctxProps = (0, react_1.useContext)(tabs_1.TabsContext); var rtl = (0, react_1.useContext)(ConfigProvider_1.ConfigContext).rtl; var mergeProps = __assign(__assign({}, props), ctxProps); var _c = __read((0, useDomSize_1.default)(), 3), headerWrapperRef = _c[0], headerWrapperSize = _c[1], setHeaderWrapperSize = _c[2]; var _d = __read((0, useDomSize_1.default)(), 3), headerRef = _d[0], headerSize = _d[1], setHeaderSize = _d[2]; var _e = __read((0, useDomSize_1.default)(), 3), scrollWrapperRef = _e[0], scrollWrapperSize = _e[1], setScrollWrapperSize = _e[2]; var _f = __read((0, useDomSize_1.default)(), 3), extraRef = _f[0], extraSize = _f[1], setExtraSize = _f[2]; var _g = __read((0, useDomSize_1.default)(), 3), addBtnRef = _g[0], addBtnSize = _g[1], setAddenBtnSize = _g[2]; var titleRef = (0, react_1.useRef)({}); var _h = __read((0, react_1.useState)(0), 2), headerOffset = _h[0], setHeaderOffset = _h[1]; var _j = __read((0, react_1.useState)(true), 2), shouldScroll = _j[0], setShouldScroll = _j[1]; var paneChildren = mergeProps.paneChildren, editable = mergeProps.editable, prefixCls = mergeProps.prefixCls, onAddTab = mergeProps.onAddTab, direction = mergeProps.direction, _k = mergeProps.type, type = _k === void 0 ? 'line' : _k, _l = mergeProps.overflow, overflow = _l === void 0 ? 'scroll' : _l, activeTab = mergeProps.activeTab, showAddButton = mergeProps.showAddButton, _m = mergeProps.size, size = _m === void 0 ? 'default' : _m, style = mergeProps.style, tabPosition = mergeProps.tabPosition, className = mergeProps.className, extra = mergeProps.extra, animation = mergeProps.animation, icons = mergeProps.icons, deleteButton = mergeProps.deleteButton, addButton = mergeProps.addButton, renderTabTitle = mergeProps.renderTabTitle, scrollAfterEdit = mergeProps.scrollAfterEdit, _o = mergeProps.scrollPosition, scrollPosition = _o === void 0 ? 'auto' : _o, inkBarSize = mergeProps.inkBarSize; var scrollConfig = (0, is_1.isObject)(scrollAfterEdit) ? __assign(__assign({}, SCROLL_MAP), scrollAfterEdit) : SCROLL_MAP; var _p = __read(rtl ? [ALIGN_RIGHT, ALIGN_LEFT] : [ALIGN_LEFT, ALIGN_RIGHT], 2), left = _p[0], right = _p[1]; var align = type === 'capsule' ? right : left; var isScrollable = (0, react_1.useMemo)(function () { var headerContentHeight = scrollWrapperSize.height - extraSize.height - addBtnSize.height; var headerContentWidth = scrollWrapperSize.width - extraSize.width - addBtnSize.width; var res = mergeProps.direction === 'vertical' ? headerContentHeight < headerSize.height : headerContentWidth < headerSize.width; return res; }, [mergeProps.direction, scrollWrapperSize, extraSize, headerSize, addBtnSize]); var updateScrollWrapperSize = function () { if (scrollWrapperRef.current) { var dom = scrollWrapperRef.current; setScrollWrapperSize({ height: dom.offsetHeight, width: dom.offsetWidth, }); } }; var resizeCallback = function (callback) { return (0, throttle_1.default)(function (entry) { updateScrollWrapperSize(); var dom = entry[0] && entry[0].target; if (dom) { callback({ height: dom.offsetHeight, width: dom.offsetWidth, domRect: dom.getBoundingClientRect(), }); } }, 200); }; var onWrapperResize = resizeCallback(setHeaderWrapperSize); var onHeaderResize = resizeCallback(setHeaderSize); var onExtraResize = resizeCallback(setExtraSize); var onAddBtnResize = resizeCallback(setAddenBtnSize); var getValidOffset = (0, react_1.useCallback)(function (offset) { var maxOffset = direction === DIRECTION_VERTICAL ? headerSize.height - headerWrapperSize.height : headerSize.width - headerWrapperSize.width; var validOffset = offset; validOffset = Math.min(maxOffset, validOffset); validOffset = Math.max(validOffset, 0); return validOffset; }, [direction, headerSize, headerWrapperSize]); var updateHeaderOffset = function (offset) { var nextOffset = getValidOffset(offset); if (nextOffset !== headerOffset) { setHeaderOffset(nextOffset); } }; (0, react_1.useEffect)(function () { return function () { var _a, _b, _c, _d; (_a = onHeaderResize === null || onHeaderResize === void 0 ? void 0 : onHeaderResize.cancel) === null || _a === void 0 ? void 0 : _a.call(onHeaderResize); (_b = onWrapperResize === null || onWrapperResize === void 0 ? void 0 : onWrapperResize.cancel) === null || _b === void 0 ? void 0 : _b.call(onWrapperResize); (_c = onExtraResize === null || onExtraResize === void 0 ? void 0 : onExtraResize.cancel) === null || _c === void 0 ? void 0 : _c.call(onExtraResize); (_d = onAddBtnResize === null || onAddBtnResize === void 0 ? void 0 : onAddBtnResize.cancel) === null || _d === void 0 ? void 0 : _d.call(onAddBtnResize); }; }, []); // 根据激活的 tab 更新 headerOffset,所以依赖里面不能加 headerOffset (0, react_1.useEffect)(function () { if (!shouldScroll) { setShouldScroll(true); return; } var getActiveTabOffset = function () { var currentTitleNode = titleRef.current[activeTab]; if (!currentTitleNode || !isScrollable) { return 0; } var diffStyle = (0, utils_1.getRectDiff)(currentTitleNode, headerWrapperRef.current); var currentOffset = getCurrentHeaderOffset({ direction: direction, align: align, headerDom: headerRef.current, headerWrapperDom: headerWrapperRef.current, }); // 垂直方向的 offset 计算,不分type if (direction === 'vertical') { var nextOffset_1 = currentOffset; var scrollAlign_1 = scrollPosition; var topOffset = currentOffset + diffStyle.top; var bottomOffset = currentOffset + diffStyle.bottom; if (scrollAlign_1 === 'auto') { scrollAlign_1 = diffStyle.top < 0 ? 'start' : diffStyle.bottom > 0 ? 'end' : scrollPosition; } if (scrollAlign_1 === 'start') { nextOffset_1 = topOffset; } else if (scrollAlign_1 === 'end') { nextOffset_1 = bottomOffset; } else if (scrollAlign_1 === 'center') { nextOffset_1 = topOffset - (diffStyle.top - diffStyle.bottom) / 2; } else if ((0, is_1.isNumber)(scrollAlign_1)) { nextOffset_1 = Math.max(topOffset - scrollAlign_1, bottomOffset); } return nextOffset_1; } // 水平方向的 offset 计算,分为 capsule 和其他,因为 capsule 是右对齐 if (align === 'right') { var startOffset_1 = currentOffset - diffStyle.left; var endOffset_1 = currentOffset - diffStyle.right; var scrollAlign_2 = scrollPosition; var nextOffset_2 = currentOffset; if (scrollPosition === 'auto') { scrollAlign_2 = diffStyle.left < 0 ? 'start' : diffStyle.right > 0 ? 'end' : scrollPosition; } if (scrollAlign_2 === 'start') { nextOffset_2 = startOffset_1; } else if (scrollAlign_2 === 'end') { nextOffset_2 = endOffset_1; } else if (scrollAlign_2 === 'center') { nextOffset_2 = startOffset_1 + (diffStyle.left - diffStyle.right) / 2; } else if ((0, is_1.isNumber)(scrollAlign_2)) { nextOffset_2 = Math.min(startOffset_1 + scrollAlign_2, endOffset_1); } return nextOffset_2; } var nextOffset = currentOffset; var scrollAlign = scrollPosition; var startOffset = currentOffset + diffStyle.left; var endOffset = currentOffset + diffStyle.right; if (scrollPosition === 'auto') { scrollAlign = diffStyle.left < 0 ? 'start' : diffStyle.right > 0 ? 'end' : scrollPosition; } if (scrollAlign === 'start') { nextOffset = startOffset; } else if (scrollAlign === 'end') { nextOffset = endOffset; } else if (scrollAlign === 'center') { nextOffset = startOffset - (diffStyle.left - diffStyle.right) / 2; } else if ((0, is_1.isNumber)(scrollAlign)) { nextOffset = Math.max(startOffset - scrollAlign, endOffset); } return nextOffset; }; (0, utils_1.updateScrollOffset)(headerWrapperRef.current, direction); var offset = getActiveTabOffset(); offset = getValidOffset(offset); setHeaderOffset(offset); }, [activeTab, direction, overflow, isScrollable, type, getValidOffset, scrollPosition]); var headerStyle = getHeaderStyle({ direction: direction, align: align, headerOffset: headerOffset, }); var isDropdown = isScrollable && overflow === 'dropdown' && direction !== 'vertical'; var isScroll = isScrollable && !isDropdown; var isEditable = editable && (type === 'card' || type === 'card-gutter' || type === 'line'); var handleDelete = function (child) { mergeProps.onDeleteTab && mergeProps.onDeleteTab(child.key); setShouldScroll(scrollConfig.delete); }; var handleAdd = function () { onAddTab === null || onAddTab === void 0 ? void 0 : onAddTab(); setShouldScroll(scrollConfig.add); }; var renderAddIcon = function (isEditable) { return (isEditable && showAddButton && (react_1.default.createElement(resizeObserver_1.default, { onResize: onAddBtnResize }, react_1.default.createElement("div", __assign({ className: prefixCls + "-add-icon", "aria-label": "add tab", tabIndex: 0, role: "button", ref: addBtnRef, onClick: handleAdd }, (0, utils_1.getKeyDownEvent)({ onPressEnter: handleAdd })), addButton || (react_1.default.createElement(icon_hover_1.default, { prefix: prefixCls + "-add" }, react_1.default.createElement("span", { className: prefixCls + "-add" }, (icons === null || icons === void 0 ? void 0 : icons.add) || react_1.default.createElement(IconPlus_1.default, null)))))))); }; (0, useHeaderScroll_1.default)({ headerWrapperRef: headerWrapperRef, headerOffset: headerOffset, align: align, direction: direction, isScrollable: isScrollable, onScroll: function (offset) { updateHeaderOffset(offset); }, }); return (react_1.default.createElement("div", { className: (0, classNames_1.default)(prefixCls + "-header-nav", prefixCls + "-header-nav-" + direction, prefixCls + "-header-nav-" + tabPosition, prefixCls + "-header-size-" + size, prefixCls + "-header-nav-" + type, className), style: style, ref: ref }, react_1.default.createElement("div", { className: (0, classNames_1.default)(prefixCls + "-header-scroll", (_a = {}, _a[prefixCls + "-header-overflow-scroll"] = isScroll, _a[prefixCls + "-header-overflow-dropdown"] = isDropdown, _a)), ref: scrollWrapperRef }, isScroll && (react_1.default.createElement(tab_nav_icon_1.default, { iconPos: "prev", rtl: rtl, icon: icons === null || icons === void 0 ? void 0 : icons.prev, prefixCls: prefixCls, currentOffset: headerOffset, headerSize: headerSize, headerWrapperSize: headerWrapperSize, // getRef={(name) => getCalcArguments()[name]} direction: direction, align: align, onChange: updateHeaderOffset })), react_1.default.createElement(resizeObserver_1.default, { onResize: onWrapperResize }, react_1.default.createElement("div", { className: prefixCls + "-header-wrapper", ref: headerWrapperRef }, react_1.default.createElement(resizeObserver_1.default, { onResize: onHeaderResize }, react_1.default.createElement("div", { className: (0, classNames_1.default)(prefixCls + "-header", (_b = {}, _b[prefixCls + "-header-no-padding"] = !props.headerPadding && direction === 'horizontal' && ['line', 'text'].indexOf(type) > -1, _b)), ref: headerRef, style: headerStyle }, paneChildren.map(function (child, index) { return (react_1.default.createElement(tab_title_1.default, __assign({ key: index, ref: function (node) { titleRef.current[child.key] = node; }, tabKey: child.key }, child.props, { prefixCls: prefixCls, onDeleteTab: function () { return handleDelete(child); }, renderTitle: props.children || renderTabTitle, onClickTab: function () { mergeProps.onClickTab && mergeProps.onClickTab(child.key); }, isActive: activeTab === child.key, editable: isEditable && child.props.closable !== false, deleteIcon: icons === null || icons === void 0 ? void 0 : icons.delete, deleteButton: deleteButton, getIdPrefix: ctxProps.getIdPrefix, index: index }))); }), type === 'line' && (react_1.default.createElement(tab_ink_1.default, { disabled: !!paneChildren.find(function (child) { return child && child.props && child.props.disabled && child.key === activeTab; }), prefixCls: prefixCls, animation: animation, direction: direction, getTitleRef: function (key) { return titleRef.current[key]; }, activeTab: activeTab, getHeaderRef: function () { return headerRef; }, inkBarSize: inkBarSize })))), !isScrollable && renderAddIcon(isEditable))), isScroll && (react_1.default.createElement(tab_nav_icon_1.default, { prefixCls: prefixCls, rtl: rtl, iconPos: "next", icon: icons === null || icons === void 0 ? void 0 : icons.next, currentOffset: headerOffset, headerSize: headerSize, headerWrapperSize: headerWrapperSize, direction: direction, align: align, onChange: updateHeaderOffset })), isDropdown && (react_1.default.createElement(dropdown_icon_1.default, { onClickTab: mergeProps.onClickTab, paneChildren: paneChildren, prefixCls: prefixCls, currentOffset: headerOffset, headerSize: headerSize, icon: icons === null || icons === void 0 ? void 0 : icons.dropdown, headerWrapperSize: headerWrapperSize, getTitleRef: function (key) { return titleRef.current[key]; }, direction: direction })), ((isEditable && isScrollable) || extra) && (react_1.default.createElement(resizeObserver_1.default, { onResize: onExtraResize }, react_1.default.createElement("div", { className: prefixCls + "-header-extra", ref: extraRef }, isScrollable && renderAddIcon(isEditable), extra)))))); }); TabHeader.displayName = 'TabHeader'; exports.default = TabHeader;