@cainiaofe/cn-ui-m
Version:
270 lines (269 loc) • 12.4 kB
JavaScript
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;