choerodon-ui
Version:
An enterprise-class UI design language and React-based implementation
651 lines (544 loc) • 24 kB
JavaScript
"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