"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _classnames = _interopRequireDefault(require("classnames")); var _rcResizeObserver = _interopRequireDefault(require("rc-resize-observer")); var _useEvent = _interopRequireDefault(require("rc-util/lib/hooks/useEvent")); var _ref3 = require("rc-util/lib/ref"); var _react = _interopRequireWildcard(require("react")); var React = _react; var _TabContext = _interopRequireDefault(require("../TabContext")); var _useIndicator2 = _interopRequireDefault(require("../hooks/useIndicator")); var _useOffsets = _interopRequireDefault(require("../hooks/useOffsets")); var _useSyncState5 = _interopRequireDefault(require("../hooks/useSyncState")); var _useTouchMove = _interopRequireDefault(require("../hooks/useTouchMove")); var _useUpdate = _interopRequireWildcard(require("../hooks/useUpdate")); var _useVisibleRange3 = _interopRequireDefault(require("../hooks/useVisibleRange")); var _util = require("../util"); var _AddButton = _interopRequireDefault(require("./AddButton")); var _ExtraContent = _interopRequireDefault(require("./ExtraContent")); var _OperationNode = _interopRequireDefault(require("./OperationNode")); var _TabNode = _interopRequireDefault(require("./TabNode")); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /* eslint-disable react-hooks/exhaustive-deps */ var getTabSize = function getTabSize(tab, containerRect) { // tabListRef var offsetWidth = tab.offsetWidth, offsetHeight = tab.offsetHeight, offsetTop = tab.offsetTop, offsetLeft = tab.offsetLeft; var _tab$getBoundingClien = tab.getBoundingClientRect(), width = _tab$getBoundingClien.width, height = _tab$getBoundingClien.height, x = _tab$getBoundingClien.x, y = _tab$getBoundingClien.y; // Use getBoundingClientRect to avoid decimal inaccuracy if (Math.abs(width - offsetWidth) < 1) { return [width, height, x - containerRect.x, y - containerRect.y]; } return [offsetWidth, offsetHeight, offsetLeft, offsetTop]; }; var getSize = function getSize(refObj) { var _ref = refObj.current || {}, _ref$offsetWidth = _ref.offsetWidth, offsetWidth = _ref$offsetWidth === void 0 ? 0 : _ref$offsetWidth, _ref$offsetHeight = _ref.offsetHeight, offsetHeight = _ref$offsetHeight === void 0 ? 0 : _ref$offsetHeight; // Use getBoundingClientRect to avoid decimal inaccuracy if (refObj.current) { var _refObj$current$getBo = refObj.current.getBoundingClientRect(), width = _refObj$current$getBo.width, height = _refObj$current$getBo.height; if (Math.abs(width - offsetWidth) < 1) { return [width, height]; } } return [offsetWidth, offsetHeight]; }; /** * Convert `SizeInfo` to unit value. Such as [123, 456] with `top` position get `123` */ var getUnitValue = function getUnitValue(size, tabPositionTopOrBottom) { return size[tabPositionTopOrBottom ? 0 : 1]; }; var TabNavList = /*#__PURE__*/React.forwardRef(function (props, ref) { var className = props.className, style = props.style, id = props.id, animated = props.animated, activeKey = props.activeKey, rtl = props.rtl, extra = props.extra, editable = props.editable, locale = props.locale, tabPosition = props.tabPosition, tabBarGutter = props.tabBarGutter, children = props.children, onTabClick = props.onTabClick, onTabScroll = props.onTabScroll, indicator = props.indicator; var _React$useContext = React.useContext(_TabContext.default), prefixCls = _React$useContext.prefixCls, tabs = _React$useContext.tabs; var containerRef = (0, _react.useRef)(null); var extraLeftRef = (0, _react.useRef)(null); var extraRightRef = (0, _react.useRef)(null); var tabsWrapperRef = (0, _react.useRef)(null); var tabListRef = (0, _react.useRef)(null); var operationsRef = (0, _react.useRef)(null); var innerAddButtonRef = (0, _react.useRef)(null); var tabPositionTopOrBottom = tabPosition === 'top' || tabPosition === 'bottom'; var _useSyncState = (0, _useSyncState5.default)(0, function (next, prev) { if (tabPositionTopOrBottom && onTabScroll) { onTabScroll({ direction: next > prev ? 'left' : 'right' }); } }), _useSyncState2 = (0, _slicedToArray2.default)(_useSyncState, 2), transformLeft = _useSyncState2[0], setTransformLeft = _useSyncState2[1]; var _useSyncState3 = (0, _useSyncState5.default)(0, function (next, prev) { if (!tabPositionTopOrBottom && onTabScroll) { onTabScroll({ direction: next > prev ? 'top' : 'bottom' }); } }), _useSyncState4 = (0, _slicedToArray2.default)(_useSyncState3, 2), transformTop = _useSyncState4[0], setTransformTop = _useSyncState4[1]; var _useState = (0, _react.useState)([0, 0]), _useState2 = (0, _slicedToArray2.default)(_useState, 2), containerExcludeExtraSize = _useState2[0], setContainerExcludeExtraSize = _useState2[1]; var _useState3 = (0, _react.useState)([0, 0]), _useState4 = (0, _slicedToArray2.default)(_useState3, 2), tabContentSize = _useState4[0], setTabContentSize = _useState4[1]; var _useState5 = (0, _react.useState)([0, 0]), _useState6 = (0, _slicedToArray2.default)(_useState5, 2), addSize = _useState6[0], setAddSize = _useState6[1]; var _useState7 = (0, _react.useState)([0, 0]), _useState8 = (0, _slicedToArray2.default)(_useState7, 2), operationSize = _useState8[0], setOperationSize = _useState8[1]; var _useUpdateState = (0, _useUpdate.useUpdateState)(new Map()), _useUpdateState2 = (0, _slicedToArray2.default)(_useUpdateState, 2), tabSizes = _useUpdateState2[0], setTabSizes = _useUpdateState2[1]; var tabOffsets = (0, _useOffsets.default)(tabs, tabSizes, tabContentSize[0]); // ========================== Unit ========================= var containerExcludeExtraSizeValue = getUnitValue(containerExcludeExtraSize, tabPositionTopOrBottom); var tabContentSizeValue = getUnitValue(tabContentSize, tabPositionTopOrBottom); var addSizeValue = getUnitValue(addSize, tabPositionTopOrBottom); var operationSizeValue = getUnitValue(operationSize, tabPositionTopOrBottom); var needScroll = containerExcludeExtraSizeValue < tabContentSizeValue + addSizeValue; var visibleTabContentValue = needScroll ? containerExcludeExtraSizeValue - operationSizeValue : containerExcludeExtraSizeValue - addSizeValue; // ========================== Util ========================= var operationsHiddenClassName = "".concat(prefixCls, "-nav-operations-hidden"); var transformMin = 0; var transformMax = 0; if (!tabPositionTopOrBottom) { transformMin = Math.min(0, visibleTabContentValue - tabContentSizeValue); transformMax = 0; } else if (rtl) { transformMin = 0; transformMax = Math.max(0, tabContentSizeValue - visibleTabContentValue); } else { transformMin = Math.min(0, visibleTabContentValue - tabContentSizeValue); transformMax = 0; } function alignInRange(value) { if (value < transformMin) { return transformMin; } if (value > transformMax) { return transformMax; } return value; } // ========================= Mobile ======================== var touchMovingRef = (0, _react.useRef)(null); var _useState9 = (0, _react.useState)(), _useState10 = (0, _slicedToArray2.default)(_useState9, 2), lockAnimation = _useState10[0], setLockAnimation = _useState10[1]; function doLockAnimation() { setLockAnimation(Date.now()); } function clearTouchMoving() { if (touchMovingRef.current) { clearTimeout(touchMovingRef.current); } } (0, _useTouchMove.default)(tabsWrapperRef, function (offsetX, offsetY) { function doMove(setState, offset) { setState(function (value) { var newValue = alignInRange(value + offset); return newValue; }); } // Skip scroll if place is enough if (!needScroll) { return false; } if (tabPositionTopOrBottom) { doMove(setTransformLeft, offsetX); } else { doMove(setTransformTop, offsetY); } clearTouchMoving(); doLockAnimation(); return true; }); (0, _react.useEffect)(function () { clearTouchMoving(); if (lockAnimation) { touchMovingRef.current = setTimeout(function () { setLockAnimation(0); }, 100); } return clearTouchMoving; }, [lockAnimation]); // ===================== Visible Range ===================== // Render tab node & collect tab offset var _useVisibleRange = (0, _useVisibleRange3.default)(tabOffsets, // Container visibleTabContentValue, // Transform tabPositionTopOrBottom ? transformLeft : transformTop, // Tabs tabContentSizeValue, // Add addSizeValue, // Operation operationSizeValue, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, props), {}, { tabs: tabs })), _useVisibleRange2 = (0, _slicedToArray2.default)(_useVisibleRange, 2), visibleStart = _useVisibleRange2[0], visibleEnd = _useVisibleRange2[1]; // ========================= Scroll ======================== var scrollToTab = (0, _useEvent.default)(function () { var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : activeKey; var tabOffset = tabOffsets.get(key) || { width: 0, height: 0, left: 0, right: 0, top: 0 }; if (tabPositionTopOrBottom) { // ============ Align with top & bottom ============ var newTransform = transformLeft; // RTL if (rtl) { if (tabOffset.right < transformLeft) { newTransform = tabOffset.right; } else if (tabOffset.right + tabOffset.width > transformLeft + visibleTabContentValue) { newTransform = tabOffset.right + tabOffset.width - visibleTabContentValue; } } // LTR else if (tabOffset.left < -transformLeft) { newTransform = -tabOffset.left; } else if (tabOffset.left + tabOffset.width > -transformLeft + visibleTabContentValue) { newTransform = -(tabOffset.left + tabOffset.width - visibleTabContentValue); } setTransformTop(0); setTransformLeft(alignInRange(newTransform)); } else { // ============ Align with left & right ============ var _newTransform = transformTop; if (tabOffset.top < -transformTop) { _newTransform = -tabOffset.top; } else if (tabOffset.top + tabOffset.height > -transformTop + visibleTabContentValue) { _newTransform = -(tabOffset.top + tabOffset.height - visibleTabContentValue); } setTransformLeft(0); setTransformTop(alignInRange(_newTransform)); } }); // ========================== Tab ========================== var tabNodeStyle = {}; if (tabPosition === 'top' || tabPosition === 'bottom') { tabNodeStyle[rtl ? 'marginRight' : 'marginLeft'] = tabBarGutter; } else { tabNodeStyle.marginTop = tabBarGutter; } var tabNodes = tabs.map(function (tab, i) { var key = tab.key; return /*#__PURE__*/React.createElement(_TabNode.default, { id: id, prefixCls: prefixCls, key: key, tab: tab /* first node should not have margin left */, style: i === 0 ? undefined : tabNodeStyle, closable: tab.closable, editable: editable, active: key === activeKey, renderWrapper: children, removeAriaLabel: locale === null || locale === void 0 ? void 0 : locale.removeAriaLabel, onClick: function onClick(e) { onTabClick(key, e); }, onFocus: function onFocus() { scrollToTab(key); doLockAnimation(); if (!tabsWrapperRef.current) { return; } // Focus element will make scrollLeft change which we should reset back if (!rtl) { tabsWrapperRef.current.scrollLeft = 0; } tabsWrapperRef.current.scrollTop = 0; } }); }); // Update buttons records var updateTabSizes = function updateTabSizes() { return setTabSizes(function () { var _tabListRef$current; var newSizes = new Map(); var listRect = (_tabListRef$current = tabListRef.current) === null || _tabListRef$current === void 0 ? void 0 : _tabListRef$current.getBoundingClientRect(); tabs.forEach(function (_ref2) { var _tabListRef$current2; var key = _ref2.key; var btnNode = (_tabListRef$current2 = tabListRef.current) === null || _tabListRef$current2 === void 0 ? void 0 : _tabListRef$current2.querySelector("[data-node-key=\"".concat((0, _util.genDataNodeKey)(key), "\"]")); if (btnNode) { var _getTabSize = getTabSize(btnNode, listRect), _getTabSize2 = (0, _slicedToArray2.default)(_getTabSize, 4), width = _getTabSize2[0], height = _getTabSize2[1], left = _getTabSize2[2], top = _getTabSize2[3]; newSizes.set(key, { width: width, height: height, left: left, top: top }); } }); return newSizes; }); }; (0, _react.useEffect)(function () { updateTabSizes(); }, [tabs.map(function (tab) { return tab.key; }).join('_')]); var onListHolderResize = (0, _useUpdate.default)(function () { // Update wrapper records var containerSize = getSize(containerRef); var extraLeftSize = getSize(extraLeftRef); var extraRightSize = getSize(extraRightRef); setContainerExcludeExtraSize([containerSize[0] - extraLeftSize[0] - extraRightSize[0], containerSize[1] - extraLeftSize[1] - extraRightSize[1]]); var newAddSize = getSize(innerAddButtonRef); setAddSize(newAddSize); var newOperationSize = getSize(operationsRef); setOperationSize(newOperationSize); // Which includes add button size var tabContentFullSize = getSize(tabListRef); setTabContentSize([tabContentFullSize[0] - newAddSize[0], tabContentFullSize[1] - newAddSize[1]]); // Update buttons records updateTabSizes(); }); // ======================== Dropdown ======================= var startHiddenTabs = tabs.slice(0, visibleStart); var endHiddenTabs = tabs.slice(visibleEnd + 1); var hiddenTabs = [].concat((0, _toConsumableArray2.default)(startHiddenTabs), (0, _toConsumableArray2.default)(endHiddenTabs)); // =================== Link & Operations =================== var activeTabOffset = tabOffsets.get(activeKey); var _useIndicator = (0, _useIndicator2.default)({ activeTabOffset: activeTabOffset, horizontal: tabPositionTopOrBottom, indicator: indicator, rtl: rtl }), indicatorStyle = _useIndicator.style; // ========================= Effect ======================== (0, _react.useEffect)(function () { scrollToTab(); }, [activeKey, transformMin, transformMax, (0, _util.stringify)(activeTabOffset), (0, _util.stringify)(tabOffsets), tabPositionTopOrBottom]); // Should recalculate when rtl changed (0, _react.useEffect)(function () { onListHolderResize(); // eslint-disable-next-line }, [rtl]); // ========================= Render ======================== var hasDropdown = !!hiddenTabs.length; var wrapPrefix = "".concat(prefixCls, "-nav-wrap"); var pingLeft; var pingRight; var pingTop; var pingBottom; if (tabPositionTopOrBottom) { if (rtl) { pingRight = transformLeft > 0; pingLeft = transformLeft !== transformMax; } else { pingLeft = transformLeft < 0; pingRight = transformLeft !== transformMin; } } else { pingTop = transformTop < 0; pingBottom = transformTop !== transformMin; } return /*#__PURE__*/React.createElement(_rcResizeObserver.default, { onResize: onListHolderResize }, /*#__PURE__*/React.createElement("div", { ref: (0, _ref3.useComposeRef)(ref, containerRef), role: "tablist", className: (0, _classnames.default)("".concat(prefixCls, "-nav"), className), style: style, onKeyDown: function onKeyDown() { // No need animation when use keyboard doLockAnimation(); } }, /*#__PURE__*/React.createElement(_ExtraContent.default, { ref: extraLeftRef, position: "left", extra: extra, prefixCls: prefixCls }), /*#__PURE__*/React.createElement(_rcResizeObserver.default, { onResize: onListHolderResize }, /*#__PURE__*/React.createElement("div", { className: (0, _classnames.default)(wrapPrefix, (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)({}, "".concat(wrapPrefix, "-ping-left"), pingLeft), "".concat(wrapPrefix, "-ping-right"), pingRight), "".concat(wrapPrefix, "-ping-top"), pingTop), "".concat(wrapPrefix, "-ping-bottom"), pingBottom)), ref: tabsWrapperRef }, /*#__PURE__*/React.createElement(_rcResizeObserver.default, { onResize: onListHolderResize }, /*#__PURE__*/React.createElement("div", { ref: tabListRef, className: "".concat(prefixCls, "-nav-list"), style: { transform: "translate(".concat(transformLeft, "px, ").concat(transformTop, "px)"), transition: lockAnimation ? 'none' : undefined } }, tabNodes, /*#__PURE__*/React.createElement(_AddButton.default, { ref: innerAddButtonRef, prefixCls: prefixCls, locale: locale, editable: editable, style: (0, _objectSpread2.default)((0, _objectSpread2.default)({}, tabNodes.length === 0 ? undefined : tabNodeStyle), {}, { visibility: hasDropdown ? 'hidden' : null }) }), /*#__PURE__*/React.createElement("div", { className: (0, _classnames.default)("".concat(prefixCls, "-ink-bar"), (0, _defineProperty2.default)({}, "".concat(prefixCls, "-ink-bar-animated"), animated.inkBar)), style: indicatorStyle }))))), /*#__PURE__*/React.createElement(_OperationNode.default, (0, _extends2.default)({}, props, { removeAriaLabel: locale === null || locale === void 0 ? void 0 : locale.removeAriaLabel, ref: operationsRef, prefixCls: prefixCls, tabs: hiddenTabs, className: !hasDropdown && operationsHiddenClassName, tabMoving: !!lockAnimation })), /*#__PURE__*/React.createElement(_ExtraContent.default, { ref: extraRightRef, position: "right", extra: extra, prefixCls: prefixCls }))); /* eslint-enable */ }); var _default = exports.default = TabNavList;