UNPKG

@cainiaofe/cn-ui-m

Version:
270 lines (269 loc) 12.4 kB
import { __assign, __awaiter, __generator } from "tslib"; import React, { useEffect, useRef, useState } from 'react'; import classNames from 'classnames'; import { getLeft, getScrollLeft, getWidth } from './utils'; import { usePropsValue } from "../../utils/use-props-value"; import { withNativeProps } from '@cainiaofe/cn-ui-common'; import { traverseReactNode } from "../../utils/traverse-react-node"; import { CnTabContext } from './context'; import { useGuid } from "../../utils/use-guid"; import { CnTabItem } from './item'; import './tab.scss'; import { CnTabPanel } from "./panel"; import { isRTL } from '@cainiaofe/cn-i18n'; var rtl = isRTL(); // get initialized activekey var getInitActiveKey = function (props, activeKey, defaultActiveKey) { if ('activeKey' in props && activeKey) { return activeKey; } else if (defaultActiveKey || defaultActiveKey === 0) { return defaultActiveKey; } else { // @ts-ignore return undefined; } }; var timerMap = {}; export var CnTab = function (props) { var _a, _b, _c, _d; var _e; var type = props.type, _f = props.dataSource, dataSource = _f === void 0 ? [] : _f, contentClassName = props.contentClassName, contentStyle = props.contentStyle, renderTab = props.renderTab, additionSlot = props.additionSlot, tabAlign = props.tabAlign, extra = props.extra, children = props.children; // 从 children 和 dataSource 获取的第一个 childKey var firstActiveKey = null; if (props.children) { traverseReactNode(props.children, function (child, index) { if (!React.isValidElement(child)) return; var key = child.key; if (index === 0) { firstActiveKey = key; } }); } else if (Array.isArray(dataSource) && dataSource.length > 0) { dataSource.forEach(function (item, index) { if (index === 0) { firstActiveKey = item.key || index; } }); } // 当前激活 key var _g = usePropsValue({ value: props.activeKey, defaultValue: (_e = props.defaultActiveKey) !== null && _e !== void 0 ? _e : firstActiveKey, onChange: function (v) { var _a, _b; if (v === null) return; (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, v); (_b = props.onClick) === null || _b === void 0 ? void 0 : _b.call(props, v); }, }), curActiveKey = _g[0], setActiveKey = _g[1]; // 是否为 overflow var _h = useState(false), isOverflow = _h[0], setOverflow = _h[1]; // 用于生成唯一的各种 id var curTabScrollId = useGuid('tab-scroll-'); var curScrollContainerId = useGuid('tab-ctn-'); var scrollMoreLeftId = useGuid('tab-scroll-more-left-'); var scrollMoreRightId = useGuid('tab-scroll-more-right-'); var extraId = useGuid('tab-extra-'); // 滚动容器 ref var scrollRef = useRef(); var activeTabRef = useRef(); var isControlled = 'activeKey' in props; var clsPrefix = 'cn-ui-m-tab'; var classes = { tabWrapper: classNames(CN_UI_HASH_CLASS_NAME, "".concat(clsPrefix, "-wrapper"), "".concat(clsPrefix, "-wrapper-type-").concat(type)), tab: classNames(clsPrefix, "".concat(clsPrefix, "-type-").concat(type)), tabHeader: "".concat(clsPrefix, "-header"), divider: "".concat(clsPrefix, "-divider"), content: classNames("".concat(clsPrefix, "-content"), "".concat(clsPrefix, "-content-type-").concat(type), contentClassName), container: classNames("".concat(clsPrefix, "-container"), (_a = {}, _a["".concat(clsPrefix, "-container-overflow")] = isOverflow, _a)), scrollContainer: classNames("".concat(clsPrefix, "-scroll-container"), (_b = {}, _b["".concat(clsPrefix, "-scroll-container-overflow")] = isOverflow, _b["".concat(clsPrefix, "-scroll-container-align-left")] = tabAlign === 'left', _b)), }; var scrollTo = function (offset) { if (!timerMap[curTabScrollId]) { timerMap[curTabScrollId] = setTimeout(function () { if (scrollRef && scrollRef.current && scrollRef.current.scrollTo) { scrollRef.current.scrollTo({ left: offset.x, top: offset.y, duration: 150, }); timerMap[curTabScrollId] = null; } }, 200); } }; var onScrollTrigger = function () { var _a; var scrollLeft = Math.abs(getScrollLeft(curTabScrollId)); var containerWidth = getWidth(curTabScrollId); var extraWidth = getWidth(extraId); var totalWidth = ((_a = document.getElementById(curScrollContainerId)) === null || _a === void 0 ? void 0 : _a.scrollWidth) || 0; var leftMoreEle = document.getElementById(scrollMoreLeftId); var rightMoreEle = document.getElementById(scrollMoreRightId); if (leftMoreEle && rightMoreEle) { if (scrollLeft > 1) { leftMoreEle.style.visibility = 'visible'; } else { leftMoreEle.style.visibility = 'hidden'; } if (totalWidth > containerWidth) { if (Math.floor(scrollLeft) - Math.floor(totalWidth - containerWidth) < -1) { rtl ? (rightMoreEle.style.left = "".concat(extraWidth, "px")) : (rightMoreEle.style.right = "".concat(extraWidth, "px")); rightMoreEle.style.visibility = 'visible'; } else { rightMoreEle.style.visibility = 'hidden'; } } } }; useEffect(function () { // reset curActiveKey if new activeKey is invalid if (isControlled && curActiveKey && !props.activeKey) { setActiveKey(getInitActiveKey(props)); return; } if (isControlled) { setActiveKey(props.activeKey); } // 初始根据元素判断是滚动模式 (function () { return __awaiter(void 0, void 0, void 0, function () { var totalWidth, containerWidth; var _a; return __generator(this, function (_b) { totalWidth = ((_a = document.getElementById(curScrollContainerId)) === null || _a === void 0 ? void 0 : _a.scrollWidth) || 0; containerWidth = getWidth(curTabScrollId); setOverflow(totalWidth > containerWidth); if (totalWidth > containerWidth) { onScrollTrigger(); } return [2 /*return*/]; }); }); })(); }); // 监听滚动容器设定滚动遮罩的显示 useEffect(function () { var ele = document.getElementById(curTabScrollId); ele === null || ele === void 0 ? void 0 : ele.addEventListener('scroll', onScrollTrigger); }, []); // 根据 activeKey 定位元素 useEffect(function () { (function () { return __awaiter(void 0, void 0, void 0, function () { var activeTabId, containerWidth, containerOffsetLeft, scrollLeft, activeTabWidth, activeTabOffsetLeft, centerMarkerPos, distance; return __generator(this, function (_a) { activeTabId = activeTabRef.current && activeTabRef.current.id; containerWidth = getWidth(curTabScrollId); containerOffsetLeft = getLeft(curTabScrollId); scrollLeft = getScrollLeft(curTabScrollId); activeTabWidth = getWidth(activeTabId); activeTabOffsetLeft = getLeft(activeTabId) - containerOffsetLeft; centerMarkerPos = containerWidth / 2; if (scrollRef.current && activeTabRef.current) { distance = Math.floor(rtl ? Math.min(activeTabOffsetLeft - centerMarkerPos + scrollLeft + activeTabWidth / 2, 0) : Math.max(activeTabOffsetLeft - centerMarkerPos + scrollLeft + activeTabWidth / 2, 0)); if (scrollLeft !== distance) { scrollTo({ x: distance, y: 0, }); } } return [2 /*return*/]; }); }); })(); }, [curActiveKey]); // children 拼装 var content; if (dataSource && dataSource.length > 0) { content = dataSource.map(function (item, index) { var itemProps = __assign({ key: item.key || index, itemKey: item.key, renderContent: renderTab, type: type }, item); if (item.key === curActiveKey) { itemProps.ref = function (ref) { activeTabRef.current = ref; }; } return React.createElement(CnTabItem, __assign({}, itemProps)); }); } else { content = React.Children.map(children, function (child, index) { if (child) { return React.cloneElement(child, { key: "mt_tab_".concat(index), itemKey: child.key || index, ref: "".concat(child.key) === "".concat(curActiveKey) ? activeTabRef : null, renderContent: child.renderContent || renderTab, type: type, }); } else { return null; } }); } var getContent = function () { if (children) { return React.Children.map(children, function (child, index) { var _a; var tempChildren = (_a = child === null || child === void 0 ? void 0 : child.props) === null || _a === void 0 ? void 0 : _a.children; if (tempChildren) { return (React.createElement(CnTabPanel, { itemKey: (child === null || child === void 0 ? void 0 : child.key) || index }, tempChildren)); } else { return null; } }); } return null; }; var realChildren = getContent(); return (React.createElement(CnTabContext.Provider, { value: { // @ts-ignore activeKey: curActiveKey, change: setActiveKey, } }, React.createElement("div", { className: classes.tabWrapper }, withNativeProps(props, React.createElement("div", { className: classes.tab, "data-testid": "cn-tab" }, React.createElement("div", { className: classes.tabHeader }, React.createElement("div", { id: scrollMoreLeftId, className: classNames((_c = {}, _c["".concat(clsPrefix, "-more")] = true, _c["".concat(clsPrefix, "-more-left")] = true, _c)) }), React.createElement("div", { ref: scrollRef, id: curTabScrollId, className: classes.container }, React.createElement("div", { id: curScrollContainerId, className: classes.scrollContainer }, content)), React.createElement("div", { id: scrollMoreRightId, className: classNames((_d = {}, _d["".concat(clsPrefix, "-more")] = true, _d["".concat(clsPrefix, "-more-right")] = true, _d)) }), extra && (React.createElement("div", { className: "".concat(clsPrefix, "-extra"), id: extraId }, extra))), React.createElement("div", { className: classes.divider }), additionSlot && React.createElement("div", null, additionSlot))), realChildren && (realChildren === null || realChildren === void 0 ? void 0 : realChildren.length) > 0 && (React.createElement("div", { className: classes.content, style: contentStyle }, realChildren))))); }; CnTab.displayName = 'CnTab'; CnTab.defaultProps = { type: 'primary', tabAlign: 'center', }; CnTab.Item = CnTabItem;