UNPKG

choerodon-ui

Version:

An enterprise-class UI design language and React-based implementation

651 lines (544 loc) 24 kB
"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _react = _interopRequireWildcard(require("react")); var _classnames5 = _interopRequireDefault(require("classnames")); var _noop = _interopRequireDefault(require("lodash/noop")); var _debounce = _interopRequireDefault(require("lodash/debounce")); var _button = _interopRequireDefault(require("../../pro/lib/button")); var _enum = require("../../pro/lib/button/enum"); var _ModalProvider = require("../../pro/lib/modal-provider/ModalProvider"); var _localeContext = require("../../pro/lib/locale-context"); var _utils = require("./utils"); var _warning = _interopRequireDefault(require("../_util/warning")); var _ripple = _interopRequireDefault(require("../ripple")); var _TabBarInner = _interopRequireDefault(require("./TabBarInner")); var _EventManager = _interopRequireDefault(require("../_util/EventManager")); var _enum2 = require("./enum"); var _icon = _interopRequireDefault(require("../icon")); var _menu = _interopRequireDefault(require("../menu")); var _MenuItem = _interopRequireDefault(require("../menu/MenuItem")); var _badge = _interopRequireDefault(require("../badge")); var _TabsContext = _interopRequireDefault(require("./TabsContext")); var _KeyCode = _interopRequireDefault(require("../_util/KeyCode")); var _enum3 = require("../_util/enum"); var _customizationSettings = _interopRequireDefault(require("./customization-settings")); var _Count = _interopRequireDefault(require("./Count")); var TabBar = function TabBar(props) { var scrollAnimated = props.scrollAnimated, className = props.className, style = props.style, inkBarStyle = props.inkBarStyle, extraContent = props.extraContent, tabBarGutter = props.tabBarGutter, inkBarAnimated = props.inkBarAnimated, type = props.type, onRemoveTab = props.onRemoveTab, restProps = (0, _objectWithoutProperties2["default"])(props, ["scrollAnimated", "className", "style", "inkBarStyle", "extraContent", "tabBarGutter", "inkBarAnimated", "type", "onRemoveTab"]); var _useContext = (0, _react.useContext)(_TabsContext["default"]), keyboard = _useContext.keyboard, customizable = _useContext.customizable, prefixCls = _useContext.prefixCls, activeKey = _useContext.activeKey, activeGroupKey = _useContext.activeGroupKey, tabBarPosition = _useContext.tabBarPosition, _useContext$hideOnlyG = _useContext.hideOnlyGroup, hideOnlyGroup = _useContext$hideOnlyG === void 0 ? false : _useContext$hideOnlyG, groupedPanelsMap = _useContext.groupedPanelsMap, currentPanelMap = _useContext.currentPanelMap, onTabClick = _useContext.onTabClick, _useContext$onPrevCli = _useContext.onPrevClick, onPrevClick = _useContext$onPrevCli === void 0 ? _noop["default"] : _useContext$onPrevCli, _useContext$onNextCli = _useContext.onNextClick, onNextClick = _useContext$onNextCli === void 0 ? _noop["default"] : _useContext$onNextCli, changeActiveKey = _useContext.changeActiveKey; var modal = (0, _ModalProvider.useModal)(); var openCustomizationModal = (0, _react.useCallback)(function () { if (customizable) { var modalProps = { drawer: true, size: _enum3.Size.small, title: (0, _localeContext.$l)('Tabs', 'customization_settings'), children: _react["default"].createElement(_customizationSettings["default"], null), bodyStyle: { overflow: 'hidden auto', padding: 0 } }; modalProps.okText = (0, _localeContext.$l)('Tabs', 'save'); modal.open(modalProps); } }, [customizable, modal]); var getNextActiveKey = (0, _react.useCallback)(function (next) { var list = []; currentPanelMap.forEach(function (c, key) { if (!c.disabled) { if (next) { list.push(key); } else { list.unshift(key); } } }); var length = list.length; if (activeKey && length) { var i = list.indexOf(activeKey); var itemIndex = i === length - 1 ? 0 : i + 1; return list[itemIndex] || list[0]; } return undefined; }, [activeKey, currentPanelMap]); var handleKeyDown = (0, _react.useCallback)(function (e) { if (keyboard === false) { return _noop["default"]; } var keyCode = e.keyCode; if (keyCode === _KeyCode["default"].RIGHT || keyCode === _KeyCode["default"].DOWN) { e.preventDefault(); var nextKey = getNextActiveKey(true); if (nextKey) { changeActiveKey(nextKey); } } else if (keyCode === _KeyCode["default"].LEFT || keyCode === _KeyCode["default"].UP) { e.preventDefault(); var previousKey = getNextActiveKey(false); if (previousKey) { changeActiveKey(previousKey); } } }, [keyboard, changeActiveKey, getNextActiveKey]); var handleTabClick = (0, _react.useCallback)(function (key) { if (onTabClick) { onTabClick(key); } changeActiveKey(key); }, [changeActiveKey, onTabClick]); var handleGroupSelect = (0, _react.useCallback)(function (param) { var key = param.key; if (activeGroupKey !== key) { var newActiveKey = (0, _utils.getActiveKeyByGroupKey)(groupedPanelsMap, key); if (newActiveKey) { changeActiveKey(newActiveKey, true); } } }, [changeActiveKey, activeGroupKey, groupedPanelsMap]); var resizeEvent = (0, _react.useMemo)(function () { return new _EventManager["default"](typeof window === 'undefined' ? undefined : window); }, []); var lastNextPrevShownRef = (0, _react.useRef)(); var offsetRef = (0, _react.useRef)(0); var containerRef = (0, _react.useRef)(null); var navWrapRef = (0, _react.useRef)(null); var navRef = (0, _react.useRef)(null); var rootRef = (0, _react.useRef)(null); var activeTabRef = (0, _react.useRef)(null); var inkBarRef = (0, _react.useRef)(null); var _useState = (0, _react.useState)(false), _useState2 = (0, _slicedToArray2["default"])(_useState, 2), next = _useState2[0], setNext = _useState2[1]; var _useState3 = (0, _react.useState)(false), _useState4 = (0, _slicedToArray2["default"])(_useState3, 2), prev = _useState4[0], setPrev = _useState4[1]; var _useState5 = (0, _react.useState)(activeKey), _useState6 = (0, _slicedToArray2["default"])(_useState5, 2), prevActiveKey = _useState6[0], setActiveKey = _useState6[1]; var getTabs = function getTabs() { return (0, _toConsumableArray2["default"])(currentPanelMap.entries()).reduce(function (rst, _ref, index, list) { var _ref2 = (0, _slicedToArray2["default"])(_ref, 2), key = _ref2[0], child = _ref2[1]; var disabled = child.disabled, _child$closable = child.closable, closable = _child$closable === void 0 ? true : _child$closable, count = child.count, overflowCount = child.overflowCount, showCount = child.showCount; var classes = ["".concat(prefixCls, "-tab")]; var tabProps = { tabKey: key, role: 'tab', 'aria-disabled': 'false', 'aria-selected': 'false', style: { marginRight: tabBarGutter && index === list.length - 1 ? 0 : tabBarGutter } }; if (disabled) { classes.push("".concat(prefixCls, "-tab-disabled")); tabProps['aria-disabled'] = 'true'; } else { tabProps.onTabClick = handleTabClick; } if (activeKey === key) { classes.push("".concat(prefixCls, "-tab-active")); tabProps.ref = activeTabRef; tabProps['aria-selected'] = 'true'; } tabProps.className = classes.join(' '); (0, _warning["default"])('tab' in child || 'title' in child, 'There must be `tab` or `title` property on children of Tabs.'); var title = _react["default"].createElement(_react["default"].Fragment, null, (0, _utils.getHeader)(child), showCount && _react["default"].createElement(_Count["default"], { prefixCls: prefixCls, count: count, overflowCount: overflowCount })); rst.push(_react["default"].createElement(_ripple["default"], { disabled: disabled, key: key }, _react["default"].createElement(_TabBarInner["default"], (0, _extends2["default"])({}, tabProps), type === _enum2.TabsType['editable-card'] ? _react["default"].createElement("div", { className: closable ? undefined : "".concat(prefixCls, "-tab-unclosable") }, title, closable && _react["default"].createElement(_icon["default"], { type: "close", onClick: function onClick(e) { return onRemoveTab(key, e); } })) : title))); return rst; }, []); }; var getContent = function getContent(contents) { if (extraContent || customizable) { return [contents, _react["default"].createElement("div", { key: "extra", className: "".concat(prefixCls, "-extra-content") }, customizable && _react["default"].createElement(_button["default"], { className: "".concat(prefixCls, "-hover-button"), funcType: _enum.FuncType.flat, icon: "predefine", size: _enum3.Size.small, onClick: openCustomizationModal }), extraContent)]; } return [contents]; }; var getGroupNode = function getGroupNode() { if (groupedPanelsMap.size > Number(hideOnlyGroup)) { return _react["default"].createElement(_menu["default"], { prefixCls: "".concat(prefixCls, "-group"), selectedKeys: activeGroupKey ? [activeGroupKey] : [], onSelect: handleGroupSelect, mode: (0, _utils.isVertical)(tabBarPosition) ? 'vertical' : 'horizontal' }, (0, _toConsumableArray2["default"])(groupedPanelsMap.entries()).map(function (_ref3) { var _ref4 = (0, _slicedToArray2["default"])(_ref3, 2), key = _ref4[0], _ref4$1$group = _ref4[1].group, tab = _ref4$1$group.tab, disabled = _ref4$1$group.disabled, dot = _ref4$1$group.dot; return _react["default"].createElement(_MenuItem["default"], { key: key, disabled: disabled }, _react["default"].createElement(_badge["default"], { dot: dot }, tab)); })); } return undefined; }; var getInkBarNode = function getInkBarNode() { var inkBarClassName = "".concat(prefixCls, "-ink-bar"); var classes = (0, _classnames5["default"])(inkBarClassName, inkBarAnimated ? "".concat(inkBarClassName, "-animated") : "".concat(inkBarClassName, "-no-animated")); return _react["default"].createElement("div", { style: inkBarStyle, className: classes, key: "inkBar", ref: inkBarRef }); }; var getOffsetWH = (0, _react.useCallback)(function (node) { return node[(0, _utils.isVertical)(tabBarPosition) ? 'offsetHeight' : 'offsetWidth']; }, [tabBarPosition]); var getScrollWH = (0, _react.useCallback)(function (node) { return node[(0, _utils.isVertical)(tabBarPosition) ? 'scrollHeight' : 'scrollWidth']; }, [tabBarPosition]); var getOffsetLT = (0, _react.useCallback)(function (node) { return node.getBoundingClientRect()[(0, _utils.isVertical)(tabBarPosition) ? 'top' : 'left']; }, [tabBarPosition]); var setOffset = (0, _react.useCallback)(function (offset, callback) { var nav = navRef.current; if (nav) { var target = Math.min(0, offset); if (offsetRef.current !== target) { offsetRef.current = target; var navOffset = {}; var navStyle = nav.style; var transformSupported = (0, _utils.isTransformSupported)(navStyle); if ((0, _utils.isVertical)(tabBarPosition)) { if (transformSupported) { navOffset.value = "translate3d(0,".concat(target, "px,0)"); } else { navOffset.name = 'top'; navOffset.value = "".concat(target, "px"); } } else if (transformSupported) { navOffset.value = "translate3d(".concat(target, "px,0,0)"); } else { navOffset.name = 'left'; navOffset.value = "".concat(target, "px"); } if (transformSupported) { (0, _utils.setTransform)(navStyle, navOffset.value); } else if (navOffset.name) { navStyle[navOffset.name] = navOffset.value; } if (callback) { callback(); } } } }, [offsetRef, navRef, tabBarPosition]); var setNextPrev = (0, _react.useCallback)(function () { var navNode = navRef.current; var container = containerRef.current; var navWrap = navWrapRef.current; if (navNode && container && navWrap) { var navNodeWH = getScrollWH(navNode); var containerWH = getOffsetWH(container); var navWrapNodeWH = getOffsetWH(navWrap); var offset = offsetRef.current; // 当容器小于tab的时候使用最小值才可以防止回弹问题。 var navNodeWHValue = Math.min(containerWH, navWrapNodeWH); var minOffset = navNodeWHValue - navNodeWH; // -165 var $next = next; var $prev = prev; if (minOffset >= 0) { $next = false; setOffset(0); offset = 0; } else if (minOffset < offset) { $next = true; } else { $next = false; // Test with container offset which is stable // and set the offset of the nav wrap node var realOffset = navWrapNodeWH - navNodeWH; setOffset(realOffset); offset = realOffset; } if (offset < 0) { $prev = true; } else { $prev = false; } if (prev !== $prev) { setPrev($prev); } if (next !== $next) { setNext($next); } return { next: $next, prev: $prev }; } }, [next, prev, navRef, containerRef, navWrapRef, offsetRef, getScrollWH, getOffsetWH, setOffset]); var isNextPrevShown = (0, _react.useCallback)(function (state) { if (state) { return state.next || state.prev; } return next || prev; }, [next, prev]); var toPrev = (0, _react.useCallback)(function (e) { onPrevClick(e); var navWrapNode = navWrapRef.current; if (navWrapNode) { var navWrapNodeWH = getOffsetWH(navWrapNode); setOffset(offsetRef.current + navWrapNodeWH, setNextPrev); } }, [getOffsetWH, setOffset, navWrapRef, onPrevClick, setNextPrev]); var toNext = (0, _react.useCallback)(function (e) { onNextClick(e); var navWrapNode = navWrapRef.current; if (navWrapNode) { var navWrapNodeWH = getOffsetWH(navWrapNode); var offset = offsetRef.current; setOffset(offset - navWrapNodeWH, setNextPrev); } }, [getOffsetWH, setOffset, navWrapRef, onNextClick, setNextPrev]); var scrollToActiveTab = (0, _react.useCallback)(function (e) { var activeTab = activeTabRef.current; var navWrap = navWrapRef.current; if (e && e.target !== e.currentTarget || !activeTab || !navWrap) { return; } // when not scrollable or enter scrollable first time, don't emit scrolling var needToSroll = isNextPrevShown() && lastNextPrevShownRef.current; lastNextPrevShownRef.current = isNextPrevShown(); if (!needToSroll) { return; } var activeTabWH = getScrollWH(activeTab); var navWrapNodeWH = getOffsetWH(navWrap); var offset = offsetRef.current; var wrapOffset = getOffsetLT(navWrap); var activeTabOffset = getOffsetLT(activeTab); if (wrapOffset > activeTabOffset) { offset += wrapOffset - activeTabOffset; setOffset(offset, setNextPrev); } else if (wrapOffset + navWrapNodeWH < activeTabOffset + activeTabWH) { offset -= activeTabOffset + activeTabWH - (wrapOffset + navWrapNodeWH); setOffset(offset, setNextPrev); } }, [activeTabRef, navWrapRef, lastNextPrevShownRef, getScrollWH, getOffsetWH, getOffsetLT, setOffset, setNextPrev, isNextPrevShown]); var prevTransitionEnd = (0, _react.useCallback)(function (e) { if (e.propertyName !== 'opacity') { return; } var current = containerRef.current; if (current) { scrollToActiveTab({ target: current, currentTarget: current }); } }, [scrollToActiveTab, containerRef]); var getScrollBarNode = function getScrollBarNode(content) { var _classnames, _classnames2, _classnames3; var showNextPrev = prev || next; var prevButton = _react["default"].createElement("span", { onClick: prev ? toPrev : undefined, unselectable: "on", className: (0, _classnames5["default"])("".concat(prefixCls, "-tab-prev"), (_classnames = {}, (0, _defineProperty2["default"])(_classnames, "".concat(prefixCls, "-tab-btn-disabled"), !prev), (0, _defineProperty2["default"])(_classnames, "".concat(prefixCls, "-tab-arrow-show"), showNextPrev), _classnames)), onTransitionEnd: prevTransitionEnd }, _react["default"].createElement("span", { className: "".concat(prefixCls, "-tab-prev-icon") })); var nextButton = _react["default"].createElement("span", { onClick: next ? toNext : undefined, unselectable: "on", className: (0, _classnames5["default"])((_classnames2 = {}, (0, _defineProperty2["default"])(_classnames2, "".concat(prefixCls, "-tab-next"), 1), (0, _defineProperty2["default"])(_classnames2, "".concat(prefixCls, "-tab-btn-disabled"), !next), (0, _defineProperty2["default"])(_classnames2, "".concat(prefixCls, "-tab-arrow-show"), showNextPrev), _classnames2)) }, _react["default"].createElement("span", { className: "".concat(prefixCls, "-tab-next-icon") })); var navClassName = "".concat(prefixCls, "-nav"); var navClasses = (0, _classnames5["default"])(navClassName, scrollAnimated ? "".concat(navClassName, "-animated") : "".concat(navClassName, "-no-animated")); return _react["default"].createElement("div", { className: (0, _classnames5["default"])((_classnames3 = {}, (0, _defineProperty2["default"])(_classnames3, "".concat(prefixCls, "-nav-container"), 1), (0, _defineProperty2["default"])(_classnames3, "".concat(prefixCls, "-nav-container-scrolling"), showNextPrev), _classnames3)), key: "container", ref: containerRef }, prevButton, nextButton, _react["default"].createElement("div", { className: "".concat(prefixCls, "-nav-wrap"), ref: navWrapRef }, _react["default"].createElement("div", { className: "".concat(prefixCls, "-nav-scroll") }, _react["default"].createElement("div", { className: navClasses, ref: navRef }, content)))); }; (0, _react.useLayoutEffect)(function () { var inkBarNode = inkBarRef.current; if (inkBarNode) { var inkBarNodeStyle = inkBarNode.style; var activeTab = activeTabRef.current; var rootNode = rootRef.current; if (activeTab && rootNode) { var wrapNode = navRef.current || rootNode; var transformSupported = (0, _utils.isTransformSupported)(inkBarNodeStyle); if (!(0, _utils.isVertical)(tabBarPosition)) { var left = (0, _utils.getLeft)(activeTab, wrapNode); var width = activeTab.offsetWidth; // If tabNode'width width equal to wrapNode'width when tabBarPosition is top or bottom // It means no css working, then ink bar should not have width until css is loaded if (width === rootNode.offsetWidth) { width = 0; } else if (inkBarStyle && inkBarStyle.width !== undefined) { width = parseFloat(inkBarStyle.width); if (width) { left += (activeTab.offsetWidth - width) / 2; } } // use 3d gpu to optimize render if (transformSupported) { (0, _utils.setTransform)(inkBarNodeStyle, "translate3d(".concat(left, "px,0,0)")); inkBarNodeStyle.width = "".concat(width, "px"); inkBarNodeStyle.height = ''; } else { inkBarNodeStyle.left = "".concat(left, "px"); inkBarNodeStyle.top = ''; inkBarNodeStyle.bottom = ''; inkBarNodeStyle.right = "".concat(wrapNode.offsetWidth - left - width, "px"); } } else { var top = (0, _utils.getTop)(activeTab, wrapNode); var height = activeTab.offsetHeight; if (inkBarStyle && inkBarStyle.height !== undefined) { height = parseFloat(inkBarStyle.height); if (height) { top += (activeTab.offsetHeight - height) / 2; } } if (transformSupported) { (0, _utils.setTransform)(inkBarNodeStyle, "translate3d(0,".concat(top, "px,0)")); inkBarNodeStyle.height = "".concat(height, "px"); inkBarNodeStyle.width = ''; } else { inkBarNodeStyle.left = ''; inkBarNodeStyle.right = ''; inkBarNodeStyle.top = "".concat(top, "px"); inkBarNodeStyle.bottom = "".concat(wrapNode.offsetHeight - top - height, "px"); } } } inkBarNodeStyle.visibility = activeTab ? 'visible' : 'hidden'; } }); (0, _react.useEffect)(function () { setOffset(0, setNextPrev); }, [tabBarPosition]); (0, _react.useLayoutEffect)(function () { var currentNextPrev = { prev: prev, next: next }; var nextPrev = setNextPrev(); // wait next, prev show hide /* eslint react/no-did-update-set-state:0 */ if (isNextPrevShown(currentNextPrev) !== isNextPrevShown(nextPrev)) { scrollToActiveTab(); } else if (activeKey !== prevActiveKey) { setActiveKey(activeKey); // can not use props.activeKey scrollToActiveTab(); } }, [setNextPrev, isNextPrevShown, prev, next, activeKey, prevActiveKey]); (0, _react.useEffect)(function () { var debouncedResize = (0, _debounce["default"])(function () { setNextPrev(); scrollToActiveTab(); }, 200); resizeEvent.addEventListener('resize', debouncedResize); return function () { resizeEvent.removeEventListener('resize', debouncedResize); debouncedResize.cancel(); }; }, [setNextPrev, scrollToActiveTab, resizeEvent]); var inkBarNode = getInkBarNode(); var tabs = getTabs(); var groupNode = getGroupNode(); var scrollbarNode = getScrollBarNode([inkBarNode, tabs]); return _react["default"].createElement("div", (0, _extends2["default"])({ role: "tablist", className: (0, _classnames5["default"])("".concat(prefixCls, "-bar"), (0, _defineProperty2["default"])({}, "".concat(prefixCls, "-bar-with-groups"), groupNode), className), tabIndex: 0, ref: rootRef, onKeyDown: handleKeyDown, style: style }, (0, _utils.getDataAttr)(restProps)), _react["default"].createElement("div", { className: "".concat(prefixCls, "-bar-inner") }, groupNode, groupNode && _react["default"].createElement("div", { className: "".concat(prefixCls, "-bar-divider") }), getContent(scrollbarNode))); }; TabBar.displayName = 'TabBar'; TabBar.defaultProps = { inkBarAnimated: true, scrollAnimated: true }; var _default = TabBar; exports["default"] = _default; //# sourceMappingURL=TabBar.js.map